From 571a733806562c3d7a7a70c29e43ea490ca5c86c Mon Sep 17 00:00:00 2001 From: Villagers654 <110007851+Villagers654@users.noreply.github.com> Date: Sat, 20 Jun 2026 05:19:49 -0400 Subject: [PATCH 01/21] Modtale Launcher --- .gitignore | 4 + README.md | 24 + .../config/core/PublicApiEndpointMatcher.java | 1 + .../net/modtale/config/db/DataSeeder.java | 600 +- .../properties/AppSeedingProperties.java | 6 +- .../config/security/SecurityConfig.java | 152 +- .../controller/auth/AuthController.java | 97 +- .../controller/user/UserController.java | 28 + .../worldlist/WorldModListController.java | 63 + .../auth/LauncherAuthExchangeRequest.java | 17 + .../auth/LauncherAuthIssueRequest.java | 27 + .../worldlist/CreateWorldModListRequest.java | 28 + .../auth/LauncherAuthIssueResponse.java | 4 + .../model/dto/worldlist/WorldModListDTO.java | 48 + .../model/user/LauncherSettingsSnapshot.java | 205 + .../java/net/modtale/model/user/User.java | 5 + .../modtale/model/worldlist/WorldModList.java | 158 + .../worldlist/WorldModListRepository.java | 9 + .../service/auth/LauncherAuthService.java | 108 + .../service/auth/OAuth2LoginService.java | 19 +- .../service/auth/OidcLoginService.java | 11 +- .../VersionDownloadOrchestrationService.java | 33 +- .../service/storage/DownloadTokenService.java | 13 +- .../service/storage/StorageService.java | 5 + .../service/user/account/AccountService.java | 166 + .../worldlist/WorldModListArchiveService.java | 115 + .../service/worldlist/WorldModListMapper.java | 86 + .../worldlist/WorldModListService.java | 343 + .../src/main/resources/application.properties | 8 +- .../SecurityConfigLauncherOAuthTest.java | 124 + .../controller/auth/AuthControllerTest.java | 84 + .../controller/user/UserControllerTest.java | 23 + .../service/auth/LauncherAuthServiceTest.java | 61 + .../service/auth/OAuth2LoginServiceTest.java | 49 + .../service/auth/OidcLoginServiceTest.java | 31 + ...rsionDownloadOrchestrationServiceTest.java | 25 +- .../storage/DownloadTokenServiceTest.java | 3 +- .../user/account/AccountServiceTest.java | 92 + .../WorldModListArchiveServiceTest.java | 77 + .../worldlist/WorldModListServiceTest.java | 301 + frontend/public/assets/launcher/patchly.png | Bin 0 -> 107835 bytes frontend/public/assets/launcher/project.png | Bin 0 -> 1185479 bytes frontend/public/assets/launcher/voile-mid.png | Bin 0 -> 136736 bytes frontend/public/assets/launcher/voile.png | Bin 0 -> 536318 bytes frontend/src/App.tsx | 121 +- .../components/ui/MarkdownRichRenderer.tsx | 66 +- frontend/src/components/ui/StatusModal.tsx | 2 +- frontend/src/data/seo-constants.ts | 52 + frontend/src/index.css | 3 + .../admin/components/PlatformAnalytics.tsx | 4 +- .../admin/components/UserManagement.tsx | 2 +- .../admin/components/VerificationQueue.tsx | 2 +- .../src/modules/admin/views/AdminPanel.tsx | 10 +- frontend/src/modules/admin/views/Review.tsx | 4 +- frontend/src/modules/auth/api/authClient.ts | 3 + .../modules/auth/components/SignInModal.tsx | 33 +- .../src/modules/auth/views/LauncherAuth.tsx | 197 + .../src/modules/core/components/Navbar.tsx | 12 +- frontend/src/modules/core/views/ApiDocs.tsx | 2 +- .../home/components/FeaturePreviews.tsx | 77 +- .../modules/home/components/HeroMarquee.tsx | 2 +- frontend/src/modules/home/views/Home.tsx | 26 +- .../launcher/utils/launcherProtocol.ts | 113 + .../modules/launcher/views/LauncherPage.tsx | 574 ++ .../src/modules/project/components/Header.tsx | 2 +- .../project/components/ProjectCard.tsx | 17 +- .../modules/project/components/Sidebar.tsx | 4 +- .../components/dialogs/DownloadModal.tsx | 36 +- .../components/dialogs/PostDownloadModal.tsx | 28 +- .../modules/project/views/CreateProject.tsx | 45 +- .../modules/project/views/ProjectDetails.tsx | 26 +- .../modules/project/views/ProjectEditor.tsx | 52 +- .../modules/user/components/ProfileLayout.tsx | 6 +- .../modules/user/tabs/ConnectionsSettings.tsx | 2 +- .../modules/user/tabs/SecuritySettings.tsx | 4 +- frontend/src/modules/user/views/Analytics.tsx | 2 +- .../src/modules/user/views/ManageProfile.tsx | 2 +- .../src/modules/user/views/UserProfile.tsx | 2 +- .../modules/worldlist/api/worldListClient.ts | 52 + .../modules/worldlist/utils/modpackSeed.ts | 76 + .../worldlist/views/WorldModListView.tsx | 220 + frontend/src/pages/[...all].astro | 32 +- frontend/src/pages/sitemap-static.xml.ts | 1 + frontend/src/styles/theme.ts | 2 +- frontend/src/utils/routes.ts | 59 + frontend/tailwind.config.mjs | 2 +- .../components/MarkdownRichRenderer.test.tsx | 36 +- .../tests/modules/auth/api/authClient.test.ts | 8 + .../modules/auth/views/LauncherAuth.test.tsx | 86 + frontend/tests/modules/home/Home.test.tsx | 1 + .../launcher/utils/launcherProtocol.test.ts | 87 + .../project/components/DownloadModal.test.tsx | 92 +- .../components/PostDownloadModal.test.tsx | 46 + .../project/components/ProjectCard.test.tsx | 41 + .../tests/performance/renderSpeed.test.tsx | 6 + frontend/tests/utils/routes.test.ts | 4 + launcher/README.md | 81 + launcher/build.gradle | 928 ++ launcher/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 46175 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + launcher/gradlew | 248 + launcher/gradlew.bat | 93 + launcher/settings.gradle | 2 + .../net/modtale/launcher/LauncherMain.java | 14 + .../launcher/LauncherPerformanceProbe.java | 264 + .../launcher/LauncherRenderSettings.java | 125 + .../net/modtale/launcher/ModtaleLauncher.java | 27 + .../modtale/launcher/api/ApiCachePolicy.java | 35 + .../modtale/launcher/api/ApiPathBuilder.java | 38 + .../launcher/api/ApiResponseCache.java | 154 + .../launcher/api/LauncherSessionStore.java | 188 + .../launcher/api/ModtaleApiClient.java | 524 + .../launcher/api/ModtaleApiException.java | 24 + .../launcher/api/ModtaleApiTransport.java | 261 + .../launcher/api/ModtaleDownloadClient.java | 103 + .../launcher/api/ProjectSearchQuery.java | 28 + .../launcher/cache/LauncherCachePaths.java | 17 + .../launcher/cache/LauncherCacheService.java | 44 + .../discord/DiscordRichPresenceService.java | 329 + .../launcher/hytale/HytaleApiClient.java | 1076 ++ .../launcher/hytale/HytaleApiException.java | 43 + .../launcher/hytale/HytaleAuthService.java | 599 ++ .../launcher/hytale/HytaleAuthSession.java | 111 + .../launcher/hytale/HytaleBlogPost.java | 13 + .../modtale/launcher/hytale/HytaleFriend.java | 29 + .../launcher/hytale/HytaleGameLauncher.java | 264 + .../launcher/hytale/HytaleGameSession.java | 9 + .../hytale/HytaleGameVersionResolver.java | 226 + .../launcher/hytale/HytaleLaunchResult.java | 6 + .../launcher/hytale/HytalePlatform.java | 36 + .../launcher/hytale/HytaleProfile.java | 24 + .../launcher/hytale/HytaleVersion.java | 45 + .../launcher/hytale/HytaleWorldManager.java | 378 + .../launcher/install/ArchiveInstaller.java | 172 + .../launcher/install/ModInstaller.java | 392 + .../launcher/install/UpdateService.java | 75 + .../launcher/install/VersionSelector.java | 59 + .../install/WorldModListInstaller.java | 62 + .../launcher/model/auth/SignInResponse.java | 7 + .../model/install/InstallOptions.java | 30 + .../launcher/model/install/InstallResult.java | 11 + .../model/install/InstalledProject.java | 110 + .../install/InstalledProjectReference.java | 126 + .../model/install/UpdateCandidate.java | 18 + .../notification/LauncherNotification.java | 57 + .../model/project/DownloadUrlResponse.java | 7 + .../model/project/GameVersionCatalog.java | 29 + .../model/project/ProjectClassification.java | 80 + .../model/project/ProjectComment.java | 96 + .../model/project/ProjectDependency.java | 74 + .../launcher/model/project/ProjectDetail.java | 67 + .../model/project/ProjectGallery.java | 16 + .../launcher/model/project/ProjectMeta.java | 16 + .../launcher/model/project/ProjectPage.java | 17 + .../model/project/ProjectSummary.java | 39 + .../model/project/ProjectVersion.java | 42 + .../project/ProjectVersionChangelog.java | 11 + .../project/VersionDependenciesView.java | 11 + .../model/sync/LauncherSettingsSnapshot.java | 366 + .../launcher/model/user/CreatorProfile.java | 76 + .../launcher/model/user/CurrentUser.java | 84 + .../launcher/model/user/UserSummary.java | 28 + .../worldlist/CreateWorldModListRequest.java | 47 + .../model/worldlist/WorldModList.java | 41 + .../worldlist/WorldModListInstallResult.java | 13 + .../model/worldlist/WorldModListItem.java | 39 + .../protocol/LauncherProtocolRequest.java | 111 + .../launcher/settings/HytalePathDetector.java | 169 + .../settings/InstalledProjectRegistry.java | 111 + .../launcher/settings/LauncherConfig.java | 133 + .../launcher/settings/LauncherSettings.java | 534 + .../launcher/settings/SettingsStore.java | 123 + .../sync/LauncherPreferenceSyncDialog.java | 132 + .../sync/LauncherSettingsSyncService.java | 335 + .../ui/account/LauncherAccountController.java | 301 + .../ui/account/LauncherAccountMenu.java | 325 + .../launcher/ui/account/LauncherAuthFlow.java | 214 + .../launcher/ui/account/LauncherAuthGate.java | 317 + .../ui/account/LauncherHytaleAuthGate.java | 111 + .../activity/LauncherFollowingController.java | 278 + .../LauncherNotificationsController.java | 423 + .../activity/LauncherNotificationsMenu.java | 445 + .../ui/browse/ProjectBrowseController.java | 1040 ++ .../ui/browse/card/ProjectCardFactory.java | 402 + .../ui/browse/card/ProjectCardFormatter.java | 80 + .../browse/card/ProjectCardInteraction.java | 208 + .../ui/browse/card/ProjectCardMedia.java | 238 + .../ui/browse/card/ProjectCardViewStyle.java | 7 + .../ui/browse/controls/BrowseOptions.java | 153 + .../controls/GameVersionFilterCatalog.java | 104 + .../controls/ProjectBrowseCategories.java | 255 + ...rojectBrowseDownloadTimeframeSelector.java | 101 + .../controls/ProjectBrowseFilterOptions.java | 503 + .../ui/browse/controls/ProjectBrowseSort.java | 62 + .../ui/browse/controls/ProjectBrowseTags.java | 135 + .../ProjectBrowseViewStyleSelector.java | 61 + .../browse/render/ProjectBrowserRenderer.java | 385 + .../search/ProjectBrowseSearchState.java | 62 + .../launcher/ui/common/CachedImageLoader.java | 199 + .../ui/common/GameVersionDropdown.java | 318 + .../launcher/ui/common/GameVersionGroups.java | 106 + .../ui/common/LauncherAssetResolver.java | 52 + .../ui/common/LauncherExternalLinks.java | 41 + .../launcher/ui/common/LauncherFonts.java | 30 + .../launcher/ui/common/LauncherIcons.java | 165 + .../launcher/ui/common/LauncherLayout.java | 36 + .../ui/common/LauncherOverlaySupport.java | 29 + .../ui/common/LauncherScrollSupport.java | 330 + .../launcher/ui/common/LauncherUi.java | 180 + .../launcher/ui/common/LauncherView.java | 37 + .../launcher/ui/common/StatusModal.java | 475 + .../ui/feedback/LauncherFeedback.java | 164 + .../ui/feedback/LauncherFeedbackView.java | 49 + .../ui/library/InstallDuplicateWarning.java | 258 + .../ui/library/LauncherLibraryController.java | 1300 +++ .../LibraryBundledInstallNormalizer.java | 297 + .../ui/library/LibraryDetailModel.java | 22 + .../library/LibraryLocalInstallRecovery.java | 215 + .../LibraryModpackUnlockConverter.java | 363 + .../library/LibraryProjectListRenderer.java | 87 + .../ui/library/LibraryProjectRenderer.java | 469 + .../ui/library/LibraryProjectSupport.java | 221 + .../launcher/ui/library/LibraryShellView.java | 76 + .../launcher/ui/library/LibraryToggleBox.java | 80 + .../ui/library/LibraryVersionChoice.java | 10 + .../ui/library/LibraryWorldContentItem.java | 52 + .../ui/library/LibraryWorldListItem.java | 16 + .../ui/library/LibraryWorldListRenderer.java | 100 + .../ui/library/LibraryWorldModel.java | 19 + .../library/LibraryWorldProjectDisplay.java | 60 + .../ui/library/LibraryWorldProjectModel.java | 81 + .../ui/library/LibraryWorldRenderer.java | 507 + .../library/LibraryWorldSnapshotMapper.java | 330 + .../ui/library/LibraryWorldToggle.java | 18 + .../ui/library/PostDownloadWorldModal.java | 414 + .../ui/play/LauncherPlayController.java | 1980 ++++ .../launcher/ui/project/FixedAspectPane.java | 56 + .../ui/project/LauncherProjectActions.java | 234 + .../ui/project/NativeBannerScrollEffect.java | 60 + .../ui/project/NativeCommentSection.java | 581 ++ .../ui/project/NativeCreatorProfileView.java | 640 ++ .../ui/project/NativeDependencyModal.java | 512 + .../ui/project/NativeDownloadModal.java | 844 ++ .../ui/project/NativeGalleryCarousel.java | 428 + .../ui/project/NativeMarkdownRenderer.java | 844 ++ .../ui/project/NativeReportModal.java | 405 + .../launcher/ui/project/NativeShareModal.java | 243 + .../launcher/ui/project/NativeSpinner.java | 92 + .../ui/project/ProjectPageController.java | 3089 ++++++ .../ui/project/ProjectVersionHydrator.java | 65 + .../ui/settings/LauncherPathControls.java | 68 + .../settings/LauncherSettingsController.java | 309 + .../ui/settings/LauncherSettingsForm.java | 213 + .../ui/settings/PathChooserSupport.java | 56 + .../launcher/ui/shell/LauncherBrowseMenu.java | 235 + .../launcher/ui/shell/LauncherNavigation.java | 30 + .../launcher/ui/shell/LauncherRuntime.java | 226 + .../launcher/ui/shell/LauncherServices.java | 131 + .../launcher/ui/shell/LauncherShell.java | 1039 ++ .../ui/shell/LauncherShellTitles.java | 34 + .../ui/shell/LauncherSnapshotService.java | 50 + .../ui/shell/LauncherToolbarActions.java | 78 + .../ui/shell/LinuxWindowManagerSupport.java | 411 + .../ui/update/LauncherUpdateController.java | 173 + .../update/LauncherUpdateCandidate.java | 21 + .../update/LauncherUpdateService.java | 314 + .../launcher/update/LauncherVersion.java | 124 + .../launcher/ui/nativefx/assets/favicon.png | Bin 0 -> 5449 bytes .../ui/nativefx/assets/logo_light.png | Bin 0 -> 54298 bytes .../ui/nativefx/fonts/Inter-Black.ttf | Bin 0 -> 328448 bytes .../launcher/ui/nativefx/fonts/Inter-Bold.ttf | Bin 0 -> 330508 bytes .../ui/nativefx/fonts/Inter-Regular.ttf | Bin 0 -> 325388 bytes .../modtale/launcher/ui/nativefx/launcher.css | 8765 +++++++++++++++++ .../launcher/LauncherRenderSettingsTest.java | 86 + .../api/ModtaleApiClientCacheTest.java | 179 + .../api/ModtaleApiClientSessionTest.java | 324 + .../cache/LauncherCacheServiceTest.java | 41 + .../DiscordRichPresenceServiceTest.java | 66 + .../launcher/hytale/HytaleApiClientTest.java | 485 + .../hytale/HytaleApiExceptionTest.java | 27 + .../hytale/HytaleAuthServiceTest.java | 364 + .../hytale/HytaleGameLauncherTest.java | 149 + .../hytale/HytaleGameVersionResolverTest.java | 98 + .../hytale/HytaleWorldManagerTest.java | 147 + .../install/ArchiveInstallerTest.java | 107 + .../launcher/install/ModInstallerTest.java | 264 + .../launcher/install/VersionSelectorTest.java | 46 + .../sync/LauncherSettingsSnapshotTest.java | 123 + .../protocol/LauncherProtocolRequestTest.java | 70 + .../settings/HytalePathDetectorTest.java | 98 + .../launcher/settings/LauncherConfigTest.java | 84 + .../settings/LauncherSettingsTest.java | 261 + .../ui/browse/controls/BrowseOptionsTest.java | 21 + .../GameVersionFilterCatalogTest.java | 41 + .../render/ProjectBrowserRendererTest.java | 74 + .../search/ProjectBrowseSearchStateTest.java | 90 + .../ui/common/GameVersionGroupsTest.java | 45 + .../ui/common/LauncherLayoutTest.java | 17 + .../library/InstallDuplicateWarningTest.java | 298 + .../LibraryBundledInstallNormalizerTest.java | 76 + .../LibraryLocalInstallRecoveryTest.java | 120 + .../LibraryModpackUnlockConverterTest.java | 142 + .../ui/library/LibraryProjectSupportTest.java | 78 + .../LibraryWorldSnapshotMapperTest.java | 95 + .../LauncherUiPerformanceProfileTest.java | 491 + .../project/NativeBannerScrollEffectTest.java | 40 + .../ui/project/NativeDependencyModalTest.java | 51 + .../project/ProjectVersionHydratorTest.java | 142 + .../launcher/ui/shell/LauncherShellTest.java | 19 + .../update/LauncherUpdateServiceTest.java | 35 + .../launcher/update/LauncherVersionTest.java | 29 + mock-db/README.md | 9 + 312 files changed, 56516 insertions(+), 178 deletions(-) create mode 100644 backend/src/main/java/net/modtale/controller/worldlist/WorldModListController.java create mode 100644 backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthExchangeRequest.java create mode 100644 backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthIssueRequest.java create mode 100644 backend/src/main/java/net/modtale/model/dto/request/worldlist/CreateWorldModListRequest.java create mode 100644 backend/src/main/java/net/modtale/model/dto/response/auth/LauncherAuthIssueResponse.java create mode 100644 backend/src/main/java/net/modtale/model/dto/worldlist/WorldModListDTO.java create mode 100644 backend/src/main/java/net/modtale/model/user/LauncherSettingsSnapshot.java create mode 100644 backend/src/main/java/net/modtale/model/worldlist/WorldModList.java create mode 100644 backend/src/main/java/net/modtale/repository/worldlist/WorldModListRepository.java create mode 100644 backend/src/main/java/net/modtale/service/auth/LauncherAuthService.java create mode 100644 backend/src/main/java/net/modtale/service/worldlist/WorldModListArchiveService.java create mode 100644 backend/src/main/java/net/modtale/service/worldlist/WorldModListMapper.java create mode 100644 backend/src/main/java/net/modtale/service/worldlist/WorldModListService.java create mode 100644 backend/src/test/java/net/modtale/config/security/SecurityConfigLauncherOAuthTest.java create mode 100644 backend/src/test/java/net/modtale/service/auth/LauncherAuthServiceTest.java create mode 100644 backend/src/test/java/net/modtale/service/worldlist/WorldModListArchiveServiceTest.java create mode 100644 backend/src/test/java/net/modtale/service/worldlist/WorldModListServiceTest.java create mode 100644 frontend/public/assets/launcher/patchly.png create mode 100644 frontend/public/assets/launcher/project.png create mode 100644 frontend/public/assets/launcher/voile-mid.png create mode 100644 frontend/public/assets/launcher/voile.png create mode 100644 frontend/src/modules/auth/views/LauncherAuth.tsx create mode 100644 frontend/src/modules/launcher/utils/launcherProtocol.ts create mode 100644 frontend/src/modules/launcher/views/LauncherPage.tsx create mode 100644 frontend/src/modules/worldlist/api/worldListClient.ts create mode 100644 frontend/src/modules/worldlist/utils/modpackSeed.ts create mode 100644 frontend/src/modules/worldlist/views/WorldModListView.tsx create mode 100644 frontend/tests/modules/auth/views/LauncherAuth.test.tsx create mode 100644 frontend/tests/modules/launcher/utils/launcherProtocol.test.ts create mode 100644 frontend/tests/modules/project/components/PostDownloadModal.test.tsx create mode 100644 launcher/README.md create mode 100644 launcher/build.gradle create mode 100644 launcher/gradle/wrapper/gradle-wrapper.jar create mode 100644 launcher/gradle/wrapper/gradle-wrapper.properties create mode 100755 launcher/gradlew create mode 100644 launcher/gradlew.bat create mode 100644 launcher/settings.gradle create mode 100644 launcher/src/main/java/net/modtale/launcher/LauncherMain.java create mode 100644 launcher/src/main/java/net/modtale/launcher/LauncherPerformanceProbe.java create mode 100644 launcher/src/main/java/net/modtale/launcher/LauncherRenderSettings.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ModtaleLauncher.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ApiCachePolicy.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ApiPathBuilder.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ApiResponseCache.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/LauncherSessionStore.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ModtaleApiClient.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ModtaleApiException.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ModtaleApiTransport.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ModtaleDownloadClient.java create mode 100644 launcher/src/main/java/net/modtale/launcher/api/ProjectSearchQuery.java create mode 100644 launcher/src/main/java/net/modtale/launcher/cache/LauncherCachePaths.java create mode 100644 launcher/src/main/java/net/modtale/launcher/cache/LauncherCacheService.java create mode 100644 launcher/src/main/java/net/modtale/launcher/discord/DiscordRichPresenceService.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiClient.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiException.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthService.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthSession.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleBlogPost.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleFriend.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameLauncher.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameSession.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameVersionResolver.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleLaunchResult.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytalePlatform.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleProfile.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleVersion.java create mode 100644 launcher/src/main/java/net/modtale/launcher/hytale/HytaleWorldManager.java create mode 100644 launcher/src/main/java/net/modtale/launcher/install/ArchiveInstaller.java create mode 100644 launcher/src/main/java/net/modtale/launcher/install/ModInstaller.java create mode 100644 launcher/src/main/java/net/modtale/launcher/install/UpdateService.java create mode 100644 launcher/src/main/java/net/modtale/launcher/install/VersionSelector.java create mode 100644 launcher/src/main/java/net/modtale/launcher/install/WorldModListInstaller.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/auth/SignInResponse.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/install/InstallOptions.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/install/InstallResult.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/install/InstalledProject.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/install/InstalledProjectReference.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/install/UpdateCandidate.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/notification/LauncherNotification.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/DownloadUrlResponse.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/GameVersionCatalog.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectClassification.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectComment.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectDependency.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectDetail.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectGallery.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectMeta.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectPage.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectSummary.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersion.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersionChangelog.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/project/VersionDependenciesView.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/sync/LauncherSettingsSnapshot.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/user/CreatorProfile.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/user/CurrentUser.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/user/UserSummary.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/worldlist/CreateWorldModListRequest.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModList.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListInstallResult.java create mode 100644 launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListItem.java create mode 100644 launcher/src/main/java/net/modtale/launcher/protocol/LauncherProtocolRequest.java create mode 100644 launcher/src/main/java/net/modtale/launcher/settings/HytalePathDetector.java create mode 100644 launcher/src/main/java/net/modtale/launcher/settings/InstalledProjectRegistry.java create mode 100644 launcher/src/main/java/net/modtale/launcher/settings/LauncherConfig.java create mode 100644 launcher/src/main/java/net/modtale/launcher/settings/LauncherSettings.java create mode 100644 launcher/src/main/java/net/modtale/launcher/settings/SettingsStore.java create mode 100644 launcher/src/main/java/net/modtale/launcher/sync/LauncherPreferenceSyncDialog.java create mode 100644 launcher/src/main/java/net/modtale/launcher/sync/LauncherSettingsSyncService.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountMenu.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthFlow.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthGate.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/account/LauncherHytaleAuthGate.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherFollowingController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsMenu.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/ProjectBrowseController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFactory.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFormatter.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardInteraction.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardMedia.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardViewStyle.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/BrowseOptions.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/GameVersionFilterCatalog.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseCategories.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseDownloadTimeframeSelector.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseFilterOptions.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseSort.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseTags.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseViewStyleSelector.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/render/ProjectBrowserRenderer.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/browse/search/ProjectBrowseSearchState.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/CachedImageLoader.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionDropdown.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionGroups.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherAssetResolver.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherExternalLinks.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherFonts.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherIcons.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherLayout.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherOverlaySupport.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherScrollSupport.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherUi.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/LauncherView.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/common/StatusModal.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedback.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedbackView.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/InstallDuplicateWarning.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LauncherLibraryController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryBundledInstallNormalizer.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryDetailModel.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryLocalInstallRecovery.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryModpackUnlockConverter.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectListRenderer.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectRenderer.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectSupport.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryShellView.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryToggleBox.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryVersionChoice.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldContentItem.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListItem.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListRenderer.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldModel.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectDisplay.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectModel.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldRenderer.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldSnapshotMapper.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldToggle.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/library/PostDownloadWorldModal.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/play/LauncherPlayController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/FixedAspectPane.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/LauncherProjectActions.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeBannerScrollEffect.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeCommentSection.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeCreatorProfileView.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeDependencyModal.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeDownloadModal.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeGalleryCarousel.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeMarkdownRenderer.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeReportModal.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeShareModal.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/NativeSpinner.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/ProjectPageController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/project/ProjectVersionHydrator.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/settings/LauncherPathControls.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/settings/LauncherSettingsController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/settings/LauncherSettingsForm.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/settings/PathChooserSupport.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherBrowseMenu.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherNavigation.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherRuntime.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherServices.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherShell.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherShellTitles.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherSnapshotService.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LauncherToolbarActions.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/shell/LinuxWindowManagerSupport.java create mode 100644 launcher/src/main/java/net/modtale/launcher/ui/update/LauncherUpdateController.java create mode 100644 launcher/src/main/java/net/modtale/launcher/update/LauncherUpdateCandidate.java create mode 100644 launcher/src/main/java/net/modtale/launcher/update/LauncherUpdateService.java create mode 100644 launcher/src/main/java/net/modtale/launcher/update/LauncherVersion.java create mode 100644 launcher/src/main/resources/net/modtale/launcher/ui/nativefx/assets/favicon.png create mode 100644 launcher/src/main/resources/net/modtale/launcher/ui/nativefx/assets/logo_light.png create mode 100644 launcher/src/main/resources/net/modtale/launcher/ui/nativefx/fonts/Inter-Black.ttf create mode 100644 launcher/src/main/resources/net/modtale/launcher/ui/nativefx/fonts/Inter-Bold.ttf create mode 100644 launcher/src/main/resources/net/modtale/launcher/ui/nativefx/fonts/Inter-Regular.ttf create mode 100644 launcher/src/main/resources/net/modtale/launcher/ui/nativefx/launcher.css create mode 100644 launcher/src/test/java/net/modtale/launcher/LauncherRenderSettingsTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/api/ModtaleApiClientCacheTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/api/ModtaleApiClientSessionTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/cache/LauncherCacheServiceTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/discord/DiscordRichPresenceServiceTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/hytale/HytaleApiClientTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/hytale/HytaleApiExceptionTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/hytale/HytaleAuthServiceTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/hytale/HytaleGameLauncherTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/hytale/HytaleGameVersionResolverTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/hytale/HytaleWorldManagerTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/install/ArchiveInstallerTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/install/ModInstallerTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/install/VersionSelectorTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/model/sync/LauncherSettingsSnapshotTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/protocol/LauncherProtocolRequestTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/settings/HytalePathDetectorTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/settings/LauncherConfigTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/settings/LauncherSettingsTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/browse/controls/BrowseOptionsTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/browse/controls/GameVersionFilterCatalogTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/browse/render/ProjectBrowserRendererTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/browse/search/ProjectBrowseSearchStateTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/common/GameVersionGroupsTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/common/LauncherLayoutTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/library/InstallDuplicateWarningTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/library/LibraryBundledInstallNormalizerTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/library/LibraryLocalInstallRecoveryTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/library/LibraryModpackUnlockConverterTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/library/LibraryProjectSupportTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/library/LibraryWorldSnapshotMapperTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/project/LauncherUiPerformanceProfileTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/project/NativeBannerScrollEffectTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/project/NativeDependencyModalTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/project/ProjectVersionHydratorTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/ui/shell/LauncherShellTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/update/LauncherUpdateServiceTest.java create mode 100644 launcher/src/test/java/net/modtale/launcher/update/LauncherVersionTest.java diff --git a/.gitignore b/.gitignore index 023eb3b3..760c03b2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,10 @@ frontend/npm-debug.log* frontend/yarn-debug.log* frontend/yarn-error.log* +launcher/.gradle/ +launcher/build/ +launcher/out/ +launcher/bin/ mock-db/collections/ mock-db/generated/ mock-db/node_modules/ diff --git a/README.md b/README.md index b0c9cc3f..9c0609f9 100644 --- a/README.md +++ b/README.md @@ -89,14 +89,18 @@ The Spring Boot backend relies on environment variables. You can set these in yo | Variable | Description | Example | | --- | --- | --- | | `MONGODB_URI` | Connection String | `mongodb://localhost:27017/modtale` | +| `R2_BUCKET_NAME` | Storage Bucket | `modtale-dev` | | `R2_ACCESS_KEY` | Storage Access Key | `your_dev_access_key` | | `R2_SECRET_KEY` | Storage Secret Key | `your_dev_secret_key` | | `R2_ENDPOINT` | Storage Endpoint URL | `https://.r2.cloudflarestorage.com` | +| `R2_PUBLIC_DOMAIN` | Optional public storage URL | `https://cdn.example.test` | | `WARDEN_ENABLED` | **Must be false locally** | `false` | | `STATUS_DISCORD_WEBHOOK_URL` | Optional Discord webhook for status-change alerts | `https://discord.com/api/webhooks/...` | > **Note on Warden:** The "Warden" malware and security scanner is proprietary to protect our threat-detection logic. You **must** set `WARDEN_ENABLED=false` to run the backend locally. This enables a "Mock Mode" where file uploads bypass the scanner and automatically return a mock "CLEAN" status. +> **Note on seeding storage:** When `APP_SEEDING_ENABLED=true`, set `APP_SEEDING_SOURCE_R2_BUCKET_NAME` to copy seeded release files from a real source R2 bucket into `R2_BUCKET_NAME`. If the target R2 key can also read the source bucket, the regular `R2_ACCESS_KEY`, `R2_SECRET_KEY`, and `R2_ENDPOINT` values are reused. After a clean R2 pass, `DataSeeder` writes a small marker under `.modtale/seeding/r2-artifacts/` in the target bucket so later boots can skip artifact-by-artifact checks for the same seeded project set. + **(Optional) OAuth Variables:** To test social logins (GitHub, Discord, Google), provide their respective Client IDs and Secrets (e.g., `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET`). @@ -138,6 +142,26 @@ npm run dev *The web client is now accessible at `http://localhost:5173`!* +### 5. Native Launcher + +The `launcher/` project is a native Java 21 JavaFX client for installing Modtale projects into a local Hytale mods folder. It does not use Electron. + +```bash +cd launcher +./gradlew run +``` + +The launcher lets users search the Modtale catalog, install the latest compatible version, include required or optional dependencies, check installed projects for updates, apply updates, and point the app at the correct Hytale mods folder. + +Self-contained native packages are built by default: + +```bash +cd launcher +./gradlew build +``` + +Package outputs land in `launcher/build/distributions/`. Windows builds produce an `.exe` installer, macOS builds produce a `.dmg`, and Linux builds produce an `.AppImage`. Each package embeds the required Java runtime, so end users do not need Java installed. Build on each target OS, or use a CI matrix, to produce all three platform artifacts. + --- ## License diff --git a/backend/src/main/java/net/modtale/config/core/PublicApiEndpointMatcher.java b/backend/src/main/java/net/modtale/config/core/PublicApiEndpointMatcher.java index 021193f5..c28af029 100644 --- a/backend/src/main/java/net/modtale/config/core/PublicApiEndpointMatcher.java +++ b/backend/src/main/java/net/modtale/config/core/PublicApiEndpointMatcher.java @@ -30,6 +30,7 @@ public final class PublicApiEndpointMatcher { "/api/v1/og/", "/api/v1/download/", "/api/v1/download-bundle/", + "/api/v1/lists/", "/api/v1/meta/", "/api/v1/version/", "/api/v1/wiki/" diff --git a/backend/src/main/java/net/modtale/config/db/DataSeeder.java b/backend/src/main/java/net/modtale/config/db/DataSeeder.java index 2a522613..9e190fff 100644 --- a/backend/src/main/java/net/modtale/config/db/DataSeeder.java +++ b/backend/src/main/java/net/modtale/config/db/DataSeeder.java @@ -7,8 +7,17 @@ import com.mongodb.client.model.Aggregates; import com.mongodb.client.model.Filters; import com.mongodb.client.model.ReplaceOptions; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.time.Instant; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import net.modtale.config.properties.AppR2Properties; import net.modtale.config.properties.AppSeedingProperties; import net.modtale.model.project.ProjectClassification; import net.modtale.model.project.ProjectStatus; @@ -16,6 +25,7 @@ import net.modtale.model.user.User; import net.modtale.repository.user.UserRepository; import net.modtale.service.auth.ReservedAccountGuardService; +import net.modtale.service.storage.StorageService; import org.bson.Document; import org.bson.conversions.Bson; import org.bson.types.ObjectId; @@ -25,6 +35,16 @@ import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.NoSuchKeyException; +import software.amazon.awssdk.services.s3.model.S3Exception; import java.util.*; @@ -37,9 +57,13 @@ public class DataSeeder implements CommandLineRunner { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final ReservedAccountGuardService reservedAccountGuardService; + private final StorageService storageService; + private final AppR2Properties r2Properties; private final AppSeedingProperties seedingProperties; private static final int PUBLISHED_PROJECT_LIMIT = 100; + private static final int R2_SEED_PROGRESS_INTERVAL = 25; + private static final String R2_SEED_MARKER_PREFIX = ".modtale/seeding/r2-artifacts/"; private static final String SUPER_ADMIN_ID = "692620f7c2f3266e23ac0ded"; private static final String ADMIN_ID = "692620f7c2f3266e23ac0dee"; private static final List MOCK_COLLECTIONS = List.of( @@ -61,12 +85,16 @@ public DataSeeder( UserRepository userRepository, PasswordEncoder passwordEncoder, ReservedAccountGuardService reservedAccountGuardService, + StorageService storageService, + AppR2Properties r2Properties, AppSeedingProperties seedingProperties ) { this.mongoTemplate = mongoTemplate; this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.reservedAccountGuardService = reservedAccountGuardService; + this.storageService = storageService; + this.r2Properties = r2Properties; this.seedingProperties = seedingProperties; } @@ -84,6 +112,15 @@ public void run(String... args) { } String currentDbName = mongoTemplate.getDb().getName(); + logger.info( + "DataSeeder enabled: mode={}, reset={}, targetDb={}, sourceDb={}, targetR2BucketConfigured={}, sourceR2BucketConfigured={}.", + seedingProperties.mode(), + seedingProperties.reset(), + currentDbName, + seedingProperties.sourceDb(), + hasText(r2Properties.bucket()), + hasText(seedingProperties.sourceR2Bucket()) + ); if (seedingProperties.mode() == AppSeedingProperties.Mode.MOCK) { seedMockDatabase(currentDbName); @@ -105,7 +142,8 @@ public void run(String... args) { } if (mongoTemplate.getCollection("projects").countDocuments() > 0) { - logger.info("Database '{}' already contains projects. Skipping content clone.", currentDbName); + logger.info("Database '{}' already contains projects. Skipping content clone and checking R2 artifacts.", currentDbName); + seedR2ObjectsFromCurrentProjects(false); return; } @@ -174,6 +212,7 @@ public void run(String... args) { logger.warn("Project insertion warning (duplicates might exist): {}", e.getMessage()); } + seedR2ObjectsForProjects(compiledProjects, false); seedSyntheticSupplementDocuments(targetDb); logger.info("Seeding completed successfully."); @@ -188,6 +227,7 @@ private void seedMockDatabase(String currentDbName) { if (!seedingProperties.reset() && mongoTemplate.getCollection("projects").countDocuments() > 0) { logger.info("Database '{}' already contains projects. Skipping mock database import.", currentDbName); + seedR2ObjectsFromCurrentProjects(true); return; } @@ -213,6 +253,9 @@ private void seedMockDatabase(String currentDbName) { } logger.info("Imported {} mock documents into '{}'.", documents.size(), collectionName); + if ("projects".equals(collectionName)) { + seedR2ObjectsForProjects(documents, true); + } } logger.info("Mock database import completed successfully."); @@ -247,6 +290,7 @@ private void seedFromSanitizedTemplate(String currentDbName) { if (!seedingProperties.reset() && mongoTemplate.getCollection("projects").countDocuments() > 0) { logger.info("Database '{}' already contains projects. Skipping template import.", currentDbName); + seedR2ObjectsFromCurrentProjects(false); return; } @@ -276,6 +320,9 @@ private void seedFromSanitizedTemplate(String currentDbName) { } logger.info("Imported {} sanitized template documents into '{}'.", documents.size(), collectionName); + if ("projects".equals(collectionName)) { + seedR2ObjectsForProjects(documents, false); + } } logger.info("Sanitized template import completed successfully."); @@ -484,13 +531,25 @@ private Document project(String id, String slug, String title, String classifica "galleryImageCaptions", new Document(), "comments", List.of(), "versions", List.of(doc("_id", slug + "-1-0-0", "versionNumber", "1.0.0", - "gameVersions", List.of("2026.03.11"), "fileUrl", "https://example.test/mock-downloads/" + slug + "-1.0.0.zip", + "gameVersions", List.of("2026.03.11"), "fileUrl", seedFileKey(slug, classification, "1.0.0"), "hash", "sha256:mock-" + slug, "downloadCount", downloads, "releaseDate", "2026-06-18", "changelog", "Synthetic changelog.", "dependencies", List.of(), "incompatibleProjectIds", List.of(), "channel", "RELEASE", "reviewStatus", "PENDING".equals(status) ? "PENDING" : "APPROVED")) ); } + private String seedFileKey(String slug, String classification, String versionNumber) { + String safeSlug = sanitizeStorageName(slug == null || slug.isBlank() ? "mock-project" : slug); + String safeVersion = sanitizeStorageName(versionNumber == null || versionNumber.isBlank() ? "latest" : versionNumber); + return switch (parseClassification(classification)) { + case MODPACK -> "modpacks/" + safeSlug + "-" + safeVersion + ".zip"; + case DATA -> "files/data/" + safeSlug + "-" + safeVersion + ".zip"; + case ART -> "files/art/" + safeSlug + "-" + safeVersion + ".hmasset"; + case SAVE -> "files/save/" + safeSlug + "-" + safeVersion + ".zip"; + case PLUGIN -> "files/plugin/" + safeSlug + "-" + safeVersion + ".jar"; + }; + } + private Document doc(Object... values) { Document document = new Document(); for (int i = 0; i + 1 < values.length; i += 2) { @@ -529,7 +588,544 @@ private void seedSyntheticSupplementDocuments(MongoDatabase targetDb) { } logger.info("Upserted {} synthetic supplement documents into '{}'.", documents.size(), collectionName); + if ("projects".equals(collectionName)) { + seedR2ObjectsForProjects(documents, true); + } + } + } + + private void seedR2ObjectsFromCurrentProjects(boolean allowSyntheticFallback) { + try { + List projects = new ArrayList<>(); + mongoTemplate.getCollection("projects") + .find() + .projection(new Document("title", 1) + .append("slug", 1) + .append("classification", 1) + .append("versions", 1)) + .into(projects); + logger.info( + "Checking existing database projects for R2 artifact seeding (projects={}, syntheticFallback={}).", + projects.size(), + allowSyntheticFallback + ); + seedR2ObjectsForProjects(projects, allowSyntheticFallback); + } catch (MongoException e) { + logger.warn("Could not read existing projects for R2 artifact seeding: {}", e.getMessage()); + } + } + + private void seedR2ObjectsForProjects(List projects, boolean allowSyntheticFallback) { + if (projects == null || projects.isEmpty()) { + logger.info("No projects available for R2 artifact seeding."); + return; + } + + int versionCount = countVersionDocuments(projects); + Map objects = new LinkedHashMap<>(); + for (Document project : projects) { + collectProjectR2Objects(project, objects); + } + + if (objects.isEmpty()) { + logger.info( + "No R2 artifact keys found across {} projects and {} versions. Skipping R2 artifact seeding.", + projects.size(), + versionCount + ); + return; + } + + if (!hasText(r2Properties.bucket())) { + logger.info("Target R2 bucket is not configured. Skipping R2 artifact seeding for {} object keys.", objects.size()); + return; + } + + String markerKey = r2SeedMarkerKey(objects.values()); + if (hasR2SeedMarker(markerKey, objects.size())) { + return; + } + + Optional sourceConfig = r2SourceConfig(); + if (sourceConfig.isEmpty() && !allowSyntheticFallback) { + logger.info("Source R2 is not configured. Skipping R2 artifact seeding for {} object keys.", objects.size()); + return; + } + + R2SourceConfig source = sourceConfig.orElse(null); + S3Client sourceClient = source == null ? null : sourceR2Client(source); + logger.info( + "Checking {} R2 artifact keys against target storage (sourceBucketConfigured={}, syntheticFallback={}).", + objects.size(), + source != null, + allowSyntheticFallback + ); + int uploaded = 0; + int skipped = 0; + int copied = 0; + int generated = 0; + int missingSource = 0; + int failed = 0; + int processed = 0; + long startedAt = System.nanoTime(); + + try { + for (R2SeedObject object : objects.values()) { + processed++; + if (processed == 1 || (processed - 1) % R2_SEED_PROGRESS_INTERVAL == 0) { + logger.info("R2 artifact seed progress: starting {}/{} ({})", processed, objects.size(), object.key()); + } + + try { + if (storageService.exists(object.key())) { + skipped++; + } else { + R2ObjectBytes bytes = sourceClient == null + ? null + : readSourceR2Object(sourceClient, source, object.key()); + if (bytes != null) { + storageService.uploadDirect( + object.key(), + bytes.bytes(), + firstNonBlank(bytes.contentType(), contentType(object.key())) + ); + uploaded++; + copied++; + } else if (allowSyntheticFallback) { + storageService.uploadDirect(object.key(), fixtureBytes(object), contentType(object.key())); + uploaded++; + generated++; + } else { + missingSource++; + logger.warn("Source R2 object '{}' was not found. Target object was not seeded.", object.key()); + } + } + } catch (RuntimeException e) { + failed++; + logger.warn("Could not seed R2 artifact object '{}': {}", object.key(), e.getMessage()); + } + + if (processed % R2_SEED_PROGRESS_INTERVAL == 0 || processed == objects.size()) { + logger.info( + "R2 artifact seed progress: processed={}/{} uploaded={} copiedFromSource={} generatedSynthetic={} alreadyPresent={} missingSource={} failed={}.", + processed, + objects.size(), + uploaded, + copied, + generated, + skipped, + missingSource, + failed + ); + } + } + } finally { + if (sourceClient != null) { + sourceClient.close(); + } } + + long elapsedMillis = (System.nanoTime() - startedAt) / 1_000_000L; + logger.info( + "R2 artifact seed finished: uploaded={}, copiedFromSource={}, generatedSynthetic={}, alreadyPresent={}, missingSource={}, failed={}, elapsedMs={}.", + uploaded, + copied, + generated, + skipped, + missingSource, + failed, + elapsedMillis + ); + + if (missingSource == 0 && failed == 0) { + writeR2SeedMarker(markerKey, objects.size(), versionCount, uploaded, copied, generated, skipped, elapsedMillis); + } else { + logger.info( + "R2 artifact seed marker was not written because missingSource={} and failed={}. The next startup will re-check R2 artifacts.", + missingSource, + failed + ); + } + } + + private boolean hasR2SeedMarker(String markerKey, int objectCount) { + try { + if (storageService.exists(markerKey)) { + logger.info( + "R2 artifact seed marker exists for current artifact set (objects={}, marker={}). Skipping R2 artifact validation.", + objectCount, + markerKey + ); + return true; + } + logger.info("R2 artifact seed marker not found for current artifact set (marker={}). Validating target objects.", markerKey); + } catch (RuntimeException e) { + logger.warn( + "Could not check R2 artifact seed marker '{}': {}. Falling back to object validation.", + markerKey, + e.getMessage() + ); + } + return false; + } + + private void writeR2SeedMarker( + String markerKey, + int objectCount, + int versionCount, + int uploaded, + int copied, + int generated, + int alreadyPresent, + long elapsedMillis + ) { + try { + storageService.uploadDirect( + markerKey, + r2SeedMarkerJson(markerKey, objectCount, versionCount, uploaded, copied, generated, alreadyPresent, elapsedMillis) + .getBytes(StandardCharsets.UTF_8), + "application/json" + ); + logger.info("Wrote R2 artifact seed marker for current artifact set (objects={}, marker={}).", objectCount, markerKey); + } catch (RuntimeException e) { + logger.warn("Could not write R2 artifact seed marker '{}': {}", markerKey, e.getMessage()); + } + } + + private String r2SeedMarkerKey(Collection objects) { + return R2_SEED_MARKER_PREFIX + r2SeedFingerprint(objects) + ".json"; + } + + private String r2SeedFingerprint(Collection objects) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + objects.stream() + .map(R2SeedObject::key) + .filter(Objects::nonNull) + .sorted() + .forEach(key -> { + digest.update(key.getBytes(StandardCharsets.UTF_8)); + digest.update((byte) '\n'); + }); + return HexFormat.of().formatHex(digest.digest()); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("SHA-256 is not available for R2 seed fingerprinting.", e); + } + } + + private String r2SeedMarkerJson( + String markerKey, + int objectCount, + int versionCount, + int uploaded, + int copied, + int generated, + int alreadyPresent, + long elapsedMillis + ) { + String fingerprint = markerKey + .substring(R2_SEED_MARKER_PREFIX.length(), markerKey.length() - ".json".length()); + return "{\n" + + " \"type\": \"modtale-r2-artifact-seed\",\n" + + " \"fingerprint\": \"" + fingerprint + "\",\n" + + " \"objectCount\": " + objectCount + ",\n" + + " \"versionCount\": " + versionCount + ",\n" + + " \"uploaded\": " + uploaded + ",\n" + + " \"copiedFromSource\": " + copied + ",\n" + + " \"generatedSynthetic\": " + generated + ",\n" + + " \"alreadyPresent\": " + alreadyPresent + ",\n" + + " \"elapsedMs\": " + elapsedMillis + ",\n" + + " \"createdAt\": \"" + Instant.now() + "\"\n" + + "}\n"; + } + + private int countVersionDocuments(List projects) { + int count = 0; + for (Document project : projects) { + Object rawVersions = project.get("versions"); + if (rawVersions instanceof List versions) { + count += versions.size(); + } + } + return count; + } + + private Optional r2SourceConfig() { + String bucket = trimToNull(seedingProperties.sourceR2Bucket()); + if (bucket == null) { + return Optional.empty(); + } + + String accessKey = trimToNull(seedingProperties.sourceR2AccessKey()); + String secretKey = trimToNull(seedingProperties.sourceR2SecretKey()); + String endpoint = trimToNull(seedingProperties.sourceR2Endpoint()); + if (accessKey == null || secretKey == null || endpoint == null) { + logger.warn( + "Source R2 bucket '{}' is configured, but source endpoint/access/secret is incomplete. Skipping source R2 copy.", + bucket + ); + return Optional.empty(); + } + + return Optional.of(new R2SourceConfig(bucket, accessKey, secretKey, endpoint)); + } + + private S3Client sourceR2Client(R2SourceConfig source) { + URI endpoint = cleanEndpoint(source.endpoint()); + return S3Client.builder() + .endpointOverride(endpoint) + .region(Region.US_EAST_1) + .credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create(source.accessKey(), source.secretKey()) + )) + .serviceConfiguration(S3Configuration.builder() + .pathStyleAccessEnabled(true) + .build()) + .build(); + } + + private URI cleanEndpoint(String endpoint) { + URI uri = URI.create(endpoint); + return URI.create(uri.getScheme() + "://" + uri.getAuthority()); + } + + private R2ObjectBytes readSourceR2Object(S3Client sourceClient, R2SourceConfig source, String key) { + try { + ResponseBytes response = sourceClient.getObjectAsBytes(GetObjectRequest.builder() + .bucket(source.bucket()) + .key(key) + .build()); + return new R2ObjectBytes(response.asByteArray(), response.response().contentType()); + } catch (NoSuchKeyException e) { + return null; + } catch (S3Exception e) { + if (e.statusCode() == 404) { + return null; + } + throw e; + } + } + + private void collectProjectR2Objects(Document project, Map objects) { + ProjectClassification classification = parseClassification(project.get("classification")); + String projectName = firstNonBlank( + stringValue(project.get("slug")), + stringValue(project.get("title")), + "project" + ); + + Object rawVersions = project.get("versions"); + if (!(rawVersions instanceof List versions)) { + return; + } + + for (Object versionObj : versions) { + if (!(versionObj instanceof Document versionDoc)) { + continue; + } + + String versionNumber = firstNonBlank(stringValue(versionDoc.get("versionNumber")), "latest"); + addR2SeedObject(objects, stringValue(versionDoc.get("fileUrl")), projectName, versionNumber, classification); + collectDependencyR2Objects(versionDoc, objects); + } + } + + private void collectDependencyR2Objects(Document versionDoc, Map objects) { + Object rawDependencies = versionDoc.get("dependencies"); + if (!(rawDependencies instanceof List dependencies)) { + return; + } + + for (Object dependencyObj : dependencies) { + if (!(dependencyObj instanceof Document dependencyDoc)) { + continue; + } + + String title = firstNonBlank( + stringValue(dependencyDoc.get("projectTitle")), + stringValue(dependencyDoc.get("title")), + stringValue(dependencyDoc.get("projectId")), + stringValue(dependencyDoc.get("externalId")), + "dependency" + ); + String versionNumber = firstNonBlank(stringValue(dependencyDoc.get("versionNumber")), "latest"); + addR2SeedObject(objects, stringValue(dependencyDoc.get("cachedFileUrl")), title, versionNumber, ProjectClassification.PLUGIN); + } + } + + private void addR2SeedObject( + Map objects, + String key, + String projectName, + String versionNumber, + ProjectClassification classification + ) { + if (key == null || key.isBlank()) { + return; + } + + objects.putIfAbsent( + key, + new R2SeedObject( + key, + firstNonBlank(projectName, filenameStem(key), "project"), + firstNonBlank(versionNumber, "latest"), + classification == null ? ProjectClassification.PLUGIN : classification + ) + ); + } + + private byte[] fixtureBytes(R2SeedObject object) { + String extension = extension(object.key()); + if (object.classification() == ProjectClassification.MODPACK || "zip".equals(extension)) { + return zipFixtureBytes(object); + } + if ("jar".equals(extension)) { + return jarFixtureBytes(object); + } + + return ("Modtale fixture artifact\n" + + "Project: " + object.projectName() + "\n" + + "Version: " + object.versionNumber() + "\n" + + "Key: " + object.key() + "\n").getBytes(StandardCharsets.UTF_8); + } + + private byte[] zipFixtureBytes(R2SeedObject object) { + try { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (ZipOutputStream zip = new ZipOutputStream(bytes)) { + writeZipEntry(zip, "README.txt", ("Modtale fixture archive for " + + object.projectName() + + " " + + object.versionNumber() + + "\n").getBytes(StandardCharsets.UTF_8)); + + if (object.classification() == ProjectClassification.MODPACK) { + writeZipEntry( + zip, + sanitizeStorageName(object.projectName()) + "-" + sanitizeStorageName(object.versionNumber()) + ".jar", + jarFixtureBytes(object) + ); + } + } + return bytes.toByteArray(); + } catch (IOException e) { + throw new IllegalStateException("Could not build fixture ZIP.", e); + } + } + + private byte[] jarFixtureBytes(R2SeedObject object) { + try { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (ZipOutputStream jar = new ZipOutputStream(bytes)) { + writeZipEntry(jar, "META-INF/MANIFEST.MF", "Manifest-Version: 1.0\nCreated-By: Modtale DataSeeder\n\n" + .getBytes(StandardCharsets.UTF_8)); + writeZipEntry(jar, "modtale-fixture.txt", ("Fixture mod artifact for " + + object.projectName() + + " " + + object.versionNumber() + + "\n").getBytes(StandardCharsets.UTF_8)); + } + return bytes.toByteArray(); + } catch (IOException e) { + throw new IllegalStateException("Could not build fixture JAR.", e); + } + } + + private void writeZipEntry(ZipOutputStream zip, String name, byte[] bytes) throws IOException { + zip.putNextEntry(new ZipEntry(name)); + zip.write(bytes == null ? new byte[0] : bytes); + zip.closeEntry(); + } + + private String contentType(String key) { + return switch (extension(key)) { + case "jar" -> "application/java-archive"; + case "zip" -> "application/zip"; + case "png" -> "image/png"; + case "jpg", "jpeg" -> "image/jpeg"; + case "webp" -> "image/webp"; + case "gif" -> "image/gif"; + default -> "application/octet-stream"; + }; + } + + private ProjectClassification parseClassification(Object value) { + if (value == null) { + return ProjectClassification.PLUGIN; + } + + try { + return ProjectClassification.valueOf(value.toString().trim().toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + return ProjectClassification.PLUGIN; + } + } + + private String extension(String key) { + String filename = filenameStem(key); + int dot = filename.lastIndexOf('.'); + if (dot < 0 || dot == filename.length() - 1) { + return ""; + } + return filename.substring(dot + 1).toLowerCase(Locale.ROOT); + } + + private String filenameStem(String key) { + if (key == null || key.isBlank()) { + return ""; + } + String trimmed = key.trim(); + int query = trimmed.indexOf('?'); + if (query >= 0) { + trimmed = trimmed.substring(0, query); + } + int slash = trimmed.lastIndexOf('/'); + return slash >= 0 ? trimmed.substring(slash + 1) : trimmed; + } + + private String sanitizeStorageName(String value) { + String sanitized = firstNonBlank(value, "fixture") + .replaceAll("[^A-Za-z0-9._-]+", "-") + .replaceAll("-+", "-") + .replaceAll("(^-|-$)", ""); + return sanitized.isBlank() ? "fixture" : sanitized; + } + + private String firstNonBlank(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + private String stringValue(Object value) { + return value == null ? null : value.toString(); + } + + private String trimToNull(String value) { + if (value == null || value.isBlank()) { + return null; + } + return value.trim(); + } + + private boolean hasText(String value) { + return value != null && !value.isBlank(); + } + + private record R2SeedObject(String key, String projectName, String versionNumber, ProjectClassification classification) { + } + + private record R2SourceConfig(String bucket, String accessKey, String secretKey, String endpoint) { + } + + private record R2ObjectBytes(byte[] bytes, String contentType) { } private Set projectIds(List projects) { diff --git a/backend/src/main/java/net/modtale/config/properties/AppSeedingProperties.java b/backend/src/main/java/net/modtale/config/properties/AppSeedingProperties.java index 529012a2..6d64c7d3 100644 --- a/backend/src/main/java/net/modtale/config/properties/AppSeedingProperties.java +++ b/backend/src/main/java/net/modtale/config/properties/AppSeedingProperties.java @@ -8,7 +8,11 @@ public record AppSeedingProperties( @DefaultValue("false") boolean enabled, @DefaultValue("clone") Mode mode, @DefaultValue("false") boolean reset, - @DefaultValue("modtale") String sourceDb + @DefaultValue("modtale") String sourceDb, + @DefaultValue("") String sourceR2Bucket, + @DefaultValue("") String sourceR2AccessKey, + @DefaultValue("") String sourceR2SecretKey, + @DefaultValue("") String sourceR2Endpoint ) { public enum Mode { MOCK, diff --git a/backend/src/main/java/net/modtale/config/security/SecurityConfig.java b/backend/src/main/java/net/modtale/config/security/SecurityConfig.java index a896e1bd..c3bd89c3 100644 --- a/backend/src/main/java/net/modtale/config/security/SecurityConfig.java +++ b/backend/src/main/java/net/modtale/config/security/SecurityConfig.java @@ -13,11 +13,13 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import net.modtale.controller.auth.AuthController; import net.modtale.config.auth.ApiKeyAuthFilter; import net.modtale.config.properties.AppFrontendProperties; import net.modtale.exception.ErrorMessageUtils; import net.modtale.model.user.User; import net.modtale.service.auth.AuthenticationService; +import net.modtale.service.auth.LauncherAuthService; import net.modtale.service.auth.LocalUserDetailsService; import net.modtale.service.auth.OAuth2LoginService; import net.modtale.service.auth.OidcLoginService; @@ -69,6 +71,7 @@ public class SecurityConfig { private final PasswordEncoder passwordEncoder; private final AccountService accountService; private final AuthenticationService authenticationService; + private final LauncherAuthService launcherAuthService; private final AppFrontendProperties frontendProperties; public SecurityConfig( @@ -81,6 +84,7 @@ public SecurityConfig( PasswordEncoder passwordEncoder, AccountService accountService, AuthenticationService authenticationService, + LauncherAuthService launcherAuthService, AppFrontendProperties frontendProperties ) { this.apiKeyAuthFilter = apiKeyAuthFilter; @@ -92,6 +96,7 @@ public SecurityConfig( this.passwordEncoder = passwordEncoder; this.accountService = accountService; this.authenticationService = authenticationService; + this.launcherAuthService = launcherAuthService; this.frontendProperties = frontendProperties; } @@ -282,7 +287,10 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/api/v1/auth/verify", "/api/v1/auth/signin", "/api/v1/auth/logout", + "/api/v1/auth/oauth/**", + "/api/v1/auth/launcher/oauth/**", "/api/v1/auth/mfa/validate-login", + "/api/v1/auth/launcher/exchange", "/api/v1/auth/forgot-password", "/api/v1/auth/reset-password" ).permitAll() @@ -299,13 +307,14 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/api/v1/og/**", "/api/v1/download/**", "/api/v1/download-bundle/**", + "/api/v1/lists/**", "/api/v1/meta/**", "/api/v1/status", "/api/v1/version/**", "/api/v1/analytics/platform/stats", "/api/v1/wiki/**" ).permitAll() - .requestMatchers(HttpMethod.HEAD, "/api/v1/projects/**", "/api/v1/tags", "/api/v1/files/**", "/api/v1/user/profile/**", "/api/v1/og/**").permitAll() + .requestMatchers(HttpMethod.HEAD, "/api/v1/projects/**", "/api/v1/tags", "/api/v1/files/**", "/api/v1/user/profile/**", "/api/v1/og/**", "/api/v1/lists/**").permitAll() .requestMatchers(HttpMethod.POST, "/api/v1/users/batch" ).permitAll() @@ -482,9 +491,44 @@ public AuthenticationSuccessHandler oauthSuccessHandler() { User user = accountService.getPublicProfile(login); boolean isLinking = Boolean.TRUE.equals(oauthUser.getAttribute("is_linking")); + LauncherOAuthRequest launcherOAuthRequest = consumeLauncherOAuthRequest(request); + if (launcherOAuthRequest != null && !isLinking) { + if (user == null) { + response.sendRedirect(launcherCallbackUrl( + launcherOAuthRequest.redirectUri(), + "oauth_user_not_found", + launcherOAuthRequest.state(), + false + )); + return; + } + if (!user.isMfaEnabled()) { + SecurityContextRepository repository = securityContextRepository(); + repository.saveContext(SecurityContextHolder.getContext(), request, response); + try { + LauncherAuthService.LauncherAuthGrant grant = launcherAuthService.issueCode( + user, + launcherOAuthRequest.redirectUri(), + launcherOAuthRequest.state() + ); + response.sendRedirect(launcherCallbackUrl(grant.redirectUri(), grant.code(), grant.state(), true)); + } catch (RuntimeException ex) { + response.sendRedirect(launcherCallbackUrl( + launcherOAuthRequest.redirectUri(), + ex.getMessage(), + launcherOAuthRequest.state(), + false + )); + } + return; + } + } if (user != null && user.isMfaEnabled() && !isLinking) { String preAuthToken = authenticationService.generatePreAuthToken(user.getId()); + String postLoginRedirect = launcherOAuthRequest == null + ? consumePostOAuthRedirect(request, "/dashboard/profile") + : launcherAuthFrontendPath(launcherOAuthRequest); SecurityContextHolder.clearContext(); @@ -496,14 +540,16 @@ public AuthenticationSuccessHandler oauthSuccessHandler() { session.invalidate(); } - String cleanUrl = getCleanFrontendUrl(); - response.sendRedirect((cleanUrl != null ? cleanUrl : "") + "/mfa?token=" + preAuthToken); + String mfaPath = "/mfa?token=" + preAuthToken; + if (!"/dashboard/profile".equals(postLoginRedirect)) { + mfaPath += "&redirect=" + URLEncoder.encode(postLoginRedirect, StandardCharsets.UTF_8); + } + response.sendRedirect(frontendUrl(mfaPath)); } else { SecurityContextRepository repository = securityContextRepository(); repository.saveContext(SecurityContextHolder.getContext(), request, response); - String cleanUrl = getCleanFrontendUrl(); - response.sendRedirect((cleanUrl != null ? cleanUrl : "") + "/dashboard/profile"); + response.sendRedirect(frontendUrl(consumePostOAuthRedirect(request, "/dashboard/profile"))); } }; } @@ -511,12 +557,101 @@ public AuthenticationSuccessHandler oauthSuccessHandler() { @Bean public AuthenticationFailureHandler oauthFailureHandler() { return (request, response, exception) -> { + LauncherOAuthRequest launcherOAuthRequest = consumeLauncherOAuthRequest(request); + if (launcherOAuthRequest != null) { + response.sendRedirect(launcherCallbackUrl( + launcherOAuthRequest.redirectUri(), + exception.getMessage(), + launcherOAuthRequest.state(), + false + )); + return; + } String errorParam = URLEncoder.encode(exception.getMessage(), StandardCharsets.UTF_8); - String cleanUrl = getCleanFrontendUrl(); - response.sendRedirect((cleanUrl != null ? cleanUrl : "") + "/?oauth_error=" + errorParam); + String redirectPath = consumePostOAuthRedirect(request, "/"); + String separator = redirectPath.contains("?") ? "&" : "?"; + response.sendRedirect(frontendUrl(redirectPath + separator + "oauth_error=" + errorParam)); }; } + private String frontendUrl(String path) { + String cleanUrl = getCleanFrontendUrl(); + return (cleanUrl != null ? cleanUrl : "") + safeInternalRedirect(path, "/"); + } + + private LauncherOAuthRequest consumeLauncherOAuthRequest(HttpServletRequest request) { + HttpSession session = request.getSession(false); + if (session == null) { + return null; + } + + Object redirectUri = session.getAttribute(LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE); + Object state = session.getAttribute(LauncherAuthService.OAUTH_STATE_SESSION_ATTRIBUTE); + session.removeAttribute(LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE); + session.removeAttribute(LauncherAuthService.OAUTH_STATE_SESSION_ATTRIBUTE); + + if (redirectUri instanceof String redirect && !redirect.isBlank()) { + return new LauncherOAuthRequest(redirect, state instanceof String value ? value : ""); + } + return null; + } + + private String launcherAuthFrontendPath(LauncherOAuthRequest request) { + return "/launcher/auth?redirect_uri=" + URLEncoder.encode(request.redirectUri(), StandardCharsets.UTF_8) + + (request.state().isBlank() + ? "" + : "&state=" + URLEncoder.encode(request.state(), StandardCharsets.UTF_8)); + } + + private String launcherCallbackUrl(String redirectUri, String value, String state, boolean success) { + String key = success ? "code" : "error"; + int fragmentStart = redirectUri.indexOf('#'); + String base = fragmentStart >= 0 ? redirectUri.substring(0, fragmentStart) : redirectUri; + String fragment = fragmentStart >= 0 ? redirectUri.substring(fragmentStart) : ""; + + StringBuilder target = new StringBuilder(base); + if (base.contains("?")) { + if (!base.endsWith("?") && !base.endsWith("&")) { + target.append('&'); + } + } else { + target.append('?'); + } + + target.append(key).append('=').append(URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8)); + if (state != null && !state.isBlank()) { + target.append("&state=").append(URLEncoder.encode(state, StandardCharsets.UTF_8)); + } + target.append(fragment); + return target.toString(); + } + + private String consumePostOAuthRedirect(HttpServletRequest request, String fallback) { + HttpSession session = request.getSession(false); + if (session == null) { + return fallback; + } + + Object redirect = session.getAttribute(AuthController.POST_OAUTH_REDIRECT_ATTRIBUTE); + session.removeAttribute(AuthController.POST_OAUTH_REDIRECT_ATTRIBUTE); + if (redirect instanceof String redirectPath) { + return safeInternalRedirect(redirectPath, fallback); + } + return fallback; + } + + private String safeInternalRedirect(String redirect, String fallback) { + if (redirect == null || redirect.isBlank()) { + return fallback; + } + + String trimmed = redirect.trim(); + if (!trimmed.startsWith("/") || trimmed.startsWith("//")) { + return fallback; + } + return trimmed; + } + private URI safeUri(String rawUri, String description) { if (rawUri == null || rawUri.isBlank()) { return null; @@ -533,4 +668,7 @@ private String safeHostFromUrl(String rawUri) { URI uri = safeUri(rawUri, "request origin"); return uri != null ? uri.getHost() : null; } + + private record LauncherOAuthRequest(String redirectUri, String state) { + } } diff --git a/backend/src/main/java/net/modtale/controller/auth/AuthController.java b/backend/src/main/java/net/modtale/controller/auth/AuthController.java index c456de68..53196bc0 100644 --- a/backend/src/main/java/net/modtale/controller/auth/AuthController.java +++ b/backend/src/main/java/net/modtale/controller/auth/AuthController.java @@ -3,20 +3,23 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; +import java.io.IOException; import jakarta.validation.Valid; import java.time.Duration; -import java.util.Map; import java.util.stream.Collectors; import net.modtale.exception.InvalidAuthenticationRequestException; import net.modtale.exception.UnauthorizedException; import net.modtale.model.dto.request.auth.ChangePasswordRequest; import net.modtale.model.dto.request.auth.ForgotPasswordRequest; +import net.modtale.model.dto.request.auth.LauncherAuthExchangeRequest; +import net.modtale.model.dto.request.auth.LauncherAuthIssueRequest; import net.modtale.model.dto.request.auth.MfaLoginRequest; import net.modtale.model.dto.request.auth.RegisterRequest; import net.modtale.model.dto.request.auth.ResetPasswordRequest; import net.modtale.model.dto.request.auth.SignInRequest; import net.modtale.model.dto.request.auth.UpdateCredentialsRequest; import net.modtale.model.dto.request.auth.VerifyMfaRequest; +import net.modtale.model.dto.response.auth.LauncherAuthIssueResponse; import net.modtale.model.dto.response.auth.MfaChallengeResponse; import net.modtale.model.dto.response.auth.MfaSetupResponse; import net.modtale.model.dto.response.auth.RegistrationResponse; @@ -26,6 +29,7 @@ import net.modtale.model.user.User; import net.modtale.service.auth.AuthenticationMutationService; import net.modtale.service.auth.AuthenticationService; +import net.modtale.service.auth.LauncherAuthService; import net.modtale.service.auth.TwoFactorService; import net.modtale.service.user.account.AccountService; import org.springframework.http.HttpHeaders; @@ -44,10 +48,13 @@ @RequestMapping("/api/v1/auth") public class AuthController { + public static final String POST_OAUTH_REDIRECT_ATTRIBUTE = "MODTALE_POST_OAUTH_REDIRECT"; + private final AuthenticationService authenticationService; private final AuthenticationMutationService authenticationMutationService; private final AccountService accountService; private final TwoFactorService twoFactorService; + private final LauncherAuthService launcherAuthService; private final SecurityContextRepository securityContextRepository; public AuthController( @@ -55,12 +62,14 @@ public AuthController( AuthenticationMutationService authenticationMutationService, AccountService accountService, TwoFactorService twoFactorService, + LauncherAuthService launcherAuthService, SecurityContextRepository securityContextRepository ) { this.authenticationService = authenticationService; this.authenticationMutationService = authenticationMutationService; this.accountService = accountService; this.twoFactorService = twoFactorService; + this.launcherAuthService = launcherAuthService; this.securityContextRepository = securityContextRepository; } @@ -191,6 +200,80 @@ public ResponseEntity validateLoginMfa(@Valid @RequestBody MfaLo return ResponseEntity.ok(new StatusResponse("success")); } + @GetMapping("/oauth/{provider}") + public void beginOAuthLogin( + @PathVariable String provider, + @RequestParam(value = "redirect", required = false) String redirect, + HttpServletRequest request, + HttpServletResponse response + ) throws IOException { + if (!provider.matches("[A-Za-z0-9_-]+")) { + throw new InvalidAuthenticationRequestException("That OAuth provider is not valid."); + } + + String safeRedirect = safeInternalRedirect(redirect); + if (safeRedirect != null) { + request.getSession(true).setAttribute(POST_OAUTH_REDIRECT_ATTRIBUTE, safeRedirect); + } + + response.sendRedirect("/oauth2/authorization/" + provider); + } + + @GetMapping("/launcher/oauth/{provider}") + public void beginLauncherOAuthLogin( + @PathVariable String provider, + @RequestParam("redirect_uri") String redirectUri, + @RequestParam(value = "state", required = false) String state, + HttpServletRequest request, + HttpServletResponse response + ) throws IOException { + if (!provider.matches("[A-Za-z0-9_-]+")) { + throw new InvalidAuthenticationRequestException("That OAuth provider is not valid."); + } + + launcherAuthService.validateLoopbackRedirectUri(redirectUri); + HttpSession session = request.getSession(true); + session.setAttribute(LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE, redirectUri.trim()); + session.setAttribute(LauncherAuthService.OAUTH_STATE_SESSION_ATTRIBUTE, state == null ? "" : state.trim()); + + response.sendRedirect("/oauth2/authorization/" + provider); + } + + @PostMapping("/launcher/issue") + @PreAuthorize("@apiSecurity.hasPersonalPerm('PROFILE_READ', authentication)") + public ResponseEntity issueLauncherAuthCode( + @Valid @RequestBody LauncherAuthIssueRequest requestPayload, + Authentication authentication + ) { + User user = accountService.requireCurrentUser(authentication, "authorizing the Modtale Launcher"); + LauncherAuthService.LauncherAuthGrant grant = launcherAuthService.issueCode( + user, + requestPayload.getRedirectUri(), + requestPayload.getState() + ); + return ResponseEntity.ok(new LauncherAuthIssueResponse( + grant.code(), + grant.redirectUri(), + grant.state(), + grant.expiresIn() + )); + } + + @PostMapping("/launcher/exchange") + public ResponseEntity exchangeLauncherAuthCode( + @Valid @RequestBody LauncherAuthExchangeRequest requestPayload, + HttpServletRequest request, + HttpServletResponse response + ) { + User user = launcherAuthService.consumeCode(requestPayload.getCode()); + if (user == null) { + throw new UnauthorizedException("That launcher authorization code is invalid or has expired. Please sign in again."); + } + + createSession(user, request, response); + return ResponseEntity.ok(new StatusResponse("success")); + } + private void createSession(User user, HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(true); @@ -214,4 +297,16 @@ private void expireCookie(HttpServletResponse response, String name) { response.addHeader(HttpHeaders.SET_COOKIE, expiredCookie.toString()); } + private String safeInternalRedirect(String redirect) { + if (redirect == null || redirect.isBlank()) { + return null; + } + + String trimmed = redirect.trim(); + if (!trimmed.startsWith("/") || trimmed.startsWith("//")) { + return null; + } + return trimmed; + } + } diff --git a/backend/src/main/java/net/modtale/controller/user/UserController.java b/backend/src/main/java/net/modtale/controller/user/UserController.java index 6288bb5a..e9cf484c 100644 --- a/backend/src/main/java/net/modtale/controller/user/UserController.java +++ b/backend/src/main/java/net/modtale/controller/user/UserController.java @@ -16,6 +16,7 @@ import net.modtale.model.dto.user.UserDTO; import net.modtale.model.dto.user.UserSummaryDTO; import net.modtale.model.project.Project; +import net.modtale.model.user.LauncherSettingsSnapshot; import net.modtale.model.user.User; import net.modtale.repository.user.UserRepository; import net.modtale.service.media.MediaUploadService; @@ -185,6 +186,33 @@ public ResponseEntity updateNotificationSettings( return ResponseEntity.ok().build(); } + @GetMapping("/user/launcher-settings") + @PreAuthorize("@apiSecurity.hasPersonalPerm('PROFILE_READ', authentication)") + public ResponseEntity getLauncherSettings(Authentication authentication) { + User user = accountService.requireCurrentUser(authentication, "loading launcher settings"); + return ResponseEntity.ok(accountService.getLauncherSettings(user.getId())); + } + + @PutMapping("/user/launcher-settings") + @PreAuthorize("@apiSecurity.hasPersonalPerm('PROFILE_EDIT_BASIC', authentication)") + public ResponseEntity updateLauncherSettings( + @RequestBody LauncherSettingsSnapshot snapshot, + Authentication authentication + ) { + User user = accountService.requireCurrentUser(authentication, "syncing launcher settings"); + return ResponseEntity.ok(accountService.updateLauncherSettings(user.getId(), snapshot)); + } + + @PutMapping("/user/launcher-settings/preferences") + @PreAuthorize("@apiSecurity.hasPersonalPerm('PROFILE_EDIT_BASIC', authentication)") + public ResponseEntity updateLauncherSettingsPreferences( + @RequestBody LauncherSettingsSnapshot snapshot, + Authentication authentication + ) { + User user = accountService.requireCurrentUser(authentication, "syncing launcher settings"); + return ResponseEntity.ok(accountService.updateLauncherSettingsPreferences(user.getId(), snapshot)); + } + @PostMapping("/user/follow/{targetId}") @PreAuthorize("@apiSecurity.hasPersonalPerm('PROFILE_FOLLOW', authentication)") public ResponseEntity followUser(@PathVariable String targetId, Authentication authentication) { diff --git a/backend/src/main/java/net/modtale/controller/worldlist/WorldModListController.java b/backend/src/main/java/net/modtale/controller/worldlist/WorldModListController.java new file mode 100644 index 00000000..f5a17e07 --- /dev/null +++ b/backend/src/main/java/net/modtale/controller/worldlist/WorldModListController.java @@ -0,0 +1,63 @@ +package net.modtale.controller.worldlist; + +import jakarta.validation.Valid; +import java.io.IOException; +import net.modtale.model.dto.request.worldlist.CreateWorldModListRequest; +import net.modtale.model.dto.worldlist.WorldModListDTO; +import net.modtale.service.user.account.AccountService; +import net.modtale.service.worldlist.WorldModListService; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1") +public class WorldModListController { + + private final WorldModListService service; + private final AccountService accountService; + + public WorldModListController(WorldModListService service, AccountService accountService) { + this.service = service; + this.accountService = accountService; + } + + @PostMapping("/lists") + public ResponseEntity create( + @Valid @RequestBody CreateWorldModListRequest request, + Authentication authentication + ) { + return ResponseEntity.ok(service.create( + request, + accountService.requireCurrentUser(authentication, "sharing a world mod list") + )); + } + + @GetMapping("/lists/{id}") + public ResponseEntity view(@PathVariable String id) { + return ResponseEntity.ok(service.view(id)); + } + + @GetMapping("/lists/{id}/install") + public ResponseEntity installMetadata(@PathVariable String id) { + return ResponseEntity.ok(service.metadataForInstall(id)); + } + + @GetMapping("/lists/{id}/download") + public ResponseEntity download(@PathVariable String id) throws IOException { + WorldModListService.Download download = service.download(id); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + download.filename() + "\"") + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(new ByteArrayResource(download.bytes())); + } +} diff --git a/backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthExchangeRequest.java b/backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthExchangeRequest.java new file mode 100644 index 00000000..ec1425c8 --- /dev/null +++ b/backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthExchangeRequest.java @@ -0,0 +1,17 @@ +package net.modtale.model.dto.request.auth; + +import jakarta.validation.constraints.NotBlank; + +public class LauncherAuthExchangeRequest { + + @NotBlank(message = "A launcher authorization code is required.") + private String code; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} diff --git a/backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthIssueRequest.java b/backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthIssueRequest.java new file mode 100644 index 00000000..63b4a143 --- /dev/null +++ b/backend/src/main/java/net/modtale/model/dto/request/auth/LauncherAuthIssueRequest.java @@ -0,0 +1,27 @@ +package net.modtale.model.dto.request.auth; + +import jakarta.validation.constraints.NotBlank; + +public class LauncherAuthIssueRequest { + + @NotBlank(message = "A launcher callback URL is required.") + private String redirectUri; + + private String state; + + public String getRedirectUri() { + return redirectUri; + } + + public void setRedirectUri(String redirectUri) { + this.redirectUri = redirectUri; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } +} diff --git a/backend/src/main/java/net/modtale/model/dto/request/worldlist/CreateWorldModListRequest.java b/backend/src/main/java/net/modtale/model/dto/request/worldlist/CreateWorldModListRequest.java new file mode 100644 index 00000000..37611dd2 --- /dev/null +++ b/backend/src/main/java/net/modtale/model/dto/request/worldlist/CreateWorldModListRequest.java @@ -0,0 +1,28 @@ +package net.modtale.model.dto.request.worldlist; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; +import java.util.List; +import net.modtale.model.project.ProjectClassification; +import net.modtale.model.project.ProjectDependency; + +public record CreateWorldModListRequest( + @Size(max = 120) String title, + @Size(max = 120) String worldName, + @Size(max = 60) String gameVersion, + @NotEmpty @Size(max = 200) List<@Valid Item> mods +) { + public record Item( + @Size(max = 160) String modId, + @Size(max = 120) String projectId, + @Size(max = 160) String slug, + @Size(max = 180) String title, + @Size(max = 80) String versionNumber, + ProjectClassification classification, + ProjectDependency.Source source, + @Size(max = 180) String externalId, + @Size(max = 600) String externalUrl, + @Size(max = 600) String icon + ) {} +} diff --git a/backend/src/main/java/net/modtale/model/dto/response/auth/LauncherAuthIssueResponse.java b/backend/src/main/java/net/modtale/model/dto/response/auth/LauncherAuthIssueResponse.java new file mode 100644 index 00000000..56a10a3e --- /dev/null +++ b/backend/src/main/java/net/modtale/model/dto/response/auth/LauncherAuthIssueResponse.java @@ -0,0 +1,4 @@ +package net.modtale.model.dto.response.auth; + +public record LauncherAuthIssueResponse(String code, String redirectUri, String state, int expiresIn) { +} diff --git a/backend/src/main/java/net/modtale/model/dto/worldlist/WorldModListDTO.java b/backend/src/main/java/net/modtale/model/dto/worldlist/WorldModListDTO.java new file mode 100644 index 00000000..e0cd1d14 --- /dev/null +++ b/backend/src/main/java/net/modtale/model/dto/worldlist/WorldModListDTO.java @@ -0,0 +1,48 @@ +package net.modtale.model.dto.worldlist; + +import java.time.Instant; +import java.util.List; +import net.modtale.model.project.ProjectClassification; +import net.modtale.model.project.ProjectDependency; + +public record WorldModListDTO( + String id, + String title, + String worldName, + String gameVersion, + String ownerUsername, + Instant createdAt, + Instant lastViewedAt, + Instant expiresAt, + int viewCount, + int downloadCount, + int modCount, + int downloadableCount, + String shareUrl, + String downloadUrl, + String launcherInstallUrl, + List mods +) { + public record Item( + String id, + String modId, + String projectId, + String slug, + String title, + String authorId, + String author, + String description, + String versionNumber, + ProjectClassification classification, + ProjectDependency.Source source, + String externalId, + String externalUrl, + String icon, + String bannerUrl, + int downloadCount, + int favoriteCount, + String updatedAt, + boolean downloadable, + String unavailableReason + ) {} +} diff --git a/backend/src/main/java/net/modtale/model/user/LauncherSettingsSnapshot.java b/backend/src/main/java/net/modtale/model/user/LauncherSettingsSnapshot.java new file mode 100644 index 00000000..35ea1151 --- /dev/null +++ b/backend/src/main/java/net/modtale/model/user/LauncherSettingsSnapshot.java @@ -0,0 +1,205 @@ +package net.modtale.model.user; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class LauncherSettingsSnapshot implements Serializable { + + private static final long serialVersionUID = 1L; + + private int schemaVersion = 1; + private String settingsHash = ""; + private String updatedAt = ""; + private Preferences preferences = new Preferences(); + private List installedProjects = new ArrayList<>(); + + public int getSchemaVersion() { + return schemaVersion; + } + + public void setSchemaVersion(int schemaVersion) { + this.schemaVersion = Math.max(1, schemaVersion); + } + + public String getSettingsHash() { + return settingsHash; + } + + public void setSettingsHash(String settingsHash) { + this.settingsHash = settingsHash == null ? "" : settingsHash.trim(); + } + + public String getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt == null ? "" : updatedAt.trim(); + } + + public Preferences getPreferences() { + return preferences; + } + + public void setPreferences(Preferences preferences) { + this.preferences = preferences == null ? new Preferences() : preferences; + } + + public List getInstalledProjects() { + return installedProjects; + } + + public void setInstalledProjects(List installedProjects) { + this.installedProjects = installedProjects == null ? new ArrayList<>() : new ArrayList<>(installedProjects); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Preferences implements Serializable { + private static final long serialVersionUID = 1L; + + private String hytaleModsPath = ""; + private String hytaleGamePath = ""; + private String hytaleUserDataPath = ""; + private String hytaleJavaPath = ""; + private String hytaleBranch = "release"; + private int hytaleBuild; + private String gameVersion = ""; + private boolean includeDependencies = true; + private boolean includeOptionalDependencies; + private boolean autoCheckUpdates = true; + private boolean launcherAutoUpdates; + + public String getHytaleModsPath() { return hytaleModsPath; } + public void setHytaleModsPath(String hytaleModsPath) { this.hytaleModsPath = hytaleModsPath; } + public String getHytaleGamePath() { return hytaleGamePath; } + public void setHytaleGamePath(String hytaleGamePath) { this.hytaleGamePath = hytaleGamePath; } + public String getHytaleUserDataPath() { return hytaleUserDataPath; } + public void setHytaleUserDataPath(String hytaleUserDataPath) { this.hytaleUserDataPath = hytaleUserDataPath; } + public String getHytaleJavaPath() { return hytaleJavaPath; } + public void setHytaleJavaPath(String hytaleJavaPath) { this.hytaleJavaPath = hytaleJavaPath; } + public String getHytaleBranch() { return hytaleBranch; } + public void setHytaleBranch(String hytaleBranch) { this.hytaleBranch = hytaleBranch; } + public int getHytaleBuild() { return hytaleBuild; } + public void setHytaleBuild(int hytaleBuild) { this.hytaleBuild = Math.max(0, hytaleBuild); } + public String getGameVersion() { return gameVersion; } + public void setGameVersion(String gameVersion) { this.gameVersion = gameVersion; } + public boolean isIncludeDependencies() { return includeDependencies; } + public void setIncludeDependencies(boolean includeDependencies) { this.includeDependencies = includeDependencies; } + public boolean isIncludeOptionalDependencies() { return includeOptionalDependencies; } + public void setIncludeOptionalDependencies(boolean includeOptionalDependencies) { this.includeOptionalDependencies = includeOptionalDependencies; } + public boolean isAutoCheckUpdates() { return autoCheckUpdates; } + public void setAutoCheckUpdates(boolean autoCheckUpdates) { this.autoCheckUpdates = autoCheckUpdates; } + public boolean isLauncherAutoUpdates() { return launcherAutoUpdates; } + public void setLauncherAutoUpdates(boolean launcherAutoUpdates) { this.launcherAutoUpdates = launcherAutoUpdates; } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class InstalledProject implements Serializable { + private static final long serialVersionUID = 1L; + + private String projectId = ""; + private String slug = ""; + private String title = ""; + private String classification = ""; + private String installedVersion = ""; + private String installedVersionId = ""; + private String gameVersion = ""; + private String source = "MODTALE"; + private String installType = "DIRECT"; + private boolean modpackUnlocked; + private List dependencyProjectIds = new ArrayList<>(); + private List externalDependencies = new ArrayList<>(); + private List bundledProjects = new ArrayList<>(); + + public String getProjectId() { return projectId; } + public void setProjectId(String projectId) { this.projectId = projectId; } + public String getSlug() { return slug; } + public void setSlug(String slug) { this.slug = slug; } + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + public String getClassification() { return classification; } + public void setClassification(String classification) { this.classification = classification; } + public String getInstalledVersion() { return installedVersion; } + public void setInstalledVersion(String installedVersion) { this.installedVersion = installedVersion; } + public String getInstalledVersionId() { return installedVersionId; } + public void setInstalledVersionId(String installedVersionId) { this.installedVersionId = installedVersionId; } + public String getGameVersion() { return gameVersion; } + public void setGameVersion(String gameVersion) { this.gameVersion = gameVersion; } + public String getSource() { return source; } + public void setSource(String source) { this.source = source; } + public String getInstallType() { return installType; } + public void setInstallType(String installType) { this.installType = installType; } + public boolean isModpackUnlocked() { return modpackUnlocked; } + public void setModpackUnlocked(boolean modpackUnlocked) { this.modpackUnlocked = modpackUnlocked; } + public List getDependencyProjectIds() { return dependencyProjectIds; } + public void setDependencyProjectIds(List dependencyProjectIds) { + this.dependencyProjectIds = dependencyProjectIds == null ? new ArrayList<>() : new ArrayList<>(dependencyProjectIds); + } + public List getExternalDependencies() { return externalDependencies; } + public void setExternalDependencies(List externalDependencies) { + this.externalDependencies = externalDependencies == null ? new ArrayList<>() : new ArrayList<>(externalDependencies); + } + public List getBundledProjects() { return bundledProjects; } + public void setBundledProjects(List bundledProjects) { + this.bundledProjects = bundledProjects == null ? new ArrayList<>() : new ArrayList<>(bundledProjects); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class InstalledProjectReference implements Serializable { + private static final long serialVersionUID = 1L; + + private String id = ""; + private String projectId = ""; + private String slug = ""; + private String title = ""; + private String classification = ""; + private String versionNumber = ""; + private String dependencyType = ""; + private String source = ""; + private String externalId = ""; + private String externalUrl = ""; + private String externalFileUrl = ""; + private String externalFileName = ""; + private String cachedFileUrl = ""; + private String icon = ""; + private Boolean optional; + private Boolean embedded; + + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public String getProjectId() { return projectId; } + public void setProjectId(String projectId) { this.projectId = projectId; } + public String getSlug() { return slug; } + public void setSlug(String slug) { this.slug = slug; } + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + public String getClassification() { return classification; } + public void setClassification(String classification) { this.classification = classification; } + public String getVersionNumber() { return versionNumber; } + public void setVersionNumber(String versionNumber) { this.versionNumber = versionNumber; } + public String getDependencyType() { return dependencyType; } + public void setDependencyType(String dependencyType) { this.dependencyType = dependencyType; } + public String getSource() { return source; } + public void setSource(String source) { this.source = source; } + public String getExternalId() { return externalId; } + public void setExternalId(String externalId) { this.externalId = externalId; } + public String getExternalUrl() { return externalUrl; } + public void setExternalUrl(String externalUrl) { this.externalUrl = externalUrl; } + public String getExternalFileUrl() { return externalFileUrl; } + public void setExternalFileUrl(String externalFileUrl) { this.externalFileUrl = externalFileUrl; } + public String getExternalFileName() { return externalFileName; } + public void setExternalFileName(String externalFileName) { this.externalFileName = externalFileName; } + public String getCachedFileUrl() { return cachedFileUrl; } + public void setCachedFileUrl(String cachedFileUrl) { this.cachedFileUrl = cachedFileUrl; } + public String getIcon() { return icon; } + public void setIcon(String icon) { this.icon = icon; } + public Boolean getOptional() { return optional; } + public void setOptional(Boolean optional) { this.optional = optional; } + public Boolean getEmbedded() { return embedded; } + public void setEmbedded(Boolean embedded) { this.embedded = embedded; } + } +} diff --git a/backend/src/main/java/net/modtale/model/user/User.java b/backend/src/main/java/net/modtale/model/user/User.java index a33c9eb5..0cd140b5 100644 --- a/backend/src/main/java/net/modtale/model/user/User.java +++ b/backend/src/main/java/net/modtale/model/user/User.java @@ -74,6 +74,8 @@ public class User implements Serializable { private NotificationPreferences notificationPreferences = new NotificationPreferences(); + private LauncherSettingsSnapshot launcherSettings; + private String githubAccessToken; private String gitlabAccessToken; @@ -284,6 +286,9 @@ public ConnectedAccount(OAuthProvider provider, String providerId, String userna public NotificationPreferences getNotificationPreferences() { return notificationPreferences; } public void setNotificationPreferences(NotificationPreferences notificationPreferences) { this.notificationPreferences = notificationPreferences; } + public LauncherSettingsSnapshot getLauncherSettings() { return launcherSettings; } + public void setLauncherSettings(LauncherSettingsSnapshot launcherSettings) { this.launcherSettings = launcherSettings; } + public String getGithubAccessToken() { return githubAccessToken; } public void setGithubAccessToken(String githubAccessToken) { this.githubAccessToken = githubAccessToken; } diff --git a/backend/src/main/java/net/modtale/model/worldlist/WorldModList.java b/backend/src/main/java/net/modtale/model/worldlist/WorldModList.java new file mode 100644 index 00000000..92c6e703 --- /dev/null +++ b/backend/src/main/java/net/modtale/model/worldlist/WorldModList.java @@ -0,0 +1,158 @@ +package net.modtale.model.worldlist; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import net.modtale.model.project.ProjectClassification; +import net.modtale.model.project.ProjectDependency; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +@Document(collection = "world_mod_lists") +@CompoundIndex(name = "world_mod_lists_expires_idx", def = "{'expiresAt': 1}") +public class WorldModList { + + @MongoId(FieldType.STRING) + private String id = UUID.randomUUID().toString(); + + @Indexed + private String ownerId; + + private String ownerUsername; + private String title; + private String worldName; + private String gameVersion; + private Instant createdAt; + private Instant lastViewedAt; + private Instant expiresAt; + private int viewCount; + private int downloadCount; + private List mods = new ArrayList<>(); + + public String getId() { return id; } + public void setId(String id) { this.id = id == null || id.isBlank() ? UUID.randomUUID().toString() : id; } + + public String getOwnerId() { return ownerId; } + public void setOwnerId(String ownerId) { this.ownerId = ownerId; } + + public String getOwnerUsername() { return ownerUsername; } + public void setOwnerUsername(String ownerUsername) { this.ownerUsername = ownerUsername; } + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public String getWorldName() { return worldName; } + public void setWorldName(String worldName) { this.worldName = worldName; } + + public String getGameVersion() { return gameVersion; } + public void setGameVersion(String gameVersion) { this.gameVersion = gameVersion; } + + public Instant getCreatedAt() { return createdAt; } + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } + + public Instant getLastViewedAt() { return lastViewedAt; } + public void setLastViewedAt(Instant lastViewedAt) { this.lastViewedAt = lastViewedAt; } + + public Instant getExpiresAt() { return expiresAt; } + public void setExpiresAt(Instant expiresAt) { this.expiresAt = expiresAt; } + + public int getViewCount() { return viewCount; } + public void setViewCount(int viewCount) { this.viewCount = Math.max(0, viewCount); } + + public int getDownloadCount() { return downloadCount; } + public void setDownloadCount(int downloadCount) { this.downloadCount = Math.max(0, downloadCount); } + + public List getMods() { return mods; } + public void setMods(List mods) { this.mods = mods == null ? new ArrayList<>() : new ArrayList<>(mods); } + + public static class Item { + private String id = UUID.randomUUID().toString(); + private String modId; + private String projectId; + private String slug; + private String title; + private String authorId; + private String author; + private String description; + private String versionNumber; + private ProjectClassification classification; + private ProjectDependency.Source source = ProjectDependency.Source.MODTALE; + private String externalId; + private String externalUrl; + private String icon; + private String bannerUrl; + private int downloadCount; + private int favoriteCount; + private String updatedAt; + private String fileUrl; + private boolean downloadable; + private String unavailableReason; + + public String getId() { return id; } + public void setId(String id) { this.id = id == null || id.isBlank() ? UUID.randomUUID().toString() : id; } + + public String getModId() { return modId; } + public void setModId(String modId) { this.modId = modId; } + + public String getProjectId() { return projectId; } + public void setProjectId(String projectId) { this.projectId = projectId; } + + public String getSlug() { return slug; } + public void setSlug(String slug) { this.slug = slug; } + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public String getAuthorId() { return authorId; } + public void setAuthorId(String authorId) { this.authorId = authorId; } + + public String getAuthor() { return author; } + public void setAuthor(String author) { this.author = author; } + + public String getDescription() { return description; } + public void setDescription(String description) { this.description = description; } + + public String getVersionNumber() { return versionNumber; } + public void setVersionNumber(String versionNumber) { this.versionNumber = versionNumber; } + + public ProjectClassification getClassification() { return classification; } + public void setClassification(ProjectClassification classification) { this.classification = classification; } + + public ProjectDependency.Source getSource() { return source == null ? ProjectDependency.Source.MODTALE : source; } + public void setSource(ProjectDependency.Source source) { this.source = source == null ? ProjectDependency.Source.MODTALE : source; } + + public String getExternalId() { return externalId; } + public void setExternalId(String externalId) { this.externalId = externalId; } + + public String getExternalUrl() { return externalUrl; } + public void setExternalUrl(String externalUrl) { this.externalUrl = externalUrl; } + + public String getIcon() { return icon; } + public void setIcon(String icon) { this.icon = icon; } + + public String getBannerUrl() { return bannerUrl; } + public void setBannerUrl(String bannerUrl) { this.bannerUrl = bannerUrl; } + + public int getDownloadCount() { return downloadCount; } + public void setDownloadCount(int downloadCount) { this.downloadCount = Math.max(0, downloadCount); } + + public int getFavoriteCount() { return favoriteCount; } + public void setFavoriteCount(int favoriteCount) { this.favoriteCount = Math.max(0, favoriteCount); } + + public String getUpdatedAt() { return updatedAt; } + public void setUpdatedAt(String updatedAt) { this.updatedAt = updatedAt; } + + public String getFileUrl() { return fileUrl; } + public void setFileUrl(String fileUrl) { this.fileUrl = fileUrl; } + + public boolean isDownloadable() { return downloadable; } + public void setDownloadable(boolean downloadable) { this.downloadable = downloadable; } + + public String getUnavailableReason() { return unavailableReason; } + public void setUnavailableReason(String unavailableReason) { this.unavailableReason = unavailableReason; } + } +} diff --git a/backend/src/main/java/net/modtale/repository/worldlist/WorldModListRepository.java b/backend/src/main/java/net/modtale/repository/worldlist/WorldModListRepository.java new file mode 100644 index 00000000..296f083b --- /dev/null +++ b/backend/src/main/java/net/modtale/repository/worldlist/WorldModListRepository.java @@ -0,0 +1,9 @@ +package net.modtale.repository.worldlist; + +import java.time.Instant; +import net.modtale.model.worldlist.WorldModList; +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface WorldModListRepository extends MongoRepository { + void deleteByExpiresAtBefore(Instant cutoff); +} diff --git a/backend/src/main/java/net/modtale/service/auth/LauncherAuthService.java b/backend/src/main/java/net/modtale/service/auth/LauncherAuthService.java new file mode 100644 index 00000000..c7964ca8 --- /dev/null +++ b/backend/src/main/java/net/modtale/service/auth/LauncherAuthService.java @@ -0,0 +1,108 @@ +package net.modtale.service.auth; + +import java.net.URI; +import java.security.SecureRandom; +import java.time.Duration; +import java.time.Instant; +import java.util.Base64; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import net.modtale.exception.InvalidAuthenticationRequestException; +import net.modtale.model.user.User; +import net.modtale.repository.user.UserRepository; +import org.springframework.stereotype.Service; + +@Service +public class LauncherAuthService { + + public static final String OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE = "MODTALE_LAUNCHER_OAUTH_REDIRECT_URI"; + public static final String OAUTH_STATE_SESSION_ATTRIBUTE = "MODTALE_LAUNCHER_OAUTH_STATE"; + private static final Duration CODE_VALIDITY = Duration.ofMinutes(5); + private static final int CODE_LENGTH_BYTES = 32; + + private final Map codes = new ConcurrentHashMap<>(); + private final SecureRandom secureRandom = new SecureRandom(); + private final UserRepository userRepository; + + public LauncherAuthService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + public LauncherAuthGrant issueCode(User user, String redirectUri, String state) { + if (user == null || user.getId() == null || user.getId().isBlank()) { + throw new InvalidAuthenticationRequestException("You need to sign in before authorizing the Modtale Launcher."); + } + validateLoopbackRedirectUri(redirectUri); + cleanExpiredCodes(); + + byte[] randomBytes = new byte[CODE_LENGTH_BYTES]; + secureRandom.nextBytes(randomBytes); + String code = Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes); + Instant expiresAt = Instant.now().plus(CODE_VALIDITY); + codes.put(code, new LauncherAuthCode(user.getId(), expiresAt)); + + return new LauncherAuthGrant(code, redirectUri, normalizeState(state), Math.toIntExact(CODE_VALIDITY.toSeconds())); + } + + public User consumeCode(String code) { + if (code == null || code.isBlank()) { + return null; + } + + LauncherAuthCode authCode = codes.remove(code); + if (authCode == null || authCode.isExpired()) { + return null; + } + + Optional user = userRepository.findById(authCode.userId()); + return user.filter(candidate -> !candidate.isDeleted()).orElse(null); + } + + public int getActiveCodeCount() { + cleanExpiredCodes(); + return codes.size(); + } + + public void validateLoopbackRedirectUri(String redirectUri) { + URI uri; + try { + uri = URI.create(redirectUri == null ? "" : redirectUri.trim()); + } catch (IllegalArgumentException ex) { + throw new InvalidAuthenticationRequestException("The launcher callback URL is invalid."); + } + + String scheme = uri.getScheme(); + String host = uri.getHost(); + if (!"http".equalsIgnoreCase(scheme) || host == null || uri.getPort() < 1) { + throw new InvalidAuthenticationRequestException("The launcher callback URL must use a local HTTP callback."); + } + + String normalizedHost = host.toLowerCase(Locale.ROOT); + boolean loopback = "localhost".equals(normalizedHost) + || "127.0.0.1".equals(normalizedHost) + || "::1".equals(normalizedHost) + || "[::1]".equals(normalizedHost); + if (!loopback) { + throw new InvalidAuthenticationRequestException("The launcher callback URL must point to this device."); + } + } + + private static String normalizeState(String state) { + return state == null ? "" : state.trim(); + } + + private void cleanExpiredCodes() { + codes.entrySet().removeIf(entry -> entry.getValue().isExpired()); + } + + public record LauncherAuthGrant(String code, String redirectUri, String state, int expiresIn) { + } + + private record LauncherAuthCode(String userId, Instant expiresAt) { + boolean isExpired() { + return Instant.now().isAfter(expiresAt); + } + } +} diff --git a/backend/src/main/java/net/modtale/service/auth/OAuth2LoginService.java b/backend/src/main/java/net/modtale/service/auth/OAuth2LoginService.java index 689e5528..0e7b3c3f 100644 --- a/backend/src/main/java/net/modtale/service/auth/OAuth2LoginService.java +++ b/backend/src/main/java/net/modtale/service/auth/OAuth2LoginService.java @@ -1,6 +1,7 @@ package net.modtale.service.auth; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; import net.modtale.exception.AuthenticationOperationException; import net.modtale.exception.ForbiddenOperationException; import net.modtale.exception.InvalidAuthenticationRequestException; @@ -43,8 +44,11 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic try { Authentication currentAuth = currentAuthentication(); - if (currentAuth != null && currentAuth.isAuthenticated() && - !currentAuth.getName().equals("anonymousUser")) { + boolean linking = !hasPendingLauncherOAuth() + && currentAuth != null && currentAuth.isAuthenticated() + && !currentAuth.getName().equals("anonymousUser"); + + if (linking) { User currentUser = accountService.getCurrentUser(); @@ -53,6 +57,10 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic } } + if ("gitlab".equalsIgnoreCase(provider)) { + throw new InvalidAuthenticationRequestException("GitLab can be linked from profile settings, but it cannot be used to sign in."); + } + return authenticationService.processUserLogin(provider, oauthUser, accessToken); } catch (OAuthAccountCollisionException ex) { throw new OAuth2AuthenticationException(new OAuth2Error("account_collision"), ex.getMessage()); @@ -68,6 +76,13 @@ private Authentication currentAuthentication() { return request != null && request.getUserPrincipal() instanceof Authentication auth ? auth : null; } + private boolean hasPendingLauncherOAuth() { + HttpServletRequest request = requestProvider.getIfAvailable(); + HttpSession session = request == null ? null : request.getSession(false); + return session != null + && session.getAttribute(LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE) instanceof String; + } + protected OAuth2User fetchOAuthUser(OAuth2UserRequest userRequest) { return super.loadUser(userRequest); } diff --git a/backend/src/main/java/net/modtale/service/auth/OidcLoginService.java b/backend/src/main/java/net/modtale/service/auth/OidcLoginService.java index 323871a4..d98bfff8 100644 --- a/backend/src/main/java/net/modtale/service/auth/OidcLoginService.java +++ b/backend/src/main/java/net/modtale/service/auth/OidcLoginService.java @@ -1,6 +1,7 @@ package net.modtale.service.auth; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; import java.util.Map; import net.modtale.exception.AuthenticationOperationException; import net.modtale.exception.ForbiddenOperationException; @@ -49,7 +50,8 @@ public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2Authenticatio Authentication currentAuth = currentAuthentication(); HttpServletRequest request = currentRequest(); - if (currentAuth != null && currentAuth.isAuthenticated() && !currentAuth.getName().equals("anonymousUser")) { + if (!hasPendingLauncherOAuth() + && currentAuth != null && currentAuth.isAuthenticated() && !currentAuth.getName().equals("anonymousUser")) { String pendingOrgId = request != null ? (String) request.getSession().getAttribute("pending_org_link_id") : null; @@ -89,6 +91,13 @@ private HttpServletRequest currentRequest() { return requestProvider.getIfAvailable(); } + private boolean hasPendingLauncherOAuth() { + HttpServletRequest request = currentRequest(); + HttpSession session = request == null ? null : request.getSession(false); + return session != null + && session.getAttribute(LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE) instanceof String; + } + protected OidcUser fetchOidcUser(OidcUserRequest userRequest) { return super.loadUser(userRequest); } diff --git a/backend/src/main/java/net/modtale/service/project/version/VersionDownloadOrchestrationService.java b/backend/src/main/java/net/modtale/service/project/version/VersionDownloadOrchestrationService.java index e7681e31..003ab1fa 100644 --- a/backend/src/main/java/net/modtale/service/project/version/VersionDownloadOrchestrationService.java +++ b/backend/src/main/java/net/modtale/service/project/version/VersionDownloadOrchestrationService.java @@ -5,6 +5,7 @@ import net.modtale.config.properties.AppFrontendProperties; import net.modtale.exception.InvalidDownloadTokenException; import net.modtale.exception.ResourceNotFoundException; +import net.modtale.exception.UnauthorizedException; import net.modtale.exception.VersionNotFoundException; import net.modtale.model.dto.response.project.BundleDownloadUrlResponse; import net.modtale.model.dto.response.project.DownloadUrlResponse; @@ -63,7 +64,7 @@ public DownloadUrlResponse createDownloadUrl(String projectId, String versionNum "We couldn't find that project, so no download link could be generated."); getVersionOrThrow(project, versionNumber, gameVersion, "We couldn't find the requested version for that project."); - String token = downloadTokenService.generateToken(projectId, versionNumber, gameVersion); + String token = downloadTokenService.generateToken(projectId, versionNumber, gameVersion, null, currentUserId(currentUser)); return new DownloadUrlResponse("/download/" + token, downloadTokenService.getTokenValiditySeconds()); } @@ -78,7 +79,7 @@ public BundleDownloadUrlResponse createBundleDownloadUrl( "We couldn't find that project, so no bundle download link could be generated."); getVersionOrThrow(project, versionNumber, gameVersion, "We couldn't find the requested version for that bundle download."); - String token = downloadTokenService.generateToken(projectId, versionNumber, gameVersion, dependencies); + String token = downloadTokenService.generateToken(projectId, versionNumber, gameVersion, dependencies, currentUserId(currentUser)); return new BundleDownloadUrlResponse("/download-bundle/" + token, downloadTokenService.getTokenValiditySeconds()); } @@ -90,12 +91,12 @@ public VersionDownloadPayload downloadVersion( String forwardedFor, User currentUser ) throws IOException { - DownloadContext context = resolveDownloadContext(apiRole, referer, remoteAddress, forwardedFor, currentUser); DownloadTokenService.DownloadToken downloadToken = validateToken(token, "This download link is invalid, expired, or has already been used."); + DownloadContext context = resolveDownloadContext(downloadToken, apiRole, referer, remoteAddress, forwardedFor, currentUser); Project project = getRawProjectOrThrow(downloadToken.getProjectId(), "We couldn't find the project for this download link."); - ensureReadable(project, currentUser); + ensureReadable(project, context.currentUser()); ProjectVersion targetVersion = getVersionOrThrow(project, downloadToken.getVersion(), downloadToken.getGameVersion(), "We couldn't find the version requested by this download link."); @@ -121,12 +122,12 @@ public VersionDownloadPayload downloadBundle( String forwardedFor, User currentUser ) throws IOException { - DownloadContext context = resolveDownloadContext(apiRole, referer, remoteAddress, forwardedFor, currentUser); DownloadTokenService.DownloadToken downloadToken = validateToken(token, "This bundle download link is invalid, expired, or has already been used."); + DownloadContext context = resolveDownloadContext(downloadToken, apiRole, referer, remoteAddress, forwardedFor, currentUser); Project project = getRawProjectOrThrow(downloadToken.getProjectId(), "We couldn't find the project for this bundle download link."); - ensureReadable(project, currentUser); + ensureReadable(project, context.currentUser()); ProjectVersion targetVersion = getVersionOrThrow(project, downloadToken.getVersion(), downloadToken.getGameVersion(), "We couldn't find the version requested by this bundle download link."); @@ -152,15 +153,17 @@ public VersionDownloadPayload downloadBundle( } private DownloadContext resolveDownloadContext( + DownloadTokenService.DownloadToken downloadToken, boolean apiRole, String referer, String remoteAddress, String forwardedFor, User currentUser ) { + User effectiveUser = requireTokenUser(downloadToken, currentUser); boolean apiRequest = apiRole || referer == null || !referer.startsWith(frontendUrl); String clientIp = forwardedFor == null ? remoteAddress : forwardedFor.split(",")[0].trim(); - return new DownloadContext(apiRequest, clientIp, currentUser); + return new DownloadContext(apiRequest, clientIp, effectiveUser); } private DownloadTokenService.DownloadToken validateToken(String token, String failureMessage) { @@ -171,6 +174,22 @@ private DownloadTokenService.DownloadToken validateToken(String token, String fa return downloadToken; } + private User requireTokenUser(DownloadTokenService.DownloadToken downloadToken, User currentUser) { + String tokenUserId = downloadToken.getUserId(); + if (tokenUserId == null || tokenUserId.isBlank()) { + return currentUser; + } + + if (currentUser == null || currentUser.getId() == null || !tokenUserId.equals(currentUser.getId())) { + throw new UnauthorizedException("Sign in with the account that created this download link before using it."); + } + return currentUser; + } + + private String currentUserId(User currentUser) { + return currentUser == null ? null : currentUser.getId(); + } + private Project getProjectOrThrow(String projectId, User currentUser, String failureMessage) { Project project = projectService.getProjectById(projectId, currentUser); if (project == null) { diff --git a/backend/src/main/java/net/modtale/service/storage/DownloadTokenService.java b/backend/src/main/java/net/modtale/service/storage/DownloadTokenService.java index 62bbaccd..d94b540b 100644 --- a/backend/src/main/java/net/modtale/service/storage/DownloadTokenService.java +++ b/backend/src/main/java/net/modtale/service/storage/DownloadTokenService.java @@ -21,15 +21,21 @@ public static class DownloadToken { private final String projectId; private final String version; private final String gameVersion; + private final String userId; private final Instant expiresAt; private final List selectedDependencies; private boolean used; public DownloadToken(String projectId, String version, String gameVersion, List selectedDependencies, Instant expiresAt) { + this(projectId, version, gameVersion, selectedDependencies, null, expiresAt); + } + + public DownloadToken(String projectId, String version, String gameVersion, List selectedDependencies, String userId, Instant expiresAt) { this.projectId = projectId; this.version = version; this.gameVersion = gameVersion; this.selectedDependencies = selectedDependencies; + this.userId = userId; this.expiresAt = expiresAt; this.used = false; } @@ -37,6 +43,7 @@ public DownloadToken(String projectId, String version, String gameVersion, List< public String getProjectId() { return projectId; } public String getVersion() { return version; } public String getGameVersion() { return gameVersion; } + public String getUserId() { return userId; } public List getSelectedDependencies() { return selectedDependencies; } public Instant getExpiresAt() { return expiresAt; } public boolean isUsed() { return used; } @@ -48,6 +55,10 @@ public boolean isExpired() { } public String generateToken(String projectId, String version, String gameVersion, List selectedDependencies) { + return generateToken(projectId, version, gameVersion, selectedDependencies, null); + } + + public String generateToken(String projectId, String version, String gameVersion, List selectedDependencies, String userId) { cleanExpiredTokens(); byte[] randomBytes = new byte[TOKEN_LENGTH]; @@ -55,7 +66,7 @@ public String generateToken(String projectId, String version, String gameVersion String token = Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes); Instant expiresAt = Instant.now().plusSeconds(TOKEN_VALIDITY_MINUTES * 60); - tokens.put(token, new DownloadToken(projectId, version, gameVersion, selectedDependencies, expiresAt)); + tokens.put(token, new DownloadToken(projectId, version, gameVersion, selectedDependencies, userId, expiresAt)); return token; } diff --git a/backend/src/main/java/net/modtale/service/storage/StorageService.java b/backend/src/main/java/net/modtale/service/storage/StorageService.java index f5cffc87..9d04b329 100644 --- a/backend/src/main/java/net/modtale/service/storage/StorageService.java +++ b/backend/src/main/java/net/modtale/service/storage/StorageService.java @@ -185,6 +185,11 @@ public boolean exists(String fileName) { return true; } catch (NoSuchKeyException e) { return false; + } catch (S3Exception e) { + if (e.statusCode() == 404) { + return false; + } + throw StorageDownloadException.from(e, "Failed to check the requested file."); } catch (SdkException e) { throw StorageDownloadException.from(e, "Failed to check the requested file."); } diff --git a/backend/src/main/java/net/modtale/service/user/account/AccountService.java b/backend/src/main/java/net/modtale/service/user/account/AccountService.java index 6646106d..fa14d5ec 100644 --- a/backend/src/main/java/net/modtale/service/user/account/AccountService.java +++ b/backend/src/main/java/net/modtale/service/user/account/AccountService.java @@ -7,6 +7,7 @@ import net.modtale.exception.InvalidAccountRequestException; import net.modtale.exception.ResourceNotFoundException; import net.modtale.model.project.Project; +import net.modtale.model.user.LauncherSettingsSnapshot; import net.modtale.model.user.OAuthProvider; import net.modtale.model.user.User; import net.modtale.repository.user.UserRepository; @@ -26,6 +27,11 @@ @Service public class AccountService { + private static final int MAX_LAUNCHER_SYNC_PROJECTS = 500; + private static final int MAX_LAUNCHER_SYNC_LIST_ITEMS = 64; + private static final int MAX_LAUNCHER_SYNC_STRING = 512; + private static final int MAX_LAUNCHER_SYNC_HASH = 128; + private final UserRepository userRepository; private final MongoTemplate mongoTemplate; private final SanitizationService sanitizer; @@ -157,6 +163,27 @@ public void updateNotificationPreferences(String userId, User.NotificationPrefer userRepository.save(user); } + public LauncherSettingsSnapshot getLauncherSettings(String userId) { + User user = userRepository.findById(userId).orElseThrow(() -> new ResourceNotFoundException("User not found.")); + return user.getLauncherSettings() == null ? new LauncherSettingsSnapshot() : user.getLauncherSettings(); + } + + public LauncherSettingsSnapshot updateLauncherSettings(String userId, LauncherSettingsSnapshot snapshot) { + User user = userRepository.findById(userId).orElseThrow(() -> new ResourceNotFoundException("User not found.")); + LauncherSettingsSnapshot normalized = normalizeLauncherSettings(snapshot); + user.setLauncherSettings(normalized); + userRepository.save(user); + return normalized; + } + + public LauncherSettingsSnapshot updateLauncherSettingsPreferences(String userId, LauncherSettingsSnapshot snapshot) { + User user = userRepository.findById(userId).orElseThrow(() -> new ResourceNotFoundException("User not found.")); + LauncherSettingsSnapshot normalized = normalizeLauncherSettingsPreferences(snapshot, user.getLauncherSettings()); + user.setLauncherSettings(normalized); + userRepository.save(user); + return normalized; + } + public void toggleConnectionVisibility(String userId, String provider) { if ("google".equalsIgnoreCase(provider)) { throw new InvalidAccountRequestException("Google accounts cannot be made visible on public profiles."); @@ -210,6 +237,145 @@ public void recoverUser(String userId) { accountLifecycleService.recoverUser(userId); } + private LauncherSettingsSnapshot normalizeLauncherSettings(LauncherSettingsSnapshot snapshot) { + LauncherSettingsSnapshot source = snapshot == null ? new LauncherSettingsSnapshot() : snapshot; + LauncherSettingsSnapshot normalized = new LauncherSettingsSnapshot(); + normalized.setSchemaVersion(source.getSchemaVersion()); + normalized.setSettingsHash(limit(source.getSettingsHash(), MAX_LAUNCHER_SYNC_HASH)); + normalized.setUpdatedAt(LocalDateTime.now().toString()); + normalized.setPreferences(normalizeLauncherPreferences(source.getPreferences())); + normalized.setInstalledProjects(normalizeInstalledProjects(source.getInstalledProjects())); + return normalized; + } + + private LauncherSettingsSnapshot normalizeLauncherSettingsPreferences( + LauncherSettingsSnapshot snapshot, + LauncherSettingsSnapshot existing + ) { + LauncherSettingsSnapshot source = snapshot == null ? new LauncherSettingsSnapshot() : snapshot; + LauncherSettingsSnapshot stored = existing == null ? new LauncherSettingsSnapshot() : existing; + LauncherSettingsSnapshot normalized = new LauncherSettingsSnapshot(); + normalized.setSchemaVersion(source.getSchemaVersion()); + normalized.setSettingsHash(limit(source.getSettingsHash(), MAX_LAUNCHER_SYNC_HASH)); + normalized.setUpdatedAt(LocalDateTime.now().toString()); + normalized.setPreferences(normalizeLauncherPreferences(source.getPreferences())); + normalized.setInstalledProjects(normalizeInstalledProjects(stored.getInstalledProjects())); + return normalized; + } + + private LauncherSettingsSnapshot.Preferences normalizeLauncherPreferences(LauncherSettingsSnapshot.Preferences source) { + LauncherSettingsSnapshot.Preferences preferences = new LauncherSettingsSnapshot.Preferences(); + if (source == null) { + return preferences; + } + preferences.setHytaleModsPath(limit(source.getHytaleModsPath(), MAX_LAUNCHER_SYNC_STRING)); + preferences.setHytaleGamePath(limit(source.getHytaleGamePath(), MAX_LAUNCHER_SYNC_STRING)); + preferences.setHytaleUserDataPath(limit(source.getHytaleUserDataPath(), MAX_LAUNCHER_SYNC_STRING)); + preferences.setHytaleJavaPath(limit(source.getHytaleJavaPath(), MAX_LAUNCHER_SYNC_STRING)); + preferences.setHytaleBranch(limit(source.getHytaleBranch(), MAX_LAUNCHER_SYNC_STRING)); + preferences.setHytaleBuild(source.getHytaleBuild()); + preferences.setGameVersion(limit(source.getGameVersion(), MAX_LAUNCHER_SYNC_STRING)); + preferences.setIncludeDependencies(source.isIncludeDependencies()); + preferences.setIncludeOptionalDependencies(source.isIncludeOptionalDependencies()); + preferences.setAutoCheckUpdates(source.isAutoCheckUpdates()); + preferences.setLauncherAutoUpdates(source.isLauncherAutoUpdates()); + return preferences; + } + + private List normalizeInstalledProjects( + List source + ) { + if (source == null || source.isEmpty()) { + return List.of(); + } + List normalized = new ArrayList<>(); + for (LauncherSettingsSnapshot.InstalledProject project : source) { + if (project == null || isBlank(project.getProjectId()) || normalized.size() >= MAX_LAUNCHER_SYNC_PROJECTS) { + continue; + } + LauncherSettingsSnapshot.InstalledProject copy = new LauncherSettingsSnapshot.InstalledProject(); + copy.setProjectId(limit(project.getProjectId(), MAX_LAUNCHER_SYNC_STRING)); + copy.setSlug(limit(project.getSlug(), MAX_LAUNCHER_SYNC_STRING)); + copy.setTitle(limit(project.getTitle(), MAX_LAUNCHER_SYNC_STRING)); + copy.setClassification(limit(project.getClassification(), MAX_LAUNCHER_SYNC_STRING)); + copy.setInstalledVersion(limit(project.getInstalledVersion(), MAX_LAUNCHER_SYNC_STRING)); + copy.setInstalledVersionId(limit(project.getInstalledVersionId(), MAX_LAUNCHER_SYNC_STRING)); + copy.setGameVersion(limit(project.getGameVersion(), MAX_LAUNCHER_SYNC_STRING)); + copy.setSource(defaultValue(limit(project.getSource(), MAX_LAUNCHER_SYNC_STRING), "MODTALE")); + copy.setInstallType(defaultValue(limit(project.getInstallType(), MAX_LAUNCHER_SYNC_STRING), "DIRECT")); + copy.setModpackUnlocked(project.isModpackUnlocked()); + copy.setDependencyProjectIds(normalizeStringList(project.getDependencyProjectIds())); + copy.setExternalDependencies(normalizeStringList(project.getExternalDependencies())); + copy.setBundledProjects(normalizeInstalledProjectReferences(project.getBundledProjects())); + normalized.add(copy); + } + return normalized; + } + + private List normalizeInstalledProjectReferences( + List source + ) { + if (source == null || source.isEmpty()) { + return List.of(); + } + List normalized = new ArrayList<>(); + for (LauncherSettingsSnapshot.InstalledProjectReference reference : source) { + if (reference == null || normalized.size() >= MAX_LAUNCHER_SYNC_LIST_ITEMS) { + continue; + } + LauncherSettingsSnapshot.InstalledProjectReference copy = + new LauncherSettingsSnapshot.InstalledProjectReference(); + copy.setId(limit(reference.getId(), MAX_LAUNCHER_SYNC_STRING)); + copy.setProjectId(limit(reference.getProjectId(), MAX_LAUNCHER_SYNC_STRING)); + copy.setSlug(limit(reference.getSlug(), MAX_LAUNCHER_SYNC_STRING)); + copy.setTitle(limit(reference.getTitle(), MAX_LAUNCHER_SYNC_STRING)); + copy.setClassification(limit(reference.getClassification(), MAX_LAUNCHER_SYNC_STRING)); + copy.setVersionNumber(limit(reference.getVersionNumber(), MAX_LAUNCHER_SYNC_STRING)); + copy.setDependencyType(limit(reference.getDependencyType(), MAX_LAUNCHER_SYNC_STRING)); + copy.setSource(limit(reference.getSource(), MAX_LAUNCHER_SYNC_STRING)); + copy.setExternalId(limit(reference.getExternalId(), MAX_LAUNCHER_SYNC_STRING)); + copy.setExternalUrl(limit(reference.getExternalUrl(), MAX_LAUNCHER_SYNC_STRING)); + copy.setExternalFileUrl(limit(reference.getExternalFileUrl(), MAX_LAUNCHER_SYNC_STRING)); + copy.setExternalFileName(limit(reference.getExternalFileName(), MAX_LAUNCHER_SYNC_STRING)); + copy.setCachedFileUrl(limit(reference.getCachedFileUrl(), MAX_LAUNCHER_SYNC_STRING)); + copy.setIcon(limit(reference.getIcon(), MAX_LAUNCHER_SYNC_STRING)); + copy.setOptional(reference.getOptional()); + copy.setEmbedded(reference.getEmbedded()); + normalized.add(copy); + } + return normalized; + } + + private List normalizeStringList(List source) { + if (source == null || source.isEmpty()) { + return List.of(); + } + List normalized = new ArrayList<>(); + for (String value : source) { + String next = limit(value, MAX_LAUNCHER_SYNC_STRING); + if (!next.isBlank() && !normalized.contains(next)) { + normalized.add(next); + } + if (normalized.size() >= MAX_LAUNCHER_SYNC_LIST_ITEMS) { + break; + } + } + return normalized; + } + + private static String limit(String value, int maxLength) { + String trimmed = value == null ? "" : value.trim(); + return trimmed.length() <= maxLength ? trimmed : trimmed.substring(0, maxLength); + } + + private static String defaultValue(String value, String fallback) { + return value == null || value.isBlank() ? fallback : value; + } + + private static boolean isBlank(String value) { + return value == null || value.isBlank(); + } + @Scheduled(cron = "0 0 0 * * ?") public void cleanupDeletedUsers() { accountLifecycleService.cleanupDeletedUsers(); diff --git a/backend/src/main/java/net/modtale/service/worldlist/WorldModListArchiveService.java b/backend/src/main/java/net/modtale/service/worldlist/WorldModListArchiveService.java new file mode 100644 index 00000000..72b9c23d --- /dev/null +++ b/backend/src/main/java/net/modtale/service/worldlist/WorldModListArchiveService.java @@ -0,0 +1,115 @@ +package net.modtale.service.worldlist; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import net.modtale.exception.StorageDownloadException; +import net.modtale.model.worldlist.WorldModList; +import net.modtale.service.storage.StorageService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.ObjectWriter; + +@Service +public class WorldModListArchiveService { + + private static final Logger logger = LoggerFactory.getLogger(WorldModListArchiveService.class); + private final StorageService storageService; + private final ObjectWriter manifestWriter; + + public WorldModListArchiveService(StorageService storageService, ObjectMapper mapper) { + this.storageService = storageService; + this.manifestWriter = mapper.writerWithDefaultPrettyPrinter(); + } + + public byte[] generateZip(WorldModList list) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (ZipOutputStream zip = new ZipOutputStream(bytes)) { + Set entries = new HashSet<>(); + writeEntry(zip, entries, "modtale-list.json", manifestWriter.writeValueAsBytes(list)); + writeEntry(zip, entries, "README.txt", readme(list).getBytes(StandardCharsets.UTF_8)); + + for (WorldModList.Item item : list.getMods()) { + if (!item.isDownloadable() || item.getFileUrl() == null || item.getFileUrl().isBlank()) { + continue; + } + try { + byte[] file = storageService.download(item.getFileUrl()); + writeEntry(zip, entries, filename(item), file); + } catch (StorageDownloadException ex) { + logger.warn("Skipping unavailable world list file {} for list {}", item.getFileUrl(), list.getId(), ex); + } + } + } + return bytes.toByteArray(); + } + + private void writeEntry(ZipOutputStream zip, Set entries, String rawName, byte[] data) throws IOException { + String entryName = unique(entries, sanitize(rawName)); + zip.putNextEntry(new ZipEntry(entryName)); + zip.write(data == null ? new byte[0] : data); + zip.closeEntry(); + } + + private String filename(WorldModList.Item item) { + String base = firstText(item.getTitle(), item.getSlug(), item.getProjectId(), item.getModId(), "mod"); + String version = firstText(item.getVersionNumber(), "latest"); + return base + "-" + version + ".jar"; + } + + private String readme(WorldModList list) { + return "Modtale world mod list\n" + + "World: " + firstText(list.getWorldName(), "Unknown world") + "\n" + + "List: " + firstText(list.getTitle(), "Shared mod list") + "\n" + + "Game version: " + firstText(list.getGameVersion(), "Not specified") + "\n\n" + + "This ZIP contains the downloadable Modtale projects from the shared list. " + + "Some local or external entries may appear only in modtale-list.json."; + } + + private static String unique(Set entries, String filename) { + String candidate = filename; + int counter = 2; + while (!entries.add(candidate)) { + int dot = filename.lastIndexOf('.'); + candidate = dot > 0 + ? filename.substring(0, dot) + "-" + counter + filename.substring(dot) + : filename + "-" + counter; + counter++; + } + return candidate; + } + + private static String sanitize(String filename) { + String sanitized = firstText(filename, "modtale-list-file") + .replaceAll("[^A-Za-z0-9._-]+", "-") + .replaceAll("-+", "-") + .replaceAll("(^-|-$)", ""); + if (sanitized.isBlank()) { + return "modtale-list-file"; + } + String lower = sanitized.toLowerCase(Locale.ROOT); + if (lower.endsWith(".txt") || lower.endsWith(".json") || lower.endsWith(".jar") || lower.endsWith(".zip")) { + return sanitized; + } + return sanitized + ".jar"; + } + + private static String firstText(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } +} diff --git a/backend/src/main/java/net/modtale/service/worldlist/WorldModListMapper.java b/backend/src/main/java/net/modtale/service/worldlist/WorldModListMapper.java new file mode 100644 index 00000000..89149a6c --- /dev/null +++ b/backend/src/main/java/net/modtale/service/worldlist/WorldModListMapper.java @@ -0,0 +1,86 @@ +package net.modtale.service.worldlist; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import net.modtale.config.properties.AppFrontendProperties; +import net.modtale.model.dto.worldlist.WorldModListDTO; +import net.modtale.model.worldlist.WorldModList; +import org.springframework.stereotype.Component; + +@Component +final class WorldModListMapper { + + private final String frontendUrl; + + WorldModListMapper(AppFrontendProperties frontendProperties) { + this.frontendUrl = trimTrailingSlash(frontendProperties.url()); + } + + WorldModListDTO toDTO(WorldModList list) { + if (list == null) { + return null; + } + int downloadable = (int) list.getMods().stream() + .filter(WorldModList.Item::isDownloadable) + .count(); + String shareUrl = frontendUrl + "/lists/" + list.getId(); + String downloadUrl = "/lists/" + list.getId() + "/download"; + String launcherInstallUrl = "modtale://install-list?listId=" + encode(list.getId()) + "&url=" + encode(shareUrl); + return new WorldModListDTO( + list.getId(), + list.getTitle(), + list.getWorldName(), + list.getGameVersion(), + list.getOwnerUsername(), + list.getCreatedAt(), + list.getLastViewedAt(), + list.getExpiresAt(), + list.getViewCount(), + list.getDownloadCount(), + list.getMods().size(), + downloadable, + shareUrl, + downloadUrl, + launcherInstallUrl, + list.getMods().stream().map(this::toItemDTO).toList() + ); + } + + private WorldModListDTO.Item toItemDTO(WorldModList.Item item) { + return new WorldModListDTO.Item( + item.getId(), + item.getModId(), + item.getProjectId(), + item.getSlug(), + item.getTitle(), + item.getAuthorId(), + item.getAuthor(), + item.getDescription(), + item.getVersionNumber(), + item.getClassification(), + item.getSource(), + item.getExternalId(), + item.getExternalUrl(), + item.getIcon(), + item.getBannerUrl(), + item.getDownloadCount(), + item.getFavoriteCount(), + item.getUpdatedAt(), + item.isDownloadable(), + item.getUnavailableReason() + ); + } + + private static String trimTrailingSlash(String value) { + String normalized = value == null || value.isBlank() ? "https://modtale.net" : value.trim(); + while (normalized.endsWith("/")) { + normalized = normalized.substring(0, normalized.length() - 1); + } + return normalized; + } + + private static String encode(String value) { + return URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8).replace("+", "%20"); + } +} diff --git a/backend/src/main/java/net/modtale/service/worldlist/WorldModListService.java b/backend/src/main/java/net/modtale/service/worldlist/WorldModListService.java new file mode 100644 index 00000000..f026d2cb --- /dev/null +++ b/backend/src/main/java/net/modtale/service/worldlist/WorldModListService.java @@ -0,0 +1,343 @@ +package net.modtale.service.worldlist; + +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import net.modtale.exception.InvalidProjectRequestException; +import net.modtale.exception.ResourceNotFoundException; +import net.modtale.model.dto.request.worldlist.CreateWorldModListRequest; +import net.modtale.model.dto.worldlist.WorldModListDTO; +import net.modtale.model.project.Project; +import net.modtale.model.project.ProjectDependency; +import net.modtale.model.project.ProjectVersion; +import net.modtale.model.user.User; +import net.modtale.model.worldlist.WorldModList; +import net.modtale.repository.worldlist.WorldModListRepository; +import net.modtale.service.project.access.ProjectVersionAccessService; +import net.modtale.service.project.query.ProjectService; +import net.modtale.service.security.access.AccessControlService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Service +public class WorldModListService { + + private static final Duration EXPIRY_WINDOW = Duration.ofDays(30); + + private final WorldModListRepository repository; + private final ProjectService projectService; + private final ProjectVersionAccessService versionAccessService; + private final AccessControlService accessControlService; + private final WorldModListArchiveService archiveService; + private final WorldModListMapper mapper; + + public WorldModListService( + WorldModListRepository repository, + ProjectService projectService, + ProjectVersionAccessService versionAccessService, + AccessControlService accessControlService, + WorldModListArchiveService archiveService, + WorldModListMapper mapper + ) { + this.repository = repository; + this.projectService = projectService; + this.versionAccessService = versionAccessService; + this.accessControlService = accessControlService; + this.archiveService = archiveService; + this.mapper = mapper; + } + + public WorldModListDTO create(CreateWorldModListRequest request, User owner) { + if (owner == null) { + throw new InvalidProjectRequestException("Sign in before sharing a world mod list."); + } + List requestedMods = request.mods() == null ? List.of() : request.mods(); + Map items = new LinkedHashMap<>(); + for (CreateWorldModListRequest.Item requested : requestedMods) { + WorldModList.Item item = normalizeItem(requested, request.gameVersion(), owner); + String key = itemKey(item); + if (!key.isBlank()) { + items.putIfAbsent(key, item); + } + } + if (items.isEmpty()) { + throw new InvalidProjectRequestException("Pick at least one enabled mod before sharing this list."); + } + + Instant now = Instant.now(); + WorldModList list = new WorldModList(); + list.setOwnerId(owner.getId()); + list.setOwnerUsername(owner.getUsername()); + list.setTitle(firstText(request.title(), request.worldName(), "Shared world mods")); + list.setWorldName(firstText(request.worldName(), "Hytale world")); + list.setGameVersion(value(request.gameVersion())); + list.setCreatedAt(now); + list.setLastViewedAt(now); + list.setExpiresAt(now.plus(EXPIRY_WINDOW)); + list.setMods(items.values().stream().toList()); + return mapper.toDTO(repository.save(list)); + } + + public WorldModListDTO view(String id) { + return mapper.toDTO(touch(findActive(id), true, false)); + } + + public WorldModListDTO metadataForInstall(String id) { + return mapper.toDTO(touch(findActive(id), true, false)); + } + + public Download download(String id) throws IOException { + WorldModList list = touch(findActive(id), true, true); + return new Download(filename(list), archiveService.generateZip(list)); + } + + @Scheduled(cron = "${app.world-lists.cleanup-cron:0 20 3 * * ?}") + public void cleanupExpiredLists() { + repository.deleteByExpiresAtBefore(Instant.now()); + } + + private WorldModList touch(WorldModList list, boolean view, boolean download) { + refreshPublicProjectMetadata(list); + Instant now = Instant.now(); + list.setLastViewedAt(now); + list.setExpiresAt(now.plus(EXPIRY_WINDOW)); + if (view) { + list.setViewCount(list.getViewCount() + 1); + } + if (download) { + list.setDownloadCount(list.getDownloadCount() + 1); + } + return repository.save(list); + } + + private WorldModList findActive(String id) { + WorldModList list = repository.findById(id == null ? "" : id.trim()).orElse(null); + if (list == null || isExpired(list)) { + throw new ResourceNotFoundException("That shared mod list is gone or has expired."); + } + return list; + } + + private boolean isExpired(WorldModList list) { + return list.getExpiresAt() != null && Instant.now().isAfter(list.getExpiresAt()); + } + + private void refreshPublicProjectMetadata(WorldModList list) { + if (list == null || list.getMods() == null || list.getMods().isEmpty()) { + return; + } + for (WorldModList.Item item : list.getMods()) { + Project project = projectFor(item); + if (project == null || !accessControlService.isPubliclyReadable(project)) { + continue; + } + applyProjectMetadata(item, project); + item.setSource(ProjectDependency.Source.MODTALE); + } + } + + private WorldModList.Item normalizeItem(CreateWorldModListRequest.Item requested, String gameVersion, User owner) { + WorldModList.Item item = new WorldModList.Item(); + if (requested == null) { + item.setUnavailableReason("Empty list item."); + return item; + } + + item.setModId(value(requested.modId())); + item.setProjectId(value(requested.projectId())); + item.setSlug(value(requested.slug())); + item.setTitle(firstText(requested.title(), requested.modId(), requested.projectId(), "Unknown mod")); + item.setVersionNumber(value(requested.versionNumber())); + item.setClassification(requested.classification()); + item.setSource(requested.source() == null ? sourceFor(requested) : requested.source()); + item.setExternalId(value(requested.externalId())); + item.setExternalUrl(value(requested.externalUrl())); + item.setIcon(value(requested.icon())); + + if (item.getSource() == ProjectDependency.Source.MODTALE || !item.getProjectId().isBlank()) { + enrichModtaleItem(item, gameVersion, owner); + } else { + item.setDownloadable(false); + item.setUnavailableReason("Listed only; Modtale cannot package this external or local file."); + } + return item; + } + + private void enrichModtaleItem(WorldModList.Item item, String gameVersion, User owner) { + Project project = projectFor(item); + if (project == null || !accessControlService.isPubliclyReadable(project) || !accessControlService.canReadProject(project, owner)) { + item.setDownloadable(false); + item.setUnavailableReason("Project is not public on Modtale."); + return; + } + + ProjectVersion version = versionFor(project, item.getVersionNumber(), gameVersion); + applyProjectMetadata(item, project); + item.setSource(ProjectDependency.Source.MODTALE); + item.setVersionNumber(version == null ? item.getVersionNumber() : version.getVersionNumber()); + item.setFileUrl(version == null ? "" : value(version.getFileUrl())); + item.setDownloadable(version != null && version.getFileUrl() != null && !version.getFileUrl().isBlank()); + if (!item.isDownloadable()) { + item.setUnavailableReason("No downloadable public version could be resolved."); + } + } + + private void applyProjectMetadata(WorldModList.Item item, Project project) { + item.setProjectId(project.getId()); + item.setSlug(firstText(project.getSlug(), project.getId())); + item.setTitle(firstText(project.getTitle(), item.getTitle())); + item.setAuthorId(value(project.getAuthorId())); + item.setAuthor(value(project.getAuthor())); + item.setDescription(value(project.getDescription())); + item.setClassification(project.getClassification()); + item.setIcon(firstText(project.getImageUrl(), item.getIcon())); + item.setBannerUrl(value(project.getBannerUrl())); + item.setDownloadCount(project.getDownloadCount()); + item.setFavoriteCount(project.getFavoriteCount()); + item.setUpdatedAt(value(project.getUpdatedAt())); + } + + private Project projectFor(WorldModList.Item item) { + if (item == null) { + return null; + } + String projectId = value(item.getProjectId()); + if (!projectId.isBlank()) { + Project project = projectService.getRawProjectById(projectId); + if (project != null) { + return project; + } + } + String slug = value(item.getSlug()); + if (!slug.isBlank()) { + Project project = projectService.getRawProjectByRouteKey(slug); + if (project != null) { + return project; + } + } + for (String candidate : routeKeyCandidates(item)) { + Project project = projectService.getRawProjectByRouteKey(candidate); + if (project != null) { + return project; + } + } + return null; + } + + private Set routeKeyCandidates(WorldModList.Item item) { + LinkedHashSet candidates = new LinkedHashSet<>(); + addRouteKeyCandidates(candidates, item.getExternalId()); + addRouteKeyCandidates(candidates, item.getModId()); + addRouteKeyCandidates(candidates, item.getTitle()); + return candidates; + } + + private void addRouteKeyCandidates(Set candidates, String value) { + String normalized = value(value); + if (normalized.isBlank()) { + return; + } + candidates.add(normalized); + addSlugCandidates(candidates, normalized); + + int separator = normalized.lastIndexOf(':'); + if (separator >= 0 && separator < normalized.length() - 1) { + String suffix = normalized.substring(separator + 1).trim(); + if (!suffix.isBlank()) { + candidates.add(suffix); + addSlugCandidates(candidates, suffix); + } + } + } + + private void addSlugCandidates(Set candidates, String value) { + String camelSeparated = value.replaceAll("([a-z0-9])([A-Z])", "$1-$2"); + String slug = camelSeparated.toLowerCase(java.util.Locale.ROOT) + .replaceAll("[^a-z0-9]+", "-") + .replaceAll("(^-|-$)", ""); + if (!slug.isBlank()) { + candidates.add(slug); + } + + String compact = value.toLowerCase(java.util.Locale.ROOT) + .replaceAll("[^a-z0-9]+", ""); + if (!compact.isBlank()) { + candidates.add(compact); + } + } + + private ProjectVersion versionFor(Project project, String versionNumber, String gameVersion) { + ProjectVersion version = null; + if (versionNumber != null && !versionNumber.isBlank()) { + version = versionAccessService.findByVersionNumber(project, versionNumber, gameVersion); + } + if (isApproved(version)) { + return version; + } + return project.getVersions() == null ? null : project.getVersions().stream() + .filter(this::isApproved) + .filter(candidate -> supportsGameVersion(candidate, gameVersion)) + .max(Comparator.comparing(ProjectVersion::getReleaseDate, Comparator.nullsLast(String::compareTo))) + .orElse(null); + } + + private boolean isApproved(ProjectVersion version) { + return version != null && version.getReviewStatus() == ProjectVersion.ReviewStatus.APPROVED; + } + + private boolean supportsGameVersion(ProjectVersion version, String gameVersion) { + return gameVersion == null + || gameVersion.isBlank() + || version.getGameVersions() == null + || version.getGameVersions().stream().anyMatch(gameVersion::equalsIgnoreCase); + } + + private ProjectDependency.Source sourceFor(CreateWorldModListRequest.Item item) { + return item.projectId() == null || item.projectId().isBlank() + ? ProjectDependency.Source.OTHER + : ProjectDependency.Source.MODTALE; + } + + private String itemKey(WorldModList.Item item) { + if (!item.getProjectId().isBlank()) { + return item.getSource() + ":" + item.getProjectId(); + } + if (!item.getExternalId().isBlank()) { + return item.getSource() + ":" + item.getExternalId(); + } + return firstText(item.getModId(), item.getTitle()); + } + + private String filename(WorldModList list) { + String base = firstText(list.getWorldName(), list.getTitle(), "world-mod-list") + .replaceAll("[^A-Za-z0-9._-]+", "-") + .replaceAll("-+", "-") + .replaceAll("(^-|-$)", ""); + return (base.isBlank() ? "world-mod-list" : base) + "-mods.zip"; + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } + + private static String firstText(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + public record Download(String filename, byte[] bytes) { + } +} diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index ed5891a5..eb028634 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -82,7 +82,7 @@ app.r2.bucket=${R2_BUCKET_NAME} app.r2.access-key=${R2_ACCESS_KEY} app.r2.secret-key=${R2_SECRET_KEY} app.r2.endpoint=${R2_ENDPOINT} -app.r2.public-domain=${R2_PUBLIC_DOMAIN} +app.r2.public-domain=${R2_PUBLIC_DOMAIN:} spring.servlet.multipart.max-file-size=100MB spring.servlet.multipart.max-request-size=101MB @@ -119,10 +119,14 @@ app.warden.request-timeout-seconds=${WARDEN_REQUEST_TIMEOUT_SECONDS:75} app.security.pre-auth-secret=${PRE_AUTH_SECRET:c6677126-3ae0-4318-807e-b1af48b9f36c} app.security.pre-auth-expiry-seconds=600 -app.seeding.enabled=${APP_SEEDING_ENABLED:${SEEDING_ENABLED:false}} +app.seeding.enabled=${APP_SEEDING_ENABLED:false} app.seeding.mode=${APP_SEEDING_MODE:${SEEDING_MODE:clone}} app.seeding.reset=${APP_SEEDING_RESET:${SEEDING_RESET:false}} app.seeding.source-db=${APP_SEEDING_SOURCE_DB:${SEEDING_SOURCE_DB:modtale}} +app.seeding.source-r2-bucket=${APP_SEEDING_SOURCE_R2_BUCKET_NAME:${SEEDING_SOURCE_R2_BUCKET_NAME:}} +app.seeding.source-r2-access-key=${APP_SEEDING_SOURCE_R2_ACCESS_KEY:${SEEDING_SOURCE_R2_ACCESS_KEY:${R2_ACCESS_KEY:}}} +app.seeding.source-r2-secret-key=${APP_SEEDING_SOURCE_R2_SECRET_KEY:${SEEDING_SOURCE_R2_SECRET_KEY:${R2_SECRET_KEY:}}} +app.seeding.source-r2-endpoint=${APP_SEEDING_SOURCE_R2_ENDPOINT:${SEEDING_SOURCE_R2_ENDPOINT:${R2_ENDPOINT:}}} app.limits.max-api-keys-per-user=10 app.limits.max-orgs-per-user=5 diff --git a/backend/src/test/java/net/modtale/config/security/SecurityConfigLauncherOAuthTest.java b/backend/src/test/java/net/modtale/config/security/SecurityConfigLauncherOAuthTest.java new file mode 100644 index 00000000..ca884636 --- /dev/null +++ b/backend/src/test/java/net/modtale/config/security/SecurityConfigLauncherOAuthTest.java @@ -0,0 +1,124 @@ +package net.modtale.config.security; + +import java.util.Map; +import java.util.Set; +import net.modtale.config.auth.ApiKeyAuthFilter; +import net.modtale.config.properties.AppFrontendProperties; +import net.modtale.model.user.User; +import net.modtale.service.auth.AuthenticationService; +import net.modtale.service.auth.LauncherAuthService; +import net.modtale.service.auth.LocalUserDetailsService; +import net.modtale.service.auth.OAuth2LoginService; +import net.modtale.service.auth.OidcLoginService; +import net.modtale.service.user.account.AccountService; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.core.user.DefaultOAuth2User; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class SecurityConfigLauncherOAuthTest { + + @Test + void oauthSuccessRedirectsLauncherOAuthToLoopbackCallbackWithCode() throws Exception { + AccountService accountService = mock(AccountService.class); + LauncherAuthService launcherAuthService = mock(LauncherAuthService.class); + SecurityConfig config = config(accountService, launcherAuthService); + + User user = new User(); + user.setId("user-1"); + user.setUsername("ada"); + user.setRoles(java.util.List.of("USER")); + when(accountService.getPublicProfile("ada")).thenReturn(user); + when(launcherAuthService.issueCode(user, "http://127.0.0.1:49152/callback", "state-123")) + .thenReturn(new LauncherAuthService.LauncherAuthGrant( + "launcher-code", + "http://127.0.0.1:49152/callback", + "state-123", + 300 + )); + + MockHttpServletRequest request = launcherOAuthRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + OAuth2AuthenticationToken authentication = authentication(); + SecurityContextHolder.getContext().setAuthentication(authentication); + + config.oauthSuccessHandler().onAuthenticationSuccess(request, response, authentication); + + assertEquals( + "http://127.0.0.1:49152/callback?code=launcher-code&state=state-123", + response.getRedirectedUrl() + ); + SecurityContextHolder.clearContext(); + } + + @Test + void oauthFailureRedirectsLauncherOAuthToLoopbackCallbackWithError() throws Exception { + SecurityConfig config = config(mock(AccountService.class), mock(LauncherAuthService.class)); + MockHttpServletRequest request = launcherOAuthRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + config.oauthFailureHandler().onAuthenticationFailure( + request, + response, + new OAuth2AuthenticationException(new OAuth2Error("provider_error"), "Provider failed") + ); + + assertEquals( + "http://127.0.0.1:49152/callback?error=Provider+failed&state=state-123", + response.getRedirectedUrl() + ); + } + + private static SecurityConfig config(AccountService accountService, LauncherAuthService launcherAuthService) { + return new SecurityConfig( + mock(ApiKeyAuthFilter.class), + mock(RateLimitFilter.class), + mock(OAuth2LoginService.class), + mock(OidcLoginService.class), + mock(OAuth2AuthorizedClientRepository.class), + mock(LocalUserDetailsService.class), + mock(PasswordEncoder.class), + accountService, + mock(AuthenticationService.class), + launcherAuthService, + new AppFrontendProperties("http://localhost:5173") + ); + } + + private static MockHttpServletRequest launcherOAuthRequest() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.getSession().setAttribute( + LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE, + "http://127.0.0.1:49152/callback" + ); + request.getSession().setAttribute( + LauncherAuthService.OAUTH_STATE_SESSION_ATTRIBUTE, + "state-123" + ); + return request; + } + + private static OAuth2AuthenticationToken authentication() { + DefaultOAuth2User principal = new DefaultOAuth2User( + Set.of(new SimpleGrantedAuthority("ROLE_USER")), + Map.of("id", "user-1", "login", "ada"), + "login" + ); + return new OAuth2AuthenticationToken( + principal, + principal.getAuthorities(), + "github" + ); + } +} diff --git a/backend/src/test/java/net/modtale/controller/auth/AuthControllerTest.java b/backend/src/test/java/net/modtale/controller/auth/AuthControllerTest.java index e1de46f8..d373545b 100644 --- a/backend/src/test/java/net/modtale/controller/auth/AuthControllerTest.java +++ b/backend/src/test/java/net/modtale/controller/auth/AuthControllerTest.java @@ -2,19 +2,26 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import net.modtale.model.dto.request.auth.LauncherAuthExchangeRequest; +import net.modtale.model.dto.request.auth.LauncherAuthIssueRequest; import net.modtale.model.dto.request.auth.SignInRequest; import net.modtale.model.user.User; import net.modtale.service.auth.AuthenticationMutationService; import net.modtale.service.auth.AuthenticationService; +import net.modtale.service.auth.LauncherAuthService; import net.modtale.service.auth.TwoFactorService; import net.modtale.service.user.account.AccountService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.core.context.SecurityContext; import org.springframework.security.web.context.SecurityContextRepository; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -26,6 +33,7 @@ class AuthControllerTest { private AuthenticationMutationService authenticationMutationService; private AccountService accountService; private TwoFactorService twoFactorService; + private LauncherAuthService launcherAuthService; private SecurityContextRepository securityContextRepository; @BeforeEach @@ -34,12 +42,14 @@ void setUp() { authenticationMutationService = mock(AuthenticationMutationService.class); accountService = mock(AccountService.class); twoFactorService = mock(TwoFactorService.class); + launcherAuthService = mock(LauncherAuthService.class); securityContextRepository = mock(SecurityContextRepository.class); controller = new AuthController( authenticationService, authenticationMutationService, accountService, twoFactorService, + launcherAuthService, securityContextRepository ); } @@ -74,4 +84,78 @@ void logoutClearsTheSecurityContextAndExpiresSessionCookies() { assertEquals(200, result.getStatusCode().value()); verify(securityContextRepository).saveContext(org.springframework.security.core.context.SecurityContextHolder.createEmptyContext(), request, response); } + + @Test + void issueLauncherAuthCodeReturnsGrantForCurrentUser() { + User user = new User(); + user.setId("user-1"); + + LauncherAuthIssueRequest requestPayload = new LauncherAuthIssueRequest(); + requestPayload.setRedirectUri("http://127.0.0.1:49152/callback"); + requestPayload.setState("state-123"); + + when(accountService.requireCurrentUser(null, "authorizing the Modtale Launcher")).thenReturn(user); + when(launcherAuthService.issueCode(user, "http://127.0.0.1:49152/callback", "state-123")) + .thenReturn(new LauncherAuthService.LauncherAuthGrant( + "launcher-code", + "http://127.0.0.1:49152/callback", + "state-123", + 300 + )); + + var response = controller.issueLauncherAuthCode(requestPayload, null); + + assertEquals(200, response.getStatusCode().value()); + assertEquals("launcher-code", response.getBody().code()); + assertEquals("state-123", response.getBody().state()); + assertEquals(300, response.getBody().expiresIn()); + } + + @Test + void beginLauncherOAuthStoresCallbackAndRedirectsToProviderAuthorization() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + controller.beginLauncherOAuthLogin( + "github", + "http://127.0.0.1:49152/callback", + "state-123", + request, + response + ); + + assertEquals("/oauth2/authorization/github", response.getRedirectedUrl()); + assertEquals( + "http://127.0.0.1:49152/callback", + request.getSession().getAttribute(LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE) + ); + assertEquals( + "state-123", + request.getSession().getAttribute(LauncherAuthService.OAUTH_STATE_SESSION_ATTRIBUTE) + ); + verify(launcherAuthService).validateLoopbackRedirectUri("http://127.0.0.1:49152/callback"); + } + + @Test + void exchangeLauncherAuthCodeCreatesSessionForLauncherClient() { + User user = new User(); + user.setId("user-1"); + user.setRoles(java.util.List.of("USER")); + + LauncherAuthExchangeRequest requestPayload = new LauncherAuthExchangeRequest(); + requestPayload.setCode("launcher-code"); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + when(launcherAuthService.consumeCode("launcher-code")).thenReturn(user); + + var result = controller.exchangeLauncherAuthCode(requestPayload, request, response); + + assertEquals(200, result.getStatusCode().value()); + assertNotNull(request.getSession(false)); + verify(securityContextRepository).saveContext(any(SecurityContext.class), eq(request), eq(response)); + org.springframework.security.core.context.SecurityContextHolder.clearContext(); + } + } diff --git a/backend/src/test/java/net/modtale/controller/user/UserControllerTest.java b/backend/src/test/java/net/modtale/controller/user/UserControllerTest.java index 7795c525..bfb0e8a8 100644 --- a/backend/src/test/java/net/modtale/controller/user/UserControllerTest.java +++ b/backend/src/test/java/net/modtale/controller/user/UserControllerTest.java @@ -2,6 +2,7 @@ import net.modtale.model.dto.request.user.UpdateProfileRequest; import net.modtale.model.dto.response.common.ResourceUrlResponse; +import net.modtale.model.user.LauncherSettingsSnapshot; import net.modtale.model.user.User; import net.modtale.repository.user.UserRepository; import net.modtale.service.media.MediaUploadService; @@ -117,6 +118,28 @@ void followUserDelegatesUsingTheAuthenticatedUserId() { verify(socialService).followUser("user-1", "user-2"); } + @Test + void launcherSettingsEndpointsUseCurrentUser() { + User currentUser = user("user-1", "ada"); + LauncherSettingsSnapshot snapshot = new LauncherSettingsSnapshot(); + when(accountService.requireCurrentUser(null, "loading launcher settings")).thenReturn(currentUser); + when(accountService.requireCurrentUser(null, "syncing launcher settings")).thenReturn(currentUser); + when(accountService.getLauncherSettings("user-1")).thenReturn(snapshot); + when(accountService.updateLauncherSettings("user-1", snapshot)).thenReturn(snapshot); + when(accountService.updateLauncherSettingsPreferences("user-1", snapshot)).thenReturn(snapshot); + + var getResponse = controller.getLauncherSettings(null); + var putResponse = controller.updateLauncherSettings(snapshot, null); + var prefsResponse = controller.updateLauncherSettingsPreferences(snapshot, null); + + assertEquals(200, getResponse.getStatusCode().value()); + assertSame(snapshot, getResponse.getBody()); + assertEquals(200, putResponse.getStatusCode().value()); + assertSame(snapshot, putResponse.getBody()); + assertEquals(200, prefsResponse.getStatusCode().value()); + assertSame(snapshot, prefsResponse.getBody()); + } + private static User user(String id, String username) { User user = new User(); user.setId(id); diff --git a/backend/src/test/java/net/modtale/service/auth/LauncherAuthServiceTest.java b/backend/src/test/java/net/modtale/service/auth/LauncherAuthServiceTest.java new file mode 100644 index 00000000..23fd8094 --- /dev/null +++ b/backend/src/test/java/net/modtale/service/auth/LauncherAuthServiceTest.java @@ -0,0 +1,61 @@ +package net.modtale.service.auth; + +import java.util.Optional; +import net.modtale.exception.InvalidAuthenticationRequestException; +import net.modtale.model.user.User; +import net.modtale.repository.user.UserRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class LauncherAuthServiceTest { + + private UserRepository userRepository; + private LauncherAuthService service; + + @BeforeEach + void setUp() { + userRepository = mock(UserRepository.class); + service = new LauncherAuthService(userRepository); + } + + @Test + void issueCodeAllowsOnlyLoopbackRedirectsAndConsumesOnce() { + User user = new User(); + user.setId("user-1"); + + when(userRepository.findById("user-1")).thenReturn(Optional.of(user)); + + LauncherAuthService.LauncherAuthGrant grant = service.issueCode( + user, + "http://127.0.0.1:49152/callback", + "state-123" + ); + + assertNotNull(grant.code()); + assertEquals("http://127.0.0.1:49152/callback", grant.redirectUri()); + assertEquals("state-123", grant.state()); + assertTrue(grant.expiresIn() > 0); + assertEquals(1, service.getActiveCodeCount()); + assertEquals(user, service.consumeCode(grant.code())); + assertNull(service.consumeCode(grant.code())); + } + + @Test + void issueCodeRejectsExternalRedirects() { + User user = new User(); + user.setId("user-1"); + + assertThrows( + InvalidAuthenticationRequestException.class, + () -> service.issueCode(user, "https://evil.example/callback", "state") + ); + } +} diff --git a/backend/src/test/java/net/modtale/service/auth/OAuth2LoginServiceTest.java b/backend/src/test/java/net/modtale/service/auth/OAuth2LoginServiceTest.java index ba344550..7cdb6bfa 100644 --- a/backend/src/test/java/net/modtale/service/auth/OAuth2LoginServiceTest.java +++ b/backend/src/test/java/net/modtale/service/auth/OAuth2LoginServiceTest.java @@ -9,6 +9,7 @@ import net.modtale.service.user.account.AccountService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.client.registration.ClientRegistration; @@ -79,6 +80,54 @@ void loadUserFallsBackToLoginFlowForAnonymousRequests() { verify(authenticationService, never()).linkAccount(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString()); } + @Test + void loadUserRejectsGitlabAsSignInProvider() { + AccountService accountService = mock(AccountService.class); + AuthenticationService authenticationService = mock(AuthenticationService.class); + ObjectProvider requestProvider = mock(ObjectProvider.class); + + DefaultOAuth2User upstreamUser = oauthUser("oauth-1", "ada-gitlab"); + TestOAuth2LoginService service = new TestOAuth2LoginService(accountService, authenticationService, requestProvider, upstreamUser); + + OAuth2AuthenticationException error = assertThrows( + OAuth2AuthenticationException.class, + () -> service.loadUser(oauthRequest("gitlab")) + ); + + assertEquals("login_failure", error.getError().getErrorCode()); + verify(authenticationService, never()).processUserLogin(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString()); + } + + @Test + void loadUserUsesLoginFlowForLauncherOAuthEvenWithExistingBrowserSession() { + AccountService accountService = mock(AccountService.class); + AuthenticationService authenticationService = mock(AuthenticationService.class); + ObjectProvider requestProvider = mock(ObjectProvider.class); + MockHttpServletRequest request = new MockHttpServletRequest(); + Authentication authentication = mock(Authentication.class); + request.setUserPrincipal(authentication); + request.getSession().setAttribute( + LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE, + "http://127.0.0.1:49152/callback" + ); + + when(requestProvider.getIfAvailable()).thenReturn(request); + when(authentication.isAuthenticated()).thenReturn(true); + when(authentication.getName()).thenReturn("ada"); + + DefaultOAuth2User upstreamUser = oauthUser("oauth-1", "ada-gh"); + DefaultOAuth2User signedInUser = oauthUser("user-1", "Ada"); + + TestOAuth2LoginService service = new TestOAuth2LoginService(accountService, authenticationService, requestProvider, upstreamUser); + when(authenticationService.processUserLogin("github", upstreamUser, "access-token")).thenReturn(signedInUser); + + OAuth2User result = service.loadUser(oauthRequest("github")); + + assertSame(signedInUser, result); + verify(authenticationService).processUserLogin("github", upstreamUser, "access-token"); + verify(authenticationService, never()).linkAccount(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString()); + } + @Test void loadUserMapsAccountCollisionsToTheExpectedOAuthErrorCode() { AccountService accountService = mock(AccountService.class); diff --git a/backend/src/test/java/net/modtale/service/auth/OidcLoginServiceTest.java b/backend/src/test/java/net/modtale/service/auth/OidcLoginServiceTest.java index 91e303d5..505fd556 100644 --- a/backend/src/test/java/net/modtale/service/auth/OidcLoginServiceTest.java +++ b/backend/src/test/java/net/modtale/service/auth/OidcLoginServiceTest.java @@ -83,6 +83,37 @@ void loadUserFallsBackToLoginFlowWhenNoAuthenticatedUserExists() { verify(authenticationService, never()).linkAccount(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString()); } + @Test + void loadUserUsesLoginFlowForLauncherOAuthEvenWithExistingBrowserSession() { + AccountService accountService = mock(AccountService.class); + AuthenticationService authenticationService = mock(AuthenticationService.class); + ObjectProvider requestProvider = mock(ObjectProvider.class); + MockHttpServletRequest request = new MockHttpServletRequest(); + Authentication authentication = mock(Authentication.class); + request.setUserPrincipal(authentication); + request.getSession().setAttribute( + LauncherAuthService.OAUTH_REDIRECT_URI_SESSION_ATTRIBUTE, + "http://127.0.0.1:49152/callback" + ); + + when(requestProvider.getIfAvailable()).thenReturn(request); + when(authentication.isAuthenticated()).thenReturn(true); + when(authentication.getName()).thenReturn("ada"); + + OidcUser upstreamUser = oidcUser(); + DefaultOAuth2User appUser = oauthUser("user-1", "Ada"); + + TestOidcLoginService service = new TestOidcLoginService(accountService, authenticationService, requestProvider, upstreamUser); + when(authenticationService.processUserLogin("google", upstreamUser, "access-token")).thenReturn(appUser); + + OidcUser result = service.loadUser(oidcRequest("google")); + + assertInstanceOf(OidcLoginService.CustomOidcUser.class, result); + assertEquals("Ada", result.getAttribute("login")); + verify(authenticationService).processUserLogin("google", upstreamUser, "access-token"); + verify(authenticationService, never()).linkAccount(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.anyString()); + } + @Test void loadUserMapsOidcAccountCollisionsToTheExpectedOAuthErrorCode() { AccountService accountService = mock(AccountService.class); diff --git a/backend/src/test/java/net/modtale/service/project/version/VersionDownloadOrchestrationServiceTest.java b/backend/src/test/java/net/modtale/service/project/version/VersionDownloadOrchestrationServiceTest.java index d9407e6e..d380cf0f 100644 --- a/backend/src/test/java/net/modtale/service/project/version/VersionDownloadOrchestrationServiceTest.java +++ b/backend/src/test/java/net/modtale/service/project/version/VersionDownloadOrchestrationServiceTest.java @@ -5,6 +5,7 @@ import net.modtale.config.properties.AppFrontendProperties; import net.modtale.exception.InvalidDownloadTokenException; import net.modtale.exception.ResourceNotFoundException; +import net.modtale.exception.UnauthorizedException; import net.modtale.model.dto.response.project.BundleDownloadUrlResponse; import net.modtale.model.dto.response.project.DownloadUrlResponse; import net.modtale.model.project.Project; @@ -69,14 +70,15 @@ void setUp() { @Test void createDownloadUrlAndBundleUrlGenerateShortLivedTokenRoutes() { User user = new User(); + user.setId("user-1"); Project project = project("project-1", "Sky Tools", ProjectClassification.PLUGIN); ProjectVersion version = version("version-1", "1.0.0", "files/mod.jar"); when(projectService.getProjectById("project-1", user)).thenReturn(project); when(projectVersionAccessService.requireByVersionNumber(org.mockito.Mockito.eq(project), org.mockito.Mockito.eq("1.0.0"), org.mockito.Mockito.eq("1.21.0"), org.mockito.Mockito.any())) .thenReturn(version); - when(downloadTokenService.generateToken("project-1", "1.0.0", "1.21.0")).thenReturn("download-token"); - when(downloadTokenService.generateToken("project-1", "1.0.0", "1.21.0", List.of("dep-1"))).thenReturn("bundle-token"); + when(downloadTokenService.generateToken("project-1", "1.0.0", "1.21.0", null, "user-1")).thenReturn("download-token"); + when(downloadTokenService.generateToken("project-1", "1.0.0", "1.21.0", List.of("dep-1"), "user-1")).thenReturn("bundle-token"); when(downloadTokenService.getTokenValiditySeconds()).thenReturn(300); DownloadUrlResponse download = service.createDownloadUrl("project-1", "1.0.0", "1.21.0", user); @@ -197,6 +199,25 @@ void downloadRejectsInvalidTokensOrUnreadableProjects() { assertThrows(ResourceNotFoundException.class, () -> service.downloadVersion("unreadable", false, null, null, null, user)); } + @Test + void downloadRejectsUserBoundTokenWithoutMatchingSession() { + User user = new User(); + user.setId("other-user"); + + when(downloadTokenService.validateAndConsume("token")).thenReturn( + new DownloadTokenService.DownloadToken( + "project-1", + "1.0.0", + null, + null, + "user-1", + Instant.now().plusSeconds(60) + ) + ); + + assertThrows(UnauthorizedException.class, () -> service.downloadVersion("token", false, null, null, null, user)); + } + private static DownloadTokenService.DownloadToken token( String projectId, String version, diff --git a/backend/src/test/java/net/modtale/service/storage/DownloadTokenServiceTest.java b/backend/src/test/java/net/modtale/service/storage/DownloadTokenServiceTest.java index 3a67a8de..5cdb930a 100644 --- a/backend/src/test/java/net/modtale/service/storage/DownloadTokenServiceTest.java +++ b/backend/src/test/java/net/modtale/service/storage/DownloadTokenServiceTest.java @@ -24,7 +24,7 @@ private Map getTokens() { @Test void generateTokenStoresPayloadAndConsumesItOnce() { - String token = downloadTokenService.generateToken("project-1", "1.2.3", "1.0.0", List.of("dep-a", "dep-b")); + String token = downloadTokenService.generateToken("project-1", "1.2.3", "1.0.0", List.of("dep-a", "dep-b"), "user-1"); assertNotNull(token); assertTrue(downloadTokenService.getActiveTokenCount() >= 1); @@ -35,6 +35,7 @@ void generateTokenStoresPayloadAndConsumesItOnce() { assertEquals("project-1", result.getProjectId()); assertEquals("1.2.3", result.getVersion()); assertEquals("1.0.0", result.getGameVersion()); + assertEquals("user-1", result.getUserId()); assertEquals(List.of("dep-a", "dep-b"), result.getSelectedDependencies()); assertTrue(result.isUsed()); assertNull(downloadTokenService.validateAndConsume(token)); diff --git a/backend/src/test/java/net/modtale/service/user/account/AccountServiceTest.java b/backend/src/test/java/net/modtale/service/user/account/AccountServiceTest.java index 00f13e0a..fff9772d 100644 --- a/backend/src/test/java/net/modtale/service/user/account/AccountServiceTest.java +++ b/backend/src/test/java/net/modtale/service/user/account/AccountServiceTest.java @@ -1,6 +1,7 @@ package net.modtale.service.user.account; import java.util.Optional; +import net.modtale.model.user.LauncherSettingsSnapshot; import net.modtale.model.user.User; import net.modtale.repository.user.UserRepository; import net.modtale.service.security.validation.SanitizationService; @@ -9,7 +10,11 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -65,6 +70,93 @@ void getPublicProfileReturnsNullForBlankIdentifiers() { assertNull(accountService.getPublicProfile(" ")); } + @Test + void launcherSettingsAreNormalizedBeforeSaving() { + User user = user("user-1", "ada"); + when(userRepository.findById("user-1")).thenReturn(Optional.of(user)); + when(userRepository.save(any(User.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + LauncherSettingsSnapshot snapshot = new LauncherSettingsSnapshot(); + snapshot.setSettingsHash(" hash "); + LauncherSettingsSnapshot.Preferences preferences = new LauncherSettingsSnapshot.Preferences(); + preferences.setGameVersion(" 1.0 "); + snapshot.setPreferences(preferences); + LauncherSettingsSnapshot.InstalledProject installed = new LauncherSettingsSnapshot.InstalledProject(); + installed.setProjectId(" project-1 "); + installed.setSlug(" slug-one "); + installed.setTitle(" Project One "); + installed.setClassification(" MODPACK "); + installed.setInstalledVersion(" 2.0 "); + installed.setSource(""); + installed.setInstallType(""); + installed.setModpackUnlocked(true); + installed.setDependencyProjectIds(java.util.List.of("dep-1", "dep-1", " ")); + LauncherSettingsSnapshot.InstalledProjectReference bundled = + new LauncherSettingsSnapshot.InstalledProjectReference(); + bundled.setProjectId(" bundled-1 "); + bundled.setSlug(" bundled-slug "); + bundled.setVersionNumber(" 1.5 "); + bundled.setSource(" MODTALE "); + bundled.setExternalId(" external-one "); + installed.setBundledProjects(java.util.List.of(bundled)); + snapshot.setInstalledProjects(java.util.List.of(installed)); + + LauncherSettingsSnapshot saved = accountService.updateLauncherSettings("user-1", snapshot); + + assertEquals("hash", saved.getSettingsHash()); + assertEquals("1.0", saved.getPreferences().getGameVersion()); + assertEquals(1, saved.getInstalledProjects().size()); + assertEquals("project-1", saved.getInstalledProjects().getFirst().getProjectId()); + assertEquals("slug-one", saved.getInstalledProjects().getFirst().getSlug()); + assertEquals("Project One", saved.getInstalledProjects().getFirst().getTitle()); + assertEquals("MODPACK", saved.getInstalledProjects().getFirst().getClassification()); + assertEquals("MODTALE", saved.getInstalledProjects().getFirst().getSource()); + assertEquals("DIRECT", saved.getInstalledProjects().getFirst().getInstallType()); + assertTrue(saved.getInstalledProjects().getFirst().isModpackUnlocked()); + assertEquals(java.util.List.of("dep-1"), saved.getInstalledProjects().getFirst().getDependencyProjectIds()); + assertEquals("bundled-1", + saved.getInstalledProjects().getFirst().getBundledProjects().getFirst().getProjectId()); + assertEquals("bundled-slug", + saved.getInstalledProjects().getFirst().getBundledProjects().getFirst().getSlug()); + assertEquals("1.5", + saved.getInstalledProjects().getFirst().getBundledProjects().getFirst().getVersionNumber()); + assertEquals("MODTALE", + saved.getInstalledProjects().getFirst().getBundledProjects().getFirst().getSource()); + assertEquals("external-one", + saved.getInstalledProjects().getFirst().getBundledProjects().getFirst().getExternalId()); + assertNotNull(saved.getUpdatedAt()); + verify(userRepository).save(argThat(savedUser -> savedUser.getLauncherSettings() == saved)); + } + + @Test + void launcherPreferenceUpdatePreservesStoredInstalledProjects() { + User user = user("user-1", "ada"); + LauncherSettingsSnapshot stored = new LauncherSettingsSnapshot(); + LauncherSettingsSnapshot.InstalledProject installed = new LauncherSettingsSnapshot.InstalledProject(); + installed.setProjectId("project-1"); + installed.setInstalledVersion("2.0"); + stored.setInstalledProjects(java.util.List.of(installed)); + user.setLauncherSettings(stored); + when(userRepository.findById("user-1")).thenReturn(Optional.of(user)); + when(userRepository.save(any(User.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + LauncherSettingsSnapshot update = new LauncherSettingsSnapshot(); + update.setSettingsHash(" full-local-hash "); + LauncherSettingsSnapshot.Preferences preferences = new LauncherSettingsSnapshot.Preferences(); + preferences.setGameVersion(" 2.1 "); + update.setPreferences(preferences); + + LauncherSettingsSnapshot saved = accountService.updateLauncherSettingsPreferences("user-1", update); + + assertEquals("full-local-hash", saved.getSettingsHash()); + assertEquals("2.1", saved.getPreferences().getGameVersion()); + assertEquals(1, saved.getInstalledProjects().size()); + assertEquals("project-1", saved.getInstalledProjects().getFirst().getProjectId()); + assertEquals("2.0", saved.getInstalledProjects().getFirst().getInstalledVersion()); + assertNotNull(saved.getUpdatedAt()); + verify(userRepository).save(argThat(savedUser -> savedUser.getLauncherSettings() == saved)); + } + private static User user(String id, String username) { User user = new User(); user.setId(id); diff --git a/backend/src/test/java/net/modtale/service/worldlist/WorldModListArchiveServiceTest.java b/backend/src/test/java/net/modtale/service/worldlist/WorldModListArchiveServiceTest.java new file mode 100644 index 00000000..41751248 --- /dev/null +++ b/backend/src/test/java/net/modtale/service/worldlist/WorldModListArchiveServiceTest.java @@ -0,0 +1,77 @@ +package net.modtale.service.worldlist; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import net.modtale.model.project.ProjectClassification; +import net.modtale.model.project.ProjectDependency; +import net.modtale.model.worldlist.WorldModList; +import net.modtale.service.storage.StorageService; +import org.junit.jupiter.api.Test; +import tools.jackson.databind.ObjectMapper; + +class WorldModListArchiveServiceTest { + + @Test + void generateZipIncludesManifestReadmeAndDownloadableFilesOnly() throws IOException { + StorageService storageService = mock(StorageService.class); + when(storageService.download("storage/cool.jar")).thenReturn("cool-bytes".getBytes(StandardCharsets.UTF_8)); + + WorldModList list = new WorldModList(); + list.setId("list-1"); + list.setTitle("Shared list"); + list.setWorldName("Cozy World"); + list.setGameVersion("0.5.0"); + list.setCreatedAt(Instant.parse("2026-06-20T12:00:00Z")); + list.setLastViewedAt(Instant.parse("2026-06-20T12:30:00Z")); + list.setExpiresAt(Instant.parse("2026-07-20T12:00:00Z")); + list.setMods(List.of( + item("Cool Mod", "1.0.0", true, "storage/cool.jar"), + item("External Mod", "0.2.0", false, "") + )); + + byte[] archive = new WorldModListArchiveService(storageService, new ObjectMapper()).generateZip(list); + Map entries = entries(archive); + + assertTrue(entries.containsKey("modtale-list.json")); + assertTrue(entries.get("modtale-list.json").contains("\"createdAt\" : \"2026-06-20T12:00:00Z\"")); + assertTrue(entries.get("README.txt").contains("Cozy World")); + assertEquals("cool-bytes", entries.get("Cool-Mod-1.0.0.jar")); + assertFalse(entries.containsKey("External-Mod-0.2.0.jar")); + } + + private static WorldModList.Item item(String title, String version, boolean downloadable, String fileUrl) { + WorldModList.Item item = new WorldModList.Item(); + item.setId(title); + item.setTitle(title); + item.setVersionNumber(version); + item.setClassification(ProjectClassification.PLUGIN); + item.setSource(ProjectDependency.Source.MODTALE); + item.setDownloadable(downloadable); + item.setFileUrl(fileUrl); + return item; + } + + private static Map entries(byte[] archive) throws IOException { + Map entries = new HashMap<>(); + try (ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(archive))) { + ZipEntry entry; + while ((entry = zip.getNextEntry()) != null) { + entries.put(entry.getName(), new String(zip.readAllBytes(), StandardCharsets.UTF_8)); + } + } + return entries; + } +} diff --git a/backend/src/test/java/net/modtale/service/worldlist/WorldModListServiceTest.java b/backend/src/test/java/net/modtale/service/worldlist/WorldModListServiceTest.java new file mode 100644 index 00000000..56086cb6 --- /dev/null +++ b/backend/src/test/java/net/modtale/service/worldlist/WorldModListServiceTest.java @@ -0,0 +1,301 @@ +package net.modtale.service.worldlist; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import net.modtale.config.properties.AppFrontendProperties; +import net.modtale.model.dto.request.worldlist.CreateWorldModListRequest; +import net.modtale.model.dto.worldlist.WorldModListDTO; +import net.modtale.model.project.Project; +import net.modtale.model.project.ProjectClassification; +import net.modtale.model.project.ProjectDependency; +import net.modtale.model.project.ProjectVersion; +import net.modtale.model.user.User; +import net.modtale.model.worldlist.WorldModList; +import net.modtale.repository.worldlist.WorldModListRepository; +import net.modtale.service.project.access.ProjectVersionAccessService; +import net.modtale.service.project.query.ProjectService; +import net.modtale.service.security.access.AccessControlService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +class WorldModListServiceTest { + + private WorldModListRepository repository; + private ProjectService projectService; + private ProjectVersionAccessService versionAccessService; + private AccessControlService accessControlService; + private WorldModListArchiveService archiveService; + private WorldModListService service; + + @BeforeEach + void setUp() { + repository = mock(WorldModListRepository.class); + projectService = mock(ProjectService.class); + versionAccessService = mock(ProjectVersionAccessService.class); + accessControlService = mock(AccessControlService.class); + archiveService = mock(WorldModListArchiveService.class); + service = new WorldModListService( + repository, + projectService, + versionAccessService, + accessControlService, + archiveService, + new WorldModListMapper(new AppFrontendProperties("https://modtale.test/")) + ); + when(repository.save(any(WorldModList.class))).thenAnswer(invocation -> invocation.getArgument(0)); + } + + @Test + void createEnrichesModtaleItemsDedupesAndLeavesExternalItemsListedOnly() { + User owner = owner(); + Project project = project(); + ProjectVersion version = version("1.2.3", "storage/mod.jar"); + project.setVersions(List.of(version)); + + when(projectService.getRawProjectById("project-1")).thenReturn(project); + when(accessControlService.isPubliclyReadable(project)).thenReturn(true); + when(accessControlService.canReadProject(project, owner)).thenReturn(true); + when(versionAccessService.findByVersionNumber(project, "1.2.3", "0.5.0")).thenReturn(version); + + CreateWorldModListRequest request = new CreateWorldModListRequest( + "My world share", + "Cozy World", + "0.5.0", + List.of( + new CreateWorldModListRequest.Item( + "group:mod", + "project-1", + "", + "Local name", + "1.2.3", + ProjectClassification.PLUGIN, + ProjectDependency.Source.MODTALE, + "", + "", + "" + ), + new CreateWorldModListRequest.Item( + "group:mod", + "project-1", + "", + "Duplicate", + "1.2.3", + ProjectClassification.PLUGIN, + ProjectDependency.Source.MODTALE, + "", + "", + "" + ), + new CreateWorldModListRequest.Item( + "local:only", + "", + "", + "Local Only", + "0.1.0", + ProjectClassification.PLUGIN, + ProjectDependency.Source.OTHER, + "local:only", + "", + "" + ) + ) + ); + + WorldModListDTO dto = service.create(request, owner); + + UUID.fromString(dto.id()); + assertEquals("My world share", dto.title()); + assertEquals("https://modtale.test/lists/" + dto.id(), dto.shareUrl()); + assertEquals("/lists/" + dto.id() + "/download", dto.downloadUrl()); + assertTrue(dto.launcherInstallUrl().startsWith("modtale://install-list?listId=" + dto.id())); + assertEquals(2, dto.modCount()); + assertEquals(1, dto.downloadableCount()); + assertEquals("Catalog Mod", dto.mods().getFirst().title()); + assertEquals("catalog-mod", dto.mods().getFirst().slug()); + assertEquals("mayuna", dto.mods().getFirst().author()); + assertEquals("A tiny catalog mod.", dto.mods().getFirst().description()); + assertEquals(42, dto.mods().getFirst().downloadCount()); + assertEquals(ProjectDependency.Source.MODTALE, dto.mods().getFirst().source()); + assertEquals("0.1.0", dto.mods().get(1).versionNumber()); + assertEquals("Listed only; Modtale cannot package this external or local file.", dto.mods().get(1).unavailableReason()); + + ArgumentCaptor saved = ArgumentCaptor.forClass(WorldModList.class); + verify(repository).save(saved.capture()); + assertEquals(dto.id(), saved.getValue().getId()); + assertTrue(saved.getValue().getExpiresAt().isAfter(Instant.now().plusSeconds(29L * 24L * 60L * 60L))); + } + + @Test + void viewTouchesListAndExtendsExpiry() { + Instant oldExpiry = Instant.now().plusSeconds(3600); + WorldModList list = new WorldModList(); + list.setId("list-1"); + list.setTitle("Shared list"); + list.setWorldName("World"); + list.setCreatedAt(Instant.now().minusSeconds(3600)); + list.setLastViewedAt(Instant.now().minusSeconds(1800)); + list.setExpiresAt(oldExpiry); + list.setViewCount(2); + list.setMods(List.of(externalItem())); + + when(repository.findById("list-1")).thenReturn(Optional.of(list)); + + WorldModListDTO dto = service.view("list-1"); + + assertEquals(3, dto.viewCount()); + assertEquals(0, dto.downloadCount()); + assertTrue(dto.expiresAt().isAfter(oldExpiry)); + assertTrue(dto.lastViewedAt().isAfter(list.getCreatedAt())); + verify(repository).save(list); + } + + @Test + void viewHydratesStoredModtaleItemsWithCurrentProjectMetadata() { + Instant oldExpiry = Instant.now().plusSeconds(3600); + WorldModList.Item staleItem = new WorldModList.Item(); + staleItem.setId("item-1"); + staleItem.setProjectId("project-1"); + staleItem.setTitle("Old local title"); + staleItem.setSource(ProjectDependency.Source.OTHER); + staleItem.setDownloadable(true); + + WorldModList list = new WorldModList(); + list.setId("list-1"); + list.setTitle("Shared list"); + list.setWorldName("World"); + list.setCreatedAt(Instant.now().minusSeconds(3600)); + list.setExpiresAt(oldExpiry); + list.setMods(List.of(staleItem)); + + Project project = project(); + when(repository.findById("list-1")).thenReturn(Optional.of(list)); + when(projectService.getRawProjectById("project-1")).thenReturn(project); + when(accessControlService.isPubliclyReadable(project)).thenReturn(true); + + WorldModListDTO dto = service.view("list-1"); + + WorldModListDTO.Item item = dto.mods().getFirst(); + assertEquals("Catalog Mod", item.title()); + assertEquals("catalog-mod", item.slug()); + assertEquals("author-1", item.authorId()); + assertEquals("mayuna", item.author()); + assertEquals("A tiny catalog mod.", item.description()); + assertEquals("/banners/mod.png", item.bannerUrl()); + assertEquals(42, item.downloadCount()); + assertEquals(7, item.favoriteCount()); + assertEquals(ProjectDependency.Source.MODTALE, item.source()); + verify(repository).save(list); + } + + @Test + void viewHydratesStoredItemsBySlugLikeModIdWhenProjectIdIsMissing() { + WorldModList.Item staleItem = new WorldModList.Item(); + staleItem.setId("item-1"); + staleItem.setModId("AzureDoom:LevelingCore"); + staleItem.setTitle("LevelingCore"); + staleItem.setSource(ProjectDependency.Source.OTHER); + staleItem.setDownloadable(false); + + WorldModList list = new WorldModList(); + list.setId("list-1"); + list.setTitle("Shared list"); + list.setWorldName("World"); + list.setCreatedAt(Instant.now().minusSeconds(3600)); + list.setExpiresAt(Instant.now().plusSeconds(3600)); + list.setMods(List.of(staleItem)); + + Project project = project(); + project.setSlug("leveling-core"); + project.setTitle("LevelingCore"); + when(repository.findById("list-1")).thenReturn(Optional.of(list)); + when(projectService.getRawProjectByRouteKey("leveling-core")).thenReturn(project); + when(accessControlService.isPubliclyReadable(project)).thenReturn(true); + + WorldModListDTO dto = service.view("list-1"); + + WorldModListDTO.Item item = dto.mods().getFirst(); + assertEquals("project-1", item.projectId()); + assertEquals("leveling-core", item.slug()); + assertEquals("LevelingCore", item.title()); + assertEquals("mayuna", item.author()); + assertEquals(42, item.downloadCount()); + assertEquals(7, item.favoriteCount()); + assertEquals(ProjectDependency.Source.MODTALE, item.source()); + verify(repository).save(list); + } + + @Test + void downloadTouchesListAndBuildsArchive() throws IOException { + WorldModList list = new WorldModList(); + list.setId("list-1"); + list.setTitle("Shared list"); + list.setWorldName("A World"); + list.setExpiresAt(Instant.now().plusSeconds(3600)); + list.setMods(List.of(externalItem())); + + when(repository.findById("list-1")).thenReturn(Optional.of(list)); + when(archiveService.generateZip(list)).thenReturn(new byte[]{1, 2, 3}); + + WorldModListService.Download download = service.download("list-1"); + + assertEquals("A-World-mods.zip", download.filename()); + assertEquals(1, list.getViewCount()); + assertEquals(1, list.getDownloadCount()); + assertEquals(3, download.bytes().length); + } + + private static User owner() { + User user = new User(); + user.setId("user-1"); + user.setUsername("willow"); + return user; + } + + private static Project project() { + Project project = new Project(); + project.setId("project-1"); + project.setSlug("catalog-mod"); + project.setTitle("Catalog Mod"); + project.setAuthorId("author-1"); + project.setAuthor("mayuna"); + project.setDescription("A tiny catalog mod."); + project.setImageUrl("/icons/mod.png"); + project.setBannerUrl("/banners/mod.png"); + project.setClassification(ProjectClassification.PLUGIN); + project.setDownloadCount(42); + project.setFavoriteCount(7); + project.setUpdatedAt("2026-06-02T00:00:00Z"); + return project; + } + + private static ProjectVersion version(String versionNumber, String fileUrl) { + ProjectVersion version = new ProjectVersion(); + version.setId("version-1"); + version.setVersionNumber(versionNumber); + version.setGameVersions(List.of("0.5.0")); + version.setReviewStatus(ProjectVersion.ReviewStatus.APPROVED); + version.setReleaseDate("2026-06-01"); + version.setFileUrl(fileUrl); + return version; + } + + private static WorldModList.Item externalItem() { + WorldModList.Item item = new WorldModList.Item(); + item.setId("item-1"); + item.setTitle("Local Only"); + item.setSource(ProjectDependency.Source.OTHER); + item.setDownloadable(false); + return item; + } +} diff --git a/frontend/public/assets/launcher/patchly.png b/frontend/public/assets/launcher/patchly.png new file mode 100644 index 0000000000000000000000000000000000000000..86e262bc4bbc173f3fc00cee78e2d77a8590a75a GIT binary patch literal 107835 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%0Dl4HG7glH~l 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 z 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 literal 0 HcmV?d00001 diff --git a/frontend/public/assets/launcher/project.png b/frontend/public/assets/launcher/project.png new file mode 100644 index 0000000000000000000000000000000000000000..21754683ea287b2fa66f3a1016e11715d572c91c GIT binary patch literal 1185479 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

%2 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%0AoTR3sS1Og`gL5A;4_#7b<$ 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

HMFCCz0D_tVK0o|E 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%0AG`$|IN@)ZyxM@{YVnQ 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ʋ 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

_)fxvd%4z6M4^n}*jE*Bb^O`wSA(FMCc>PtiXh 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%0DCC{2GjmKI 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

  • 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

    nj6=yo{ee+wuow@n@Pl-wwC=7Cdm5<%J)|874 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 (Ju-QeZ}?) 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

    w-B}&^jhm=!{7j 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 literal 0 HcmV?d00001 diff --git a/frontend/public/assets/launcher/voile.png b/frontend/public/assets/launcher/voile.png new file mode 100644 index 0000000000000000000000000000000000000000..d08744abee06a4d8d94698599145d8dd2cad864c GIT binary patch literal 536318 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ž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

    efK6T1;7ei93C&JC|utTCmEn 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%0A;=53#C46Jr>k@ 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 z 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 S|I!ED)T$$kt%`ls)NjG(jYf6M+YxKebjX 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≦*3FPsowIHpZMTb`5wW28e*5Al?c`*jks+dv2Xqo zsbD2wRDfLAc!LiTcHy><8EB^S9^K^GdDnc=px01pX}^Z}FziPkAb)V};iyd>Zea6) zL?X~{NO^$Pd#$!v{lfWO7cKqnSx8}!#Q~Ft2X{F{hmA<2F$X3s!uH*(>KMPniwdht zX{T0^S5Dt< z$aI2`NUoKd0)S3hMBW$!^v9Wd10N~F8v}~~Z!-U$=Al5eVs_+OL8Tka#(NL=XIWq3m-QKgH!FZZa+5yLTDjVn>Pk-?9&gT?orwHQm1C+1W(jm zpxnf+`vB{mRYLZIxryxr@FaCkC0GCe$x-=;c5`SN6d$)P!~C=qEqEdX$+|D6p^ zOz1lu9OIXUNCIZ7yt55m?Mi&lYH)UN%4DJcZ1?&@bz>(0-mhF3 zrp&krZh?@j*IFRKw|1jaK~>IgAcaS!6=a8C<(!CRf|OE5!ruLJQe{x)&c^92u5+1zc$`<;jEB9y(GbH_%Avs zTcm4U^Vb#3so9GFQT@kCShbIN63-pFJ391I@Qp=c~JW1Vr?BjWRzeONj3^$Cn_kJ=j?f520 z!FNmg+BuGk+M%V^-r_u@W&-NrHn_J7bD&&^kyK}=P}eRf(F$39Xs6T|4(?GLGTl2l zB2KzTT;j=@nC-UW1abZ1R^OgArXC#(yT=D(Mmai8f=nVa(Q!#);L%C@pK-s0dc=6y z5IUP=9iuM3j|7oQN^pSRAxJ_sp$iw(4o=O2X=Y~I51zz*2x|9;pl7t+M6@F(J;&w+ zOsxY`yM3{)`0<9BqMDw`>{q&t=EYd$tH|`QU8sbsPBlh0XtRt~YL$n1d%*4rkfGgW zeBsZPZI++HZo&djW&zm8f}1xJQ?q=2aOJWr%*E`d)%@7VqnAy1hL6cTineB9pq2Zu zm%V^3POVshnAcV+h>WAFjjz{aj&l*;I9V^s*z9Iy=$@%n&Azk-I<2BhN!$^pN}H2% zU^Wez_%dG2pxLY6j*WfTd%c>=1;a)XUhKUrK`RqcDvYmMn{-_sVvxz7CVhM1*p#f>f;I&qcHJ!R!I)Og>mp@{@oq(Lf*_RAVZH)~M_E&jrhieo^g^m{E{f8YT|kDM!NO{#6drW;5G3p5)lbL|ZB`xyrP^m22}UwI zh@DejMuPhX(OreY6FP8{1w~JryFe1{&gmeTs6!UYrQo_Gm_V!q&pF7cZ2VDMR_hP{ z^`cU@ZV_c#1cq$3nai`K*;rV;xu$6wv*3TxBdR{%HM87i!gQ+fIy0q*sx4Stc?uGw zl|znr+!r)j<-4*7SA}`KMXV0D#&=U8fu^XbCI3!F;^oTE1}%FB%CWv{VL^e2idpB~ zgD?Kk&hL;$ar8$c#tcPx6xyty@n{TL7%SJp&}NxY@75}Mt0_KZCM^*Mj@K1{$D5YW zcz!kbAn@9Jab!dNMq$G9rJXUHMDLkX8bTK$nKZHC>GzjaYq=lz=;NeEJt6AalX4}L zmax*^3=kSQNdSiYx-`Qb93wa5RKzctelf4=A5_1bsVO1~Z`>KAWQ-c!?)Qt)q7-M0 ze9LRZHw%(FzCCDjET}0|O~Zm^m*nMe_fmzE*!L-#Co*BFraDjWC89CE#j2g`9e+^L zy6x(-woxlpDx7G1B_RG^+ezPhN;OFhY1_-J+l?|>9k1_qz@5x#wuhdT)*fho4mCQ- zx`}@IyV)@sOu@?&bc52At4Ud&B$7e?Ir>)55jgP7?ub#ZK6UPMz4w`uSxv~q1j5yo zJg0wV==C#UC3h}6TlT+bI^U>t(F8l~LkJf7YrfN;c=ZAu=q9I1iz3)@X;Z?PhU+Xw z8a$*idJS(@_Iq1s)p+q64N`!?4D#D}L=Oipbz`^{rp-p^Y^yrq;LyD!jndgMnba^~ z`wkHZg(7I&oA#8J3dgAq-{Vlj&9>l?B903Kg;frVL8tr#a^W`aId9C+Ao#Y=RoM8O z&^_00J?{-dmIGgTgq%rK0+1ek5NLK3I|gU7@>$(LM#x&T8-i~2E1av_@J?L|fTW&z z0zZau*J*%1!72=8ck#U{#pW0(=bwNLJY{g?)~!B=gHT|y>${kcB=D=w-{KFZm8?q$ zk@m=%GYkwmv{N5FYk>I2xUcXtrUROl&MBpO!7%Yql0LuymGJ0;2%F{%aF&$maM?0o zrqZPnmIKA-IoH~mNLm;Sq~C-ajL<-onPitU5dj?olE(cwF&`pYqxl`RqTbYFAn@45 zorGO&4b)$ZvY=YgqwaLWa8BRn_Wy@T^p4f@9rPcq+Zx=K$^vWVIyNusgdeb`R2|4V zxpjuDe_d`kfu9I(dGb6^@Fg}TYbKesB1!HF{L~a)EKYeh;A+8dYA{0ue4_2CrRphL z4lsmf16}DaO1r*=cdUd*GqLl9E8)oG8-EP`y(YqT)}PXs`bq&neq)J^${!bINU?u@ zf;Dv2M`6brYTbOBQ%7C&X@fFWSFEMhNcg1qh9h2Eo|xpVg138(&7xsN0OEs-W{|-7 zT#H9atAZWq@)=8uN}MqN4(uT{tqp+ zxtigV6*U>?!$Ce=d(0AH`ljc>AY;Q`*I?!w7h00CUko^@EFTCK<$U2!<($15%SB^1%i zNm{!(yRG=f%vXQbBh@prHI#3u&If<<3GvUcQo49GqU-MA5sspiZ(WwGSYt}~^oDw5 zDouQkV;1A%;a@LH(LRB?+nz+HISW42tLB_WM#^LINgGAZRiYvqU{uvLR#L^SC)`3c zZ@H!Wtx-0ym-R$dOl74mlJnOFfQpzu1R9+xBTABC{=B!zx4*G4c?N zm3g^^xB_R;8`!Vw`DDJ*Cb0!jsol7(4n#Xd&F|js+n^l?ke}KPV^a!#8vZRzEz?#x zK8tFsdVb70n|MrQpUK^$^{T||v2Nde#Jz3LuVcxYK+@K4AdGoZjg`)SNK+P9@PF&q z?JJd18VS4%Zv>cx43(`QOrl~yLYVRVDa~e|5_cJT?7^K2;pyo?hY=#+pdRe4)~wn4 zU(c=sSxKK%3@Fd?ExN5HFFatoE$;QW7rD~3VB2dls6PQ#-h<`|cJ70ZU)H;yt0?qM zsCD~fn@_1|G3=^8kIb38BE|B z*QPWawL8B3>i#IBbnGXoO`1-B>ilq0m2LN-FZG~N9U%xOTz_AWH$yx5nwLIc0?RWu zjt+Korz?R?bgX3Wbg2?5LEAmcnzws! z8o$#`nlqJSB}UVFT&8&`iWOYerJMGCR^O7T0|ElW62Y7LG@1F^xPF>nI$pVQ>!Lc%p>1g1h zpqA47imC9tVk(Ug^uL{#OmZdHyi>K~S-p_+^$oBT)7C zO{$+6e|h-8ZY#MRamKv4((n~JxvqML!yf2tr%`oqPNfva{^AA;T33WR65Wt~{r88- z(`L_x7bUEwjaK6=pA0c_W@KgwY;lBpZxKUb~-iP zvYKmLmf^y)Hj|hc7cm$pp1WaPeb?8iz>zjM^vt3 zhP*s<&iw%8(0z9$V-fa)gUN`@{h&NrABlyYKa z4m!Oi0~y>VgMzN={BUa1(Z`KRmYO2XF z`Cb`6f4oytQ`#XIcXLUf)|7_22%ieZ9$2%xR(C|yfV{K8t}h4K)=PDbm&hyzna)v5 zXWg)%{i#x3YEBXMf1Y8X@3mqZ!1c0#kzI%Z5Y%P>taA2|$66hDEdoLu-IqiMw+5&z{C@QA4-TT`Z_~9Fru+Q7UA8R( z4)GL42+@M9rycPC(T$TKC!O0|_&DljXs0MoMDgZKE+;&-c3|!i`G7^2>;~lEJZ3CA zSOoGkW~ZZT^aE)cIBX~9$olVbMxuZptVAVFbkCP$*wPP+@rnzR<7*P+V^Fg{SL><`iX5X%Ak2SKL{yP44-4bn z6>gd~TF|`_h8A%Ropo4+NHc?LNI4s0RgxfF2*mx_4IokLRSjX7qTI|`={>U{80HLC zK2_)`!YCc*qIF>*-Tg7;57(&`==LQTL=FiR`&GrhkQUept2*(N6IaOK8720;q1$J= zn$nQD0ujU9LXJM|^YVDK!Jk1EQWT$@VW5~|g~Zqa4aLE_M71nIM76UBg4CR-X`9Lm#^ci+#Jk$#|$}79rG&|+eMnZT6)KHQKZ1vp1d4+~} zM4h--w(w380EK7*r-(xvCyg0(`>r7Ku3+n^-`syGj)}I1kO9=27v>J>uZ(Hh`Hh%* zKFYMa+P?7E?Es=WEJ5r1{(O6Zy+DZNFCC$8;*Z-h6LdFr)Vl-+_O@sX1I$>xf|425 z+}ok^JGxS;aMz<7tb01}NxdafvF&mmK1KHV-lyVG)d|btu~eMNQcF1Nu9Fq{ZL(<$ zWnkxQnska%GiqPZz1C<_AG=$0gKM7+#3xElO0@~iRMol}zx#FV#7bQ;RU=(b{Ct2& z_CVcb8-tHdd+_I}8;3Jm?~kuoI8S%9P;HAwj8~n+-R7mu-*2?(Y2eX|;e2_5 z9(*H6JLBz=)jt?w?SaCsP2ISnGh=z55v(y&Y2V*GuFs~D%>1ieDy91=*3RI6b;XJk zvA3wi-k7#WnRc(Al1+s#FBek<^g#x2=BW#=J_P4eD-DDyd$)GFP&d!cyJZCU6n|vsLK&c~)WTDTc&k5zS`KL5_GgBc&%R?lOQ1TD+?Pl@^%o|0c z5nKFVVahiGC-MVHf9m~nk@!s1A9|JL#$VRAcAtB179bbb(rRU65!43ULV){4Xz3@+ z^w}#*b>}&MtEM#m$|`6Yb%!n)HZwwkie^`$VTGO!MTPi@uHcU_3>M}t7+|IT=}^{M z)}na7`Ff3OOV`-`6Z$r<_CjvnA^J|4c28^g$V6^lPl!bBYc;kj9ph;lXG7Q2@rZwn zFpCMwpYh&lqZHbsIn7%Q_{jMuC%`_!Mp3;^=?Lg{Y>Cjlu5 z)HR4WYa!y<^sOp>W7C%jd0rkqrobGIl-3-*9z+ zV(9$wMxMtkbFBvL+r``LLZ)q+8OMIL+joG{^u={7<++_SFwFUY0A<2zIG~g7+;7GG z7f6GNFzcm;!{qkFXFAmpmLBZebhS_#YemBzI$n@st(3u$kpf%OAL z0`DM{5N8|@g`v(E{sD}!$ySv`^YxD%o8rtQJ)r^J-$1m!7Gbk&wYz$x&pv}Q`%+}n z`+i0`aFbQUu%1||lTmY6eqJv26hH!P=>EnUp=#hstfXDJ2jVBAtWX%~=+GE2k!#CN zrK4gc^$%XEfpqd^qh?$!MPtsg=}9{(VN*B--Rv11gJOO&@^+y-;Ar5CrhSXZq_?=y zxEwEFLo~PKzx$@y=VuZ+wH(c*GlcJW0ldZVN#}>1q%04fAgPpM5_*@J6X((P>|Um;{L*txiTzEW7W- zPazcV<5skL&1`JE0!i1^QegS{VX!j$U!h%Ifk{Kbsb62u`*FZHq*(G%m{;<32y=N~ zA0|Ak@ECX)-B%ZMHod2A>(zd9@~aKs9Qw$;`{Dmqm9z(b6Gr{`Q}Nq>Q2l7xILQf$ zS)CK6j>e4~vOgD)w6R@kGU^w9%6m3MdGThMKNJ2@sO!IAs*h=aS^_5$+J7EhQ0KGX zpAzl~#UQ9P1s)Bw%(#2-KmuK2XS4V$4&lNGb54EkoM`8x#Z z!$*IUgGlu(>I8^W%LO%bCA4j_{dCSGw2au$E%8Bu7vfbXO_Bjd)JAnJK4oA`+B$+ev3iT z)@>?BV}H5MrmErg($Kk7+dwmKptB5sP^o0MjIolmAsB12fQF7RC7kbj9x&n}XI!$VM}jS@IaCwF8VcY10N1CF;zPIgLSZH6kD*#GBV)k$ zb{5GokG=8<$d@VRCX2y;J@i|Um?|X+&2x3&t5000U;tZm`f3u8Nrf$zeh+>d7`N%! zum3Rj#*JfMpFz{<8)lzAWSv#1O3c~-s#`{G>X)-$!2LIQjz;^rM@U+a6Uv*@H_H#M z{Yze(o&STgmQYt7DD-m^E-{}H7Ed$H2+Qt| zmt^m0@);Y_RlToUTM~X_v1SGvpHX`Q1i0rbjej2-xF!ARTrq{#S*;qiX298y=E{FF zq~M{b?;w#GeuBsB8eN#?O~TR@$~7xC{Ti%w$dxLkG~jTrF__|6$6fPvc8XVqJ#E~%HtE3Foh^%biS;M=40oEn{H-ygAYqH~2!pZa{JLwk zxoCb`IZ+$Bp3jx9sAO211UT+$$mrr6(9(?dxChmEfh*~fSU_+mZS(iUkQg$GUxtkn z@leqZBIXAL?2B@KBXPUdtJ$602OHbnkAsvrn?66|I0PnMNoU0x;#TBpg4f?4TeW%| zK_iALt zU;H!L;!cq01_5{2W@u%hX)}a;AAA6Td8bHoF7-hoYVK%@jlf>q?W=rdi$9$_p$Lbr zii+YChQR0eE=+T*Y)&=|+2jzY!fS?*d!Zn6C?-89WKg>Z4bIoe|IhhS3)a2J%d?>N zX>^&W-WdN{U1>dCqm7P!r}WbohgkWAAdIcS>PE7~JJ;P^FVCetz=kuwtRC28MoRa0 z1IAOcDo*Dl{tLTy>5yJ{N0LX^p*iC~(}}&SZ|hAhdfdyJo$~RIp2u0W+xmYvyfPm3 z;^3J}Vfy1gOaH36Og+e6HD0`bO%i|1cz?IMe1|wmQxFk#h_|v`lVQ!^V8Wgw7mR~w z?K7;qCbZ-GMVc|F=CR!JQdbJu!T#%x;NH2yHkU^mF0yxBr4QDB5#QkYVWmy|N#Lfj zw_|npD1-Q~^|Cry>bAjBPtK&+S7ZUoH)$H_pLv4s8tL?+F9jSi63y{lEff+fO?3ml zi|%h0tVtkoqDiff`;#VHB9hJ_e^Q|X4;T<3GHi>;aFk!RL7WyhiFi|uNZQhZjayZP zrbUAzIIVQXHy_E5BPV}@9Qal@#)?&9c5~NL#-R|^bn`ng)>v*~33aav8FE6-vF5*} zFB-Ys-(n%~ahD31SYc`;@!z-6_hB{kH%c+N*j?gyAQ*Bq=tHDIl9z&1zb&aLZ6qCw(JjoTeo`r7JMms0fN?*h@_weYb^YE`5` zW2#R_6l2*T>0a6DyhC~K*Vf|h026G0q@;7@^>+JPvM0AEmU2WrMYa8Y=#X%(#W7U8 z6zmBc@OuH*oRm1pDmEx&B@sCjZ*Pk5N@<@)GLQvoX^a_GP72<&r8YZp)8k_5TIXZ_ z!i}+#&phW4baSXv+pb?4A`n1?5@1&Ab#IugmMZqWKY21qL>#ww!s*Rl0si3C#5XLo zC7~m(Te6Kz&ItZ|qzIj~ay}TJ3a;8)k<~!yLMvU7ZI3ERXVX%bO;)6OtY)p4=+_s+G}aqX6~F{ zJxcvl)6E#G=+kI-v~O_MJ(oQSATG_qC7pE6;cY(_-y%Y9&POl?fA{R zOYZIpDU&9?MR-}f_BxDNUQ5=nsck=!&}c}HznLO7URM}eLhlJE)S=FJGtmk*ztCOE z7Cx51AvsS`<07#(olSkaA>R^F7WX@S*zFSQu!-A|*S!8^?{eItFahomRzi=c9Dgw` z7|kn95d01i9>}L_3oKExKS_lFE2&e^Cg43 z^)cnTQv?rCzFLmflU;C_l#(p&mC#lRk=f}3KW${dj6*RBGyB(L54X3%+E7|5u5IoW zsn3;j>AIJ<<)r89ila2p>O8#k+j}?v9`4R z)DXXP#om#4WNHIOaefqqm0uFG+Fe(oHP_gtEkCTFog-*}<=GxRZ{^C^HOurugYizPfJ?iVjy&${pm+?*d z znQr|&Znj7eA9Mie7~5EIHz$?g`bkzh*Klm2!2WFJL)R7F%&%!PdExAV{L3XTqS+dY zdQZvC_>nmakXiRF%Ko2^FChCD2Pl7jPwqVpq~L8;jd<@EJIw0yYr4JnL0d>j+^Q+z z5pO90|M=^Yuiw8psB=VAoKy)qEVeM$F_Hgr4BT2sJb)sQxPoW>er>Lr;FHK=2!HvF zpBy$+LfvVVB8gLU7g+T+&r}rhN0vKzDHPfZp*x0U^ypYixu9{UX^^Q6o;S~a560?+%H$m>eZfv^Z)fgDr#pTN_v}?mZ4kKi`xHrIQlDKtsW zLiBPIk=!J0=m9f{7@QNJihoq0U(yPbZS{u_MOhu|kzOe$l2N0g+mxf;?zM6$S>DAH zQGJT=5kU@HwzqXo2K(-o`Sw}F?Mh`d+FK?C5ft-yp>$}TR3^D_zji(7!NwnNQri-x z-1ssV1oX0fF?lzWh(S^CgxLIwe*be#)mkYLS3D%2dYkvdLO$uVDCE5RngPdn1Ec0H z&eya>=X)+l*pJiE(2!l*kL@daVl;;W)L|Ho8D~Z{-FH9aVwzin*pX|L95f}qA$hd{ znx&miQYLYnWXs!>CrCdYum*L4uy#;T1!0eIp_Ki~^{MenNorc_bm)3)53-By1`x}o z(s{ElOaS@EDfODr8%DH=cGCoiJ~HPF)jZ3|FdcjN$A)`)3kp?nUO7mO-v&q{Ev~*X z-B5M7ULB(J^}?0(%^zw*I%363thD zvu*a|`6*qX#I1w2$!7YJCgi?iX9zoZhL#T2g81xX=Gd3p5oN~;rZ z{oY0~n(7W-mUF+Btngo+IF^6O+Iqrr;+|>$s-WI~LfUf7rSy{|VuJT6IS{a7b+^_W zDD~c-cncE2imxC!J<>TPD6n+()~U6((pzuOP9Em7gwaV zb~q^EI%a^5^?A<1yp&dL;gn9QFwaiP&j)*XTM8&D?iS?Pb1o!DAZQRyZ*|$Gmn;5c zl-)jKk&i-9T`7S@9-MvP-{YvJnaD0tKsDjg;crCh+QbzS)o{46G0pW|trH&1UW;}^ zX&c*}EyPt`&Xi)R^?A4X9y5RHVy~imUaFY4H`}>(xUW~<=N=Fo*ZV+uIgty_AT{&_WL37n;~Xn@k`ZE(y;sme9)SlE`P*C76(y4J%Ztt;0;}ox|YSF$$J&c4^Z|!os=$Hl3JXQ6e3J0xtq@waZ6cP{kr_b9Vt74k2+))X<`a!;!vC{Ae zZJm;)%y&y*4q;ih&;G9YL%rpJ^0Gsz={Y*XKZ_%fYk;2}fmL$#_2Qrc1mvn9PsmhO zgl`lT{KBmmMKu(XcdCEer%CVYx21!SsKZf)je{r)6T0%vBS0PZp5!wHY+5Q31>+`{ z*wRet0;TCkYgf&-x?MK=zvoPG48n~Ep67lJdHiR?Ik7v#eOomrU=g?& z{jRD35q-;t6>jcyna_#oxq;rbzNd$SIchlV)l$vAB!rkJ`=gXK7}`;b z#&^t@5ytHMosK;@e{Wo;MZ$VF!)LW^|BbFssdvwyey<%0qGJ05C!({zm?VI|Z`mHv z-uAU%N?@w|cb*w;TKHro^eAfSrTtP3bMMB*F>LiOA%A#2p&ujtqY)}>l}MPq3Q_Ok zN-=+EJAzKy3gxEgj_xt8u2+q+s8Zs(93fP#*+qR;cF@1@5I56dZ&|h)W&IOZe~Cko z=rK_#E477>5c__dg@)MlFj~A?{|m=P6%7RDx{hu(LfyqBUNQPDsnE;&k&hUsaXKdS zF--PcGkB$2?`llQYS3fRHyMHLvA-^ZlA_wQ6Ufw z6Xh_O^3xDO~BfaU4t? ziNmHrXov3^-=MY$#!Pw8&iyJgkr4Fc7v!j;+JA{CkF|g27u`Pl0~F%pIA4EDYM)E2 z@9TZyD64A$&{LW?A{LTL4mc5auLvJcL4|$2srjR3!!4Pxno=o0O0&i4UbN&sW3@6c z@Bdo24u}wa4m<^0C?6 zla0omd$SW-Hlffl0ZYHv?9LBZTB_qw_mNlHZKtZ9m-go8#ce9+=HY3P72|0SQb(F! zW4l*F9YHT$BX!C;fN=C#ap~5`h*#ld4#@pd0;mB8X2G|ur>>cDzE9kFQF^*cMeg(oJ0%D8K+L9FcU(e4j3EUdIs z)Ds848v+ubW*c!MJi&KkxXbsX?bQ7aUYrWp>V;z*=j!B(5{g3n!f}VfZxU<=S2}N` zWwe&|>j#CXrLGfiy{Jnow1$1+IPLr=wGZk2s)^2)2BCXZhnJ_At_2&9)zoUvpURNg`O=T( zH4wL5T5Wh`VUlWE(K+XMiZAkGwpzV%dSO~gjuj@3%{Oc<3JwKX4k(r$Ndc-)l0(cUOU!-&@zT9hLiM&HTdIpXdB0@ zm7mkEygOGy2L(`$ruyjp_mp3oomfC-`?*k>MTAAJ2 zm69&+V{vbEu5U32t!d0QQSxz!#3-KB^vzRz7hoh>9o`2x$Uz??eVY#EjY{Q15O=9U z?4lmN2B}#}l?cvixh`}=WRvG;N%=#B@?rZLKs3Vm#&i&US+Di|AhmPUp;<0PL&a6z zyE5ZbSkZM5#^pk$J*YSE>-&xXJD(n48{dtU4SIP5h$G?@Z{cxrdLS@vu&0Kijv_PO ztF&xVGK^CMPxhdCB^5e~@`XVdhDiGgCGHfdDU9P3hs9}rtYP?dTLn6crkXK_^B*JU zrdJo!w#z=nTTIDKL`e|0uCMn~od)pA)-i??Y|MP5$w%8)oDY_)u7aqll@h|*yqq?_ zjhW^qvoG{(8Ebu(PHtL}kb_3o%8y%e7H^pakIo%63+QQ{9N<~IEPdg*5+vlO^(g6H zGgN7VFpj0@6pG7vL1wZHo*i03kNbL?<<Z4RjW^-J%j?9~rWNU|nK?bDB2M}(SvD(OuNO-0B;q)qQUBoJ8u@>s=KgoPOyD8nAJ#o>Ip>B}!c492!v7A6Mt#NI81K+@pRPR^ z6X;``TemWpgPm{DDv32VE#kk$9y^o$p=#B4K@?Fm6^b*}k&4sPOMpG^QzxAdx(Z=o zrh{*}36Gu5?@!Oad{iZQfZ7nwbKGG_W=eT=UyMKDqL%iNXw*LeagDP}(k zeGEyXdDF|`UF0^@8$lGPA*0QLK9gTXgLJgo5<8~YS5)*p4b+bfg!>2Elo{6EC?ai7 z4%Obw%zjtaxF7mT94HY?|G5$G8V^|hO<&F#)8f3BA3wRnqO=1J^X|AGOq8WcU}^KC zdI%WFC|ME36?_8Ob4shP}`Q;=CoR-{`QzURhu7Zyx%QQHMsdSLY(A7Z+g099JO}*GM*5;##b!Z z7amXV<(!*sn$6&eK5O3@?JK{P^Sd4BxVavF^8nqNKi6SXuL@cTcg-GA4ng80dPY@0 zTUPGRne7hgHRnpCdK%YaXcM2A*0LdYA7RIRDlb}yLb~vh5oE9pdgdIwbIa*5zC=ns z7t=8Pjfs+SyNcW;OPr(QZkrsT7$n!5N!@9(b5a`qQ)snkFhs2!MXHKDmo+LW1xS0XwqBeyuXxvZmXmVsa(5agx6XZ4%KDJ9)Y!>B+2ZBfgt{lUFv zHVR;uv`MW?;gDqyN|ljRz@~F$+7ja0m?44=1aToqe#Jw(oHLdPjQvGE8VJCgo#m6i zs`p5UV7YTm0|HL@c*yKNA36rz^YVy7a&^}?Dbr6*%BxCfx8eTz;7O}Y*HfMiEz^Xq zBe_7<=L(G>Q2e9;8-a-|m0uCTt{Hr2z!yy`UPt1>B^Ph_Yr(z^rA%Lw?fWYK{(~z5 zw2l&x_q}FO@$y7*RCyWrfNWhszfrJy2DRmTpuz=-21E|}KWv?MSku|t=D(p!6GVzs zJB|p!0w~oow!y9tsX@^JLP%}{vkRxGebt*1?@qlBk)@?kwPCh(dCLND*EY}xgN=#?F03k;9G zz&k|C$XJLPW2I>}%w~s{pmQRpwT*hB@+|w2)`F*#1CwDPor0&t<+A149PuZ-2_=ee z96J1!Pdbgcdn91)t4%V+H@gAnCw4%^hy%w7=?kmt-v1Jlqo$i&O6H#6BI$u6^Au#Z zS5IN9J=k^qpUowaiw-9$?{y`Ritby<1v8pbzLpBU9w@^NMbHKc(@Q@y7yrIpua85_ zRM+Hk;aN|jx}0;ZQwhXX3Fm&(*-D!ReO=HWO-T`4WAzdote*6DWm%tEv~4?9jjFlm zf3@@vqP{CUZOrlmw>PNu-fdQ{+n{Y59#84$w;sY(HS)~rTWj?2bYFwJt){N`Q;-yc z2itOXEGNItQRRQVMA^|26lPma(ONA)iQMzF+QGQtD6H*E}#Tp&aUkZ1z{Z+EfT1QnAe_`C zQMvOFX-cRrmj#t)8#*i?C4hCjq=T*>TabX(f1SI7@5l7Z;(_lDMWA!cRKi0EruRz( z;u$2QoVa9Lo-rF`g>vAr5n&+Qv{Ifg!3Z@u2UQ0`v>G!KG7u_W;*Bl_00#^j`%I6- z4T(o;_EL{7X1tlUr)oKD`Hx+kwJ1YscMweB#AgzpprWZ^!OZC$sOa38!lH&f-1otg z?L0VJNa7VmJpj}m{CdCG%64(1Bdep1-}1|k&QsfP$^58rEiBp>AVFrU&$llQxmMJh z%vU&$eqHTn3pPmBeVDp*3XASD=D|^D%ITtsYm?RegMy*AP`J2DXJt92UcAHZll8m^ z!KJv6H$%Ag3ZI^dg8%NY*hT34mGtRI?|YM4t#XI)kF|2xFSWDBRc5DskR?U}#YIa% zHFtb@una+Sp^uLT?{>A%g7Y>C>ax0SpjXX2knWO{*7*b(G^1H~cI?B_ZUbyfJ z@Y`-%WN`ofeE9jb){Yu<&FsJk*@Cc`nQkYV`yTRD^dAqzRl4{Y*$-hu#)4)fNiR3T z94c~ra!UDG>0z|P24Ni8g7ioxO0ZHk*%XwSf4=wVKmL8Y!n$6ok?nIaJm2{`km2U{RAUF7iECE!w^98+zuH|!ftWAkTzo?^IpB~>G-=H!z*a)}Mu~96u ziVC5RJeLbqt^MK&3t4pd`E=%nZJr&9}gx6k9Ex>)Ikc4PG*@nXxm zzTt$EQp#v(`@wYh`W&ukk)ZopvU(=V(2bF&xwX^>X~gp!Nnfdtxog-elPVY(3hPby zxcRV}b^pgwYs&{#%hHJ)_0}>M+trbcJHOT0izg87AETEt*)C=EdFWJKiPrUo9|k6J zbmEg8hZ~Vm*I{m?57ReOL7qukL06xsbDvPfCc=ZItf0{``O&bXMvthMl6s99n&J0@ zEg;>dqYC^=AyKwMVW8R83QDUdR%U>nu7LQupP*g-%4rp?AW2!dwr()MDD5Mq>;Jec zR|07rKemH!21U!I9@+G#G-%5X170FMyI&yS{@~xv42A1W$Gl_%HvbeS0KU3}LFCq- zkn#d@-9QH*)5Tzm{Zba#>WzRU*JFbq3lwx<_A4H0LMrgAe=@huXT1#-hwhRspUYnY zU3}-q8mp%v<*ngQ1-vQH&m^i^`YZt$TpFLA~af`PJvhegPF+a&_X@MU!8dR+|q zV}D8?ZP6^dznQ!7e||2cNbU2qCR@AP*j5>%TtT-*Si_pJ!FAhTRLq^4u@2d*#J`l5 zWBRCQ=C3MV3@>orFNV$e2r>GZX;J#lgasEn)uDSMW`_FHOPrUjxM=5%n8)Z$8kf|i zlkR2Be_<1RuqqeE&?HXzMtT3-trYJXOOv^RBTh(z@@#=ICZvX+5haL;pANGTJh4ee zmWHel%>RH!S%SqzHt6#d(?$hd`c1Vs6qx5C!0NI7|5`o1)x1z=(sI+OtTpN5C3n&v z{`t2ZEjIt~KIeWyJAUdf?s9GMk#K)oWvKcCeZTt^*wn33XXW*zkAF}2u9mp}WN+X# zdoC2+t~PPiNxl5SLEw;kU7yLQx}wplG{0sUAw1ks0;jaDN9em3rQp-|JH1x2eRmo1 zbGNG1F#pZIa&z6y=6_ zFyioL;5$85Cf_B@tbetL?g?yPtdrsBmE$`jMqrOgVMmdQW?_seRXVk zv}9%>Gv@|_J6Dln!p!dZ1z9l;8Tw0tsE@o>1E-#qZb4W!CNnX!2gzPB!d$pPI9WE$ zqJFuZT!-Y9O(N`8;oU$kkmb}A%3x`hn-|_p;Bk}`m&`6@+KOM4o+q+k{ZS40gS%eeD zcAU4?-5g1l5Fg-H6s1d5s%x)kKBEoZ$Q zj@>b^t^7EB@4nB8aa94GFqwQ7;`lKmm6YG8;Q1SQW`>+LCF?*~*f*LkacZr!MddIP zTKE*u2@+<2;>}Q5Ir0+%|2iO%pZayl!t_4Y9N_#8H+wwPx&mV;#*V;r$3Q{Eks?(< zn9-IP3KGjhX+im!GQtMf@uN%*1-B?9?wC6W+No4J(|DR!!oB6ZH;Q#fK(isBfdeMl zejeLTlTbizwk_slap!lZ-rNy^*&)nMz)TGjrJ)NoK*%6RM9L7m)^)~k5Mws7z3g%~ z_c;3eM|bn8;Pb8jS-M2lLjjU?N*wdf;!a>|a-?DdB%4#sbc5@V;q4EZA^#2peyh5- z0?HK^hEQu|2JY^Hs*Mj+zBuUB-En9~7uQ5rvT1aljh;5%wPsobOiK(}&SF5AtwlDP z?`-4+4IjNDjb%qQvLeH$r@r}hI=}>Fi(bB^qg2N-C>+ObO|)H^Ku7V%)xh|)+?p1Y z;!1^uNRoV)?hY-7gLcyYlOgrp#m5f>%hQKVzK$)fhWDq@mM6}N`TA4l@)1|<{P2#66O3jVt+xKXHU2mQE`jL-*JmDzl$G`OSJAb484emL6(jpz1REb-A?u#WXqZjY#2_3hA z1XROjJ>rp;pi9-S`$)jJpfX<5jI2L9wJqoBOD}2SY{#Y7G(7!VRQ~W!ofM=b@ee%i zzUp&RivFyV2QD$R(LI1N5z)+ow|>ii>~+ynFkz&ZUDqp05uN>5<|-gokbA3&dUG(S%;T_!Sr@= z%|!yZU7psZiJ1tIXQa|W^jNO2`&Va$`;$Ce933d_)mdRHedI2*#8Z`huLb|=J=%uB z9f^iLer;M`5sQqyD>G*LykdSMiPn6$PFHyI01&kw3+I*Ns_k zLm7MJhO`Xh!5LpA*LWc>bgJo2J4e@CEjycSKn@F#k8cgz5A?ndl)!75 z+5-+Ma~n@z{|6vwH4cEnx(#y8s6gbTy!%xdqWl9h3jY2h85Pi6huXg!WE8| zgpVUhL>?5D9y3jd105DH2^QTQGzjbq4i%4|u+mk|fSDeNRa%)PoM3QGJNFxuKZqd& z-_;WVu;F=qiHzUX0H-tq)J20>_;E&-q}GY!K#&(x4NZUx+jMI{5QJCh+^_ig1Tt9c z7=b+q@J7QFmw|O)_Ed$aH5ePI;5cI8b}>kQTY=SHd$1RU4^) zj27l3{fEfI4F~@V4EFa10SnIYqZS^ttWx7chjgk%=Y$2lNNUCUvVZbcym#l^1UCB2CF*4W)!iW0F+4cU^^^r-2 zv_(OcAjK6Q&AU> zsp9|l25HeeSCRC|40@#L{@XR6<7IBgV}?q6{uLRn80#4kt((cam*SM2dhzzPQR;WU zQ#KT0P?;Y4tX9!9r8Q{Ga>==x*oMF*(;R%?e>S&Bi7n5d4ICajbxgl`sIk8_WxZT4 zg@O(7GoX@L?_+|5L*v7%HdUSh3Wy~a!3&j%fig!jGpQ5Em}xso?EQ6Dl?re!3$KSk z&!pyS;3-Y(Ip-gK;~%e@KXy0O6I9nC-H}R*y0Pp45c~sN>I<*o55gaGcFgimGH9qj zzp5nIM8E#yI6Y%ufXc@%9SA z+Xp{;>rO|Z#?U7+3TwgZH9MVKSI^`c{M9-4an^@wSFRgZDY}&!b8D3-=Aw$Ijdwbxs14Iy z%3E{S?t2zincu0#y+`pwv-d&D|)yRaye(mJ| zXKgUoF@U-arDA!BQWID+QR`()$s-$8|?3Ob9Spnptqhezf zH&8*bw0q3`pjjUYwmJiuQ4KIg#b-A1aM+Qe#5esP;hOV0EYid zx>8zc+Y*VM7}BpQ@vs%jNwjW<-UAzfBQSh8vPw8ak6Qfok!KqfvAP}>tW~nWe!DK0 zpsGlj^c%bJVA}>SlPjjWZcU5_aLnli#hf?~wQ9^Z1AN?#P>Iv&0qUEaq4J|16xF%$ zdeWPTDaEotNirQC+q^|4$~S@<<*14l6hKx3KzPjy z9%15}CLUpesR?<=O3s{b1w@v}Z+#?G0K~o~jct@3#>-E*k`eoA z_I$eSQst?(=j+3JepCyS{mL7(bm%upH!6?bH7OWydfT!Aw&{%C`1o;+63FTNUq0L1 zd}^OQ*u6dzoL#}Q6$}dIcmlon@_&~_oDyE>=n{d>_CCcvlFN%&IRI;t$5aR`f}wQ2 z*8`IK>XD*Yk|NeuiIFFQLmq5sbPyJ+4q3@^0yWpOa(Rc>2CFejkfYq)Y~tv;k;(v! z;n1<}f^^+En6B-%e6V+2{jz0;?wj0QD_eZU62b-&3Hcsmw=t8ec5wKeud@EuUHc0a zTH$|NgH?~y;L4I-!-ePuM`*yP4vjQQC!@c#44WwTvxBP9Z0&ik#F%bEhMZ!>OtsR}m5`0C+5ZOKWrC+VW z$S7-DyQl0PcG7+7mSAHd{7#}k$n|q^m!amZuhdoYBv>$Lq1JrGll=wnOLSJsr%h$7-JAe07cyCw;bL{?*I_;uULYQoABiBd5^HVw{K0Xm(v+}_n;Hd@oqRe}OwM0t#F z%fWc00tSG-C#YYolO{CBP|~D`rn*x%pW5G{eJJkc#fWu+La#-xr{Y8>Gp?6+HPKgf zx_g`4Totyf>+8OVY_xF(b8CFV!qT1bnx5Hi$yY;;T6*oo(i`uLGyp)s0jOG< zaO7!C%Yn>-rf;vlS9Is|th=Kxx?|Q0P=(|bSD(E3>&foQ_wx>63q8F`N|YJWMey?# zWPBkCBl2wz*|7o2;njXQslWszz*xA?&0ZLzE5s)bzu^jbz0p?eBs0G;0klZEXqw^< zKF-yp{cF3HL+-Jwk48%drY4AH6;5|Eb8KIZhOkb~a701fBDcEkBblLZ&l}+jUftf( zDRW6n>}GCySe)7K7hK`F?@)u{m>cPmL3M4Mj~ga;IV{=3^klIG{8oAN&d(#e`Bs_` z_|QC01ZIdulu9EqSXNTb9D~0(odhaH6|nndoS^_iVd;J$gl$j*%*}|#qU2criQFyx z3o1gttpS6nDq8(P>tLJFr_`njawrz6oo?frZ>Gg3nIa{~v=*xax&AQzNAl%P+I7uv z6KH@6DZ>K(*mfhESZljSbcD6`Ipm6Go~)$DJy9sk14{~mktQSB;(=7?DygMM8V3RP zfEdTkvgJF!G7jE$!c}4_mMkFBmsJ)^{7DdI0#%vw#_wf9e#td8tGyb9`wS?4J78LaP z*AW4(l;#HU8(VXXp7c0fAzH90mwQ(&H`cT1h2)KNXT7#3fo)3y+vP!-w;N~eYN=&x zGq$+W(C)=T1O-*_e$Xap%~l2SDjllEwFH4-C`3_4!^Y->>E|Z6?FH< zYW64n&lc2;D;9on=mCqWq>hI}e+q<0ex=zNs|&k-UP_7RUn89Kt(a0-a@}2QI_l(^ zb5;sX{sdr1&wNTJ5QgLB1Q4Pow`3m&YKsKAPM5gJ;9Uw`B4%(t=|?#t?a4%X9$U#r z=LCJehpKtjjsEv`vpRHA58^d0IjpJ!Dbb+8f0|bYr>;0KjP^f0@V#U|MMjwBO#C>J z?tzO#X6sV?|Hv>UEdq7t+@BHQYimygD2#0!F)BwuCXFsoL*Exxzi(7PmNxHwi)nE`ZXi2m zxjQVAEzcb^%srpKlvWUdy9!woJVIbu8lRl0#(ND;7(16+8e4kac0N$M`+PF$92~v2 zF_U%bjokDXAAKV$>_@spgp<0|#A2YG@jesn9>FpXb?C1rJ$`eam;Gq{)6=ti9JTh@ zrB_(^+l%=>x@3k$`<5rf(TCRC5jcCy>bTj=s-g1R(_-$f8NbuK0+xxDgT=hnT$9$Z zu#P^N6x~L0D>sbV?4b~sAMX8LcJ8$)#8~5uLTK#oc z_NbO9rhCy`CgY0wKFI$La6#VIx(h2WrUNv4f7od`-FT0p~NdZq8W61n2r5&P}kNE$%KEtK;#7axhYKfPn z4%rqzzxMP~jN6cN&h1|Z&&vwUZkrt7&p*O`UEZ7kHXPIz^$3l8t}si3y6(V3NjE-S zzOt=6v2hkM>7q*JXiLO%5&ZbBLhFhQ+odT6wB|!dMFeHL&p65=Ajm}e?4QT3 zHN;u?*EqcfX8W$q-$K z+J4p6Y0|@bM$xC{h(2tO8X`h<9^ab3a)ON_h1t$Uwb;J#T}8{=ObAkb3XTV8yVb4e zM0b?sx=>d|+TCTW=nDOM;LSaW=KF1|YZg6-PQ0u`Pqka1-7ttuK^fGcizo1q2SltS zu+i2tI~m|6@1HkPr8v_N=~C$Zvp}bfXezl-*dER&tD(Lw8mWbL%)4aijV~Vs*}LPL zK}~F5E#VTK+DJE-p2wd010-Jm$}GC;hkO{NFx85|r(2I(#KLqKpK<4#v>pFMs;nJ4v}_*7#7=RHIi0<;~jV$jMdQwP_>g z!=K`^h#lv>XZa5pnpr8yb%-jOx7VYvqfP>rsm`kBwM8#VO(+a#%ABZOGITW5f^H+d4=8^u|vh1_}>_9$6$Mg>olb6Dj8tL-b$t~zh^K_vr z5>{@Bsa#HyCfP=OOFcGc`S`?}kM^yrp{{S3Ows>-5-{b)Tr2w7?7m_Ij{4W{lXsvP zT)rt!A|dN@)27Q8E+5R3mvQ?$z){9+=v1n#M`gYp<~-&CZ~fmlwzZT>s!!@hI*y7; zJ;_{KYO6VBC$h%)j~Lz=8n^iiGtX2#T}DiiWw^WXdY09qFE)4Z=A)5Mghy6t2_qca ze9x{b;@`pgIXdedt1B_NNZf3|nT>+%q-$*4(xm(=#zzMJFq+(=QjI>}1{m31erP(n zX1CLm<8)^l_;qhtF()CeO=K_Ke|7H7`hiw!NzUzQa5(kXBxc%no=Y~hw1nci-)p9h}v|Hg+uKE^+)eA%9;FBGlVUOIbuDa5x z)o5w{)AA}@bz({Jx7z5XTc5+$%>C)xr3g}yRO4M+c)e2RKTs~XKD8C;P|P`ZO(Ivu zQVUNm^%tJp;oCFtZRpTPkEEpVl@#O$i?h&n>az58)fTH~J;|}BogzC~!@&*`H+!>- zx=O8jqQrfIOv?7PT+CX-^4Aln?VKoWNk&g$4}Xgi zbIYY3REg2EP|eTLlL(xId+^H53^0BzuIIW=_faQie<@^GZ2auq(f!7Y9?j zqWJ>7W;&N}@5CAlu6q`bB*Nzh106%ecQ)6gK2pY-)?vd?1FuBwClJqfS;m(N@H_T8 zyVvf4-&EOLNWUy-lBtO?=J#2S*4tb-E*tPLLBGd)nvYVzdW5gOol64cLUF#Xhgy$U zSZ0$J*tfl;g6~Nh$)%yn= z*#!?*4Y|8J@=gG3Faj!1#hUngBoHIqelMy`WKH|TlVWO(2wsEr69y#^H;G-di6uhC z#{HefP?Z^0hlg@{BY7QLE=?L;cWFdTK#u%kmFnhoGR0FKQ?q~y6-Q3Hr2iChD={Em zCL3_}{$(oePdf#vueY`Yi>C&>9>t{SkqTE(s{LZWY@+iLV2rfddU1Sx#cu@Z*+hNO zqa|uJ#-O~5A`J9OUrPVksu&vGWtQ^rtBy$81Czog^D?RH|LaZ9o9!#6E;??+MrF7C zzCJzQ>O&i^YCb-`b---;Ln~uA6f$gewd>63;4!~m>ZPZ;7J)3NmvgGj<72s<7ik1R zj?hw{*II5MaH_+3uH7#nA~A#p6J6ZAD?PA{>xOe87A-{i(nTq@`E|KRry?Z@RBz1Z z6e3*PbB0r~b z(MnF#AL+?cSvIRgv&%xrx31X#zN9)rI!TKzuz<38Up?aWAf*w)&S2pI$VBD3uD&Wi z;U)8hL`)yo{z<%EC3@-p?R%@vOfX_AjiKJNSYu#9-#XfYCsChyEyj# z$lqpfi;Qa>&)Quv0hj#f7a;JK-ualalVksERe>TW>QTDhSIpL`Aw?Xo(Y}q1S@=zfoQQ( z>AsEo8VXr!-oS5b44!xq)kd87K6j02*(eD!ts9nJ$-##pBFDbR&rHQLi~7{o1h-s? zCtzS>r+`(JvLEqxg8u+C49;g5X-=jC3g7o(LmLDC=Lt2a(C=}4D5m&0lyw7S-#5m3 zLUUOpbs35tRBUt|Rvt^zl>~UMUE{C)07XJ}s+MH^NMRqtD> z@F`sf!+#bzvwDE3h;3M+LLT>tVEE4Hj1R%Uud^Ui5)#RyLX4>dT4?>7iR5tC@m6E7 zdP3qWOLN)NA>+R<$VjfG!|#oiVMQb~%+h)QOPb#$m z^^Ba+k>Ce=|{=l<|L zDeDUnKcP_}kY)!r9>~>YC5({nTS|@%W=2{BPu?quB-ID}H^>opJTf z;t(`GZHOQhalS36l$aiiJ97i~&Jt~?&cFFN2u2v3ubazjLTWU+KMbuZ2ith#9Sq<6 z?1rB7?T37vc9%&F4=?$#fUG9E>c_HV%6>w+{)8^gHzbssW}ht?)tX0Y-KkPtm5${nV_+4y87g>uycIEN*!@+x8##co^sS zUah(;N^5RBSBDCRPhK|^s>_zcnmA9BB}v+nO3EHc$-_`%rG{z0_@vw%3#OwoEa9fb7BdV--C<0}j*m3&-@*#LkDa?>Vqid;+|>~4Op zlGKzoY4YTOt31SC=Yqio6Ws^fSBb%2*d#1nq$pyf*B(VL2PKepIZ3m`H-$l(%UorT z5&_u^lPvl2HL6sszzLJC#jGAtgUXYm9I3cdc1&i!7IgKEQartIg`Is;10pLt*Ancb z4Bs0;N@8Tc*lNx!5mPo;3;py+hX|aBl<;WvM9y zjg%iG3q1k~B#pFOrODnZyVu7f4+W@s{L!l27%>pGlm4KJ#`+P{U?HnmpcgG;Z9rL~ znp4NTC#MNUpM43wbT0+Z^HE`Kk}ZYkUJRs{&pts}M1P~m+Y$X(6rVE9Wfo6hemhqd z*WJNo_r;**DHr-bX3y;4>lRWxatA}HscZjKWk!{<7KBsP(HElJ>Jiz!ufr{LxWks{ zgTjWqe})OSZ*F*#1Ln;UA5>Z~yBK=OV6Xb>3XPTJn9F92bOsJ=g?}X*PX4&Bdl(H9 zZQ@JwT?|EAXKUp0b8Mi{{gmCaTUdevd}I3(b|wtqgtrH-`GY%DJ|?2u!SKdl@{SA0 z{1f26D(lYxMXWR+ptk$d_slw}H`2|=k4TZ`0AsF1ZIL(f>(av|u8QBk?jjz>l>vt_ z1|@dwT{gax?cG0_xg%$AQh|h*CQfIZc)7i!ZbS;i@-_LsdeNVRy|OvJw)Xuz5rZ{D zBAk#0O=bFePVTNXa<8O>L*ZVr4idnSm;}A_U3KQ@K=f0i-&qBfk?8ve~hEIV1$ zN!@==xHoOBZW`*U^qG77V&-v=p(6Nu(xi8gyT=cDIYVun>)VRs+!P|IZyzQ&g(CgK zSWjpfxo$fjVXL6qnFwP(1 z9Mv?niY?XwddyLN*qh^wap1&t6&F4}i}u)vwowd)UQWy?$(2D`*(9NbO4>C8{&4l~ z0Q8e7@SChvzSp@oc^T1Z6f)`r=8Gl#*Q1Fl)gj_EZIapAmfMXu6Cbzjc?HS=XKOql zR|ZO^ULUe(+N^|-d|6P5F^0+>>PbQYKOqz6*%5G++K(VFOOuYRBOefJM5t1jF2vX^ zssa2LVTB~=s>M?Xa$&-cF*KlqQd7*s(eJ^JM;qq%`+hf#WAv{_b^N6PF(hJFBl_zw zbuiPDb_ht3gD(~6K#aWzfhGgIy5CQMi`JN52@RzB4&D1lFKni|K##}Jk`^?E4gs{# ze`F=Ft3}}4i$46m4R8H^jq2^-Lg6okTiX-|hV$As_6wnNvUjTBu90J_1V5Wrx~8IB zeoV9&41oHjcxrP{v35~$T@hm`cmu42c>0Rq702radxtxFw(f}X)?pr-Vg}hv7ncd< z*S6fUnRUUb&MV+{pw}o;Zv;MUhmIG5FB1g6I-Jhu3=u0NE-Em$ctweLn$OPjXXqx{KVH%V-S%%Bi$K9C624cuE#v+gK#g%z=(B$XrXUlDt~9)5jJn9Nh}}}K z>$utoAyh(t;t2e&#Fd64>+42z)YhS`>kK3M1#U-|2R`vpB%QDyGp#{&=~{L* zX$?b8Q>D-1^f~Qp3x_=RD{%S-wis#kmz`CU{uxNyK9qaxZtTbIGOUvi*^hDE&BXQD zX!vw{JH=$v$)oU_d%y?U-bR?f>Ys-+qAt0$2&|=cr{lupmp+zA&}wY3p%3diYME&b zGemJ0<@DT=rfr}@?H&5Up~`nq zFP8_8Lq0}pY=O>Uj1UeS`wJdxv{~22dODVo@y+8k&Ob@*`b}YklP_!szwfZO1hICf zT=eD3BJs&IeTjTY&_qz?8F^AxXbkA~j3cc_Pbe{FLHS2&vch2r;w3TI7KREfHOrH+ z8XSB3s{(u+@;DK9P!F?5jcI2iQYX^G^pv?lSQjEuyqNxBN(rY(Uj-x zsx9am`1}yMt!3)bps4dNSVY)D6?@356A_$3L|~%-wWP4t_63R?kHlCFA=AqBD^Y#! zWM1hb5?d1ZHt_5@^c-Ir53h?3IeQ1#xno{e;gT!K&)ll2;D22Fx2Bfxb;jrinAxOB zb1P;k$kO@U415z(hDfLaG_tEyyd_#s2wtV7i^ZF!$@?iCi^X6!N1R>W)#;m`bKZ{* z3FU=--*3bbJ})zO}PjzsqkS^rw)CB3YS!a5q8EJD@M1PjXOa~joNWw6XadvA9?Zj zKGi&TBA3W*4)zwC$zzfVyIWqdvU(6VP%;g2_;W2w$M4_RG%$G@~-QQLGuOkdD=`cv)gnplX?Bmi1uQFqV6%JxXSg5-( zF;DhFw#G)1jI+$WD<+;YoiP4MCpksBs%6INK=*!#P@nvj^QFb-ITg!#V0~ku4rsB2Ii7ez{u{Cik1aCuL;_eA~2c9C3bJ9-EY7`7&mawCdwf zChMAqgWO|Du>#OrAQ3w#y)VThIibq*aG*qw?SlqkSYa)8G2z+PP0rH4Pa0B8wI9QY zbq0?Df7BKGh8O5>nvM(ean&4xY(9OXGW;FYV$pS6*pCrgl0^&0QOy_$6wq9Z*yCMUfov=OHY4$*vZ& zgNdt+VTDV#8oPPsc+^h`IG*0tDa@JcpBgsW(YshJi2wf)d#~I(>#MB3!MUFY%d z5$AQnj4`^DrB-1rij8N9QUpt6ld*fWi&4Wo7Q2FFO|SB$;o+>Vka+JqbkygKlqVtc z2MMX(GXk#QBfD%V-`0|5#`UGexa?>gJx8@vXO;n+!bCj z82w1NKdmb|=UrmqR9?am;pcKg;?1ck!2ipGw_4ky=~Y#zYxMN(E5S|Y^@u;$LP(n6 z;mFxFZN#7+K`*`ChDA=8KACR(HqXi;^evJv(EYZo^`H4u3b+{%z5)rp@u$U(zIg?; znnUl&&l;YYOgUu{3LgM#LnTAgjd0-Mc}Du~syNZo?3bU)f z#&Ti1m%e1C?&4qjaq!RauTUu+t?Rr(2K5oaOQs1*XpmB* z2TU$3j~|rnrW1i}!4v7b-b|(zAWKd^ayh7im z)(ajjH$9WxBa^X>gCg>{Gat~*ss$uGVCtEa)Kz1T*v2iQwKLPlwpPD8bu`~vv5X$8QFtl$f<%K2{%co-Xc z!Q;BKCTAEjtwEO>4b);)W$c@z*Xf2Gbj272Vd>>gDU6p5zZ4oMyql+1{aa>4@Zcwp z?of2(D=bpJz_M~-SxXkgeU7<$S|XD^J`nOSAUy9NMj-#rXJ+kQ+oDU7!}=~Cq{1`| z!CVPiso$>~by0qbM)vC+0gQI_R`?g&=A>AoKug854AecbywDBC(flj9m)R{N`fE5S zRCKc)aFCfD!#OK$KbgpL#3$+78&`dyatP@n0AQsnq0%>Vr6F8wEm0jh{gEPtx$SCN zzJP<wZ*e}G-BKbv?&zuGsy zs;ly&%?}J}>iPg~ILT%-gut#l0_U5&v3-O771SEkUTMij^DEy(HT#~i%VyS!xVDQ{ ziIf8jVPuXt`=EHrnGbfy5fkEA2{ia3_8x2muScJmMqE76w{g*BJV#x)F!PSh0>p6Q zWi)-R_8UWU4BpQxg|3s}y(@jyOqVlSynSU))M3I>FcZRSu6`@M$w0m8+*t&#K@Tpn zNT>v&?$YpaWO9^0=sb#1T5b;!wQ#MzOBCTQY~A=z3-TM4k@8)IrMtYh?J2?dF)%~e!UIy|4(q@bj$4r9iBE4%fu1krFS4dAAoLSWHfh7k1(~K=kb;zq77z!ylh4;IiksYJ zu^@}Z2vhx&zGS~29EHuFWl0f$`JMovGABo+vtaN7v+FAR$}NIn2tLgcOVgUp-2|oo zeDrNY$-Pc+fMBM?!+jgT$)ip)>)~R9eGCLk>}XgnN!l$@D*+yk9|d>?i0PFwE1}H5 zojMBW`bm2sp#6=D+AD!mu&fKLTM}U&ymPzFu$~}KF;EA%Wkz5+-ADNs7z>%WFtM@( zSaffY^5P@`s|k@IG<$zouZtorg$Mow(HA~*)B0m&4|E~0>D{=?7$Hi<`B-;7zEKOA zrZ6+^U5&b6O}OV-?4g*@`d!aD=HhG4qZRv#tsR!17yF5o6o$(gGwrD!I9@|{Hn z1Z;b_#o{vhCN_A&NE5F`wbi1(FB<*eqHDgQLai0C1ZjT8hC?a6M$hgZ83!Jo?=QB6 z3~r}_euRUtcV$TD)4zRxO3N=^dIgvEt`Rn|+ftCsHDlF>X0xw+r_Z(pJ!nwpZ(458 zvp4~4KAV>AHUcOa+7Fo$QP!EB#)3qDwN%^_y!r97GDHXrLp3rtV~MkTuG;iZ&MxR2 zD`J!T4O9u*N6^Ny-~36|Cw_TMHupl$L}qu>lRlrDjk`nMOYf&hfsb23ZM5pY|73QM zk0Q%v>=~NA(Ql;qx1c{Skm^tbyY&$=rY}0B4pn1hoJGuHuxH4R)DE{AX@2wd0IuQ$ zf;Q9Dj5K2pBvFuWvFRSPjJ~|-Y#Rx|FsY5IF@ev^CKku%=s%aw%Jvu|$ot90j(q4l znM6Ktn0okr$U4~Fv{T?uVI-WVY=B7DGmxk+{NeSKa*;~znAq+^8{6JL0h2O6`VwQJ zu1G0-VNWgEI9x$&F^*D+vVK0sR^z#6?bh^TV5kv)+_@2u9Jj)a)iE^HN61C5*3|VZ zUDVwQxfZDKzYE~!y-Kaf$C2(u-l4&wNKLSV50%!LR>0U>zF;L#jL^lTKIeh^si%ueM>Q?b0>3)J(zu8YVuEIROoPwSCsI>M}y~T_}M&_oo|6 z3(Fpo0DlnFFZ?=UN2mTWkwU{~-wAZ;Ftq)T408YU+&oAP8Ab_~+CEN2nu=z8q1@-c z7n|-47aV@OWM(=kKV|v z9ldvvKt$BJ{VX#S1n8v4j4aQrt@uUPO}WdsHg7CMN7WHWn3P4TS!+wBuB%;bSpy0` zqKl^+a=qA8p5KBJo0@%5;7!Zv8TIPH1Q^ql!DlzJw2ZRj_wzCEJZ^i4Q27DDnNF=m zOM?My*R<~#C^Jc#KG<2Uep3S+M5YYFjBSL0!!zQ zJ5|%BmnVk^YCt=FcP{H1^&hVgj}S?Q^%J<-T5LA;yg@%IRIIwonjhKP@dZvKywmdF4L}Kp@W8WSyUaH z93Ln~_uLZ%IT3D|&yRjS(l9@rv%C)1KPz5N)@ae+xXvJ-?rsj7_u~5^-Sj+6^VcdRGXNs?96ckN`yQ`3p3URrsedL~GM9%-{>s;KSTH7$bW*o+GJ0+b{iqA(g z>?k3m)K_+j{V6hLluJU5)1HLpKz3zIN{2~eDiLkx9ELPA2#K0XV?xZt)(nFoH0L$@ z{k}h7uYX`&*IMgc@B7@(@4g?}j;c2-%}VIFHTGn!YRo~8fT*R!Y|)I~AcpOIFxbMp zkezj`2jiX@=m6;oS&7IjGpO)BJ6P3h5sM6yIZ*Is!2Z7~!>NTr3>DP)2)aOBNThO( z{OPRQN{uK-orUQM^E3@bKMuh9fLF7Ti=uD8@+xsc-v25wS5WRWeUKO8+YAmlxhw-) zj%}*U9}0OgPlIZ&7H?VuVIN|U;H?#kgyS-z>8e;wtWiUi3kH-DS@Z;K91B--MM6DDf|m#+?-R2(<~2;LreH@}79Q|XyffXD zgz$eV@UnG7$b!>6HM@VKgEEtWU3axN6<$Lgp$qejM+lr*22T4v%Ri zB=fcAxW)V?SHAsR3M<))8!1`>N4L}$^jMYo(y{<#f^>P>$V%NK^+>McLkto^(c~-g zcjf>n6>F&t2-9X?zNbAZfPZIv*m^!LL$bDaG7M|2cX4sc$@96dw`|_SH@avntE%1U z5%g)wKak^DFysSL(S{XFouy;z1Hzt7&}^~Bs>$9VU4`#Ce)m+^7awhs{r7@LlKOQU z3wTi-VA62$)v}Q2n<lcO~@mk2e(4Q1_52Yef}oN;$5|WEsrD7Bfr7pAA%bX zhtiS_AoAYD?br5!ws&qV@SrMD`l{dqixKwPO@yzlI4rx(k$}J45mn^k>QzW!ojj5z z=dVAckqWg{r=#>plC{#ZN&hx+3hAlVJpr1LkyE)h1b6SK6Hr2SKAp^Iev-!&8lb3J zyNOPuZ*^KzUp+7fg=dHF+{L_O2~C%;L5xZO1z~zh&GEv>UQ9>Nynt|uy^po_$wAbb__9LAc3T^lxfw$2Yv>n zf;FbU?to8;GNmL1QYNiH!v&}4n-r_f1O77(&z7shHq$LZ-r}kvR>KxqToDUNbyf^{ zP*5jHouk_)wGX05aBQVx{->_JwQL zV}|Q)&Gu}No||yCSTFs@wnT&h>Ihlz4Rty&eY=mtC66yOOA=p>)UR)3+9sC)^TZ=D1 z^YKVTTTBOWc!SGT7T=9XU6XNk%f0HYuGaBh7t$5rxn7w8t7Z0PU;LpGutkbqzj4`p zcheO&aNjk&8WgkPuxZyNOC5G;b^PU*Ge3gO`km)#qs&1|#@2HoEl*oCl^jp`*$n2h zsF@2Z5~9R%bJ=n&&;8=|nJRXQixw`6)o?AGS-;+AtgXM1)B-zlryHwrI{9Xd-$jwS zcT+=c?$wcYM-xvtMw~bOl*>j#xB=TUv`z6$6LSQ9ltz1Im=ZpyGO~#RIX3r^g6+a> zRlLGgC7k_9H+E8ACEsM@hcDCpbl7np-;_R|dL894;6UGf8v) zQAgl=uI0=gr*7{!W6+=95vVXV2?ql#1V)+uYGR@~e~}goH#xsYQe#HDebQxxc=R)f z0rNXF!hOpWEB}|N2$mUi%+#@BWv-HD^RUk_P!~$pZm7_56jr9%eM%o!=f9}TF1^q_A qDdg92c1+MK1k~xT!T+aD#TqTMT$VWbbl^7#TnGIE_Eq~vWd05G0k)C= literal 0 HcmV?d00001 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index af7f8ae7..24d5b94e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, Suspense, lazy, useRef } from 'react'; +import React, { useState, useEffect, Suspense, lazy, useCallback, useRef } from 'react'; import { Route, Routes, useNavigate, useLocation, Navigate, BrowserRouter } from 'react-router-dom'; import { StaticRouter } from 'react-router-dom/server'; import { HelmetProvider } from 'react-helmet-async'; @@ -36,6 +36,9 @@ const Dashboard = lazy(() => import('@/modules/user/views/Dashboard').then((modu const VerifyEmail = lazy(() => import('@/modules/auth/views/VerifyEmail').then((module) => ({ default: module.VerifyEmail }))); const ResetPassword = lazy(() => import('@/modules/auth/views/ResetPassword').then((module) => ({ default: module.ResetPassword }))); const MfaVerify = lazy(() => import('@/modules/auth/views/MfaVerify').then((module) => ({ default: module.MfaVerify }))); +const LauncherAuth = lazy(() => import('@/modules/auth/views/LauncherAuth').then((module) => ({ default: module.LauncherAuth }))); +const LauncherPage = lazy(() => import('@/modules/launcher/views/LauncherPage').then((module) => ({ default: module.LauncherPage }))); +const WorldModListView = lazy(() => import('@/modules/worldlist/views/WorldModListView').then((module) => ({ default: module.WorldModListView }))); const CreateProject = lazy(() => import('@/modules/project/views/CreateProject').then((module) => ({ default: module.CreateProject }))); const ProjectEditorView = lazy(() => import('@/modules/project/views/ProjectEditor').then((module) => ({ default: module.ProjectEditorView }))); const AdminPanel = lazy(() => import('@/modules/admin/views/AdminPanel').then((module) => ({ default: module.AdminPanel }))); @@ -44,39 +47,39 @@ const SwaggerDocs = lazy(() => import('@/modules/core/views/SwaggerDocs').then(( const RouteLoading = () =>

    ; +type FavoriteToggleOptions = { + onError?: () => void; +}; + +const setProjectLikedState = (user: User, projectId: string, liked: boolean): User => { + const likedProjectIds = user.likedProjectIds || []; + const alreadyLiked = likedProjectIds.includes(projectId); + + if (alreadyLiked === liked) return user; + + return { + ...user, + likedProjectIds: liked + ? [...likedProjectIds, projectId] + : likedProjectIds.filter(likedProjectId => likedProjectId !== projectId) + }; +}; + const hasLikelyAuthCookie = () => { if (typeof document === 'undefined') return false; const cookies = document.cookie || ''; return /(?:^|;\s*)(SESSION|JSESSIONID|XSRF-TOKEN)=/.test(cookies); }; -const projectRouteBase = (pathname: string) => { - const match = pathname.match(/^\/(project|mod|modpack|world)\/[^/]+/i); - return match ? match[0].toLowerCase() : ''; -}; - -const isProjectModalSubroute = (pathname: string) => ( - /^\/(project|mod|modpack|world)\/[^/]+\/(download|changelog|gallery)\/?$/i.test(pathname) -); - const ScrollToTop = () => { const { pathname } = useLocation(); - const previousPathRef = useRef(null); + const previousPathnameRef = useRef(undefined); useEffect(() => { - const previousPath = previousPathRef.current; - const previousProjectBase = previousPath ? projectRouteBase(previousPath) : ''; - const nextProjectBase = projectRouteBase(pathname); - const isSameProjectModalTransition = Boolean( - previousPath - && previousProjectBase - && previousProjectBase === nextProjectBase - && (isProjectModalSubroute(previousPath) || isProjectModalSubroute(pathname)) - ); - - previousPathRef.current = pathname; - - if (isSameProjectModalTransition) { + const previousPathname = previousPathnameRef.current; + previousPathnameRef.current = pathname; + + if (previousPathname && SiteRoutes.isSameProjectModalContext(previousPathname, pathname)) { return; } @@ -94,6 +97,8 @@ const AppContent: React.FC = () => { const [showOnboarding, setShowOnboarding] = useState(false); const [isDarkMode, setIsDarkMode] = useState(true); const [statusModal, setStatusModal] = useState<{ type: 'success' | 'error' | 'warning' | 'info'; title: string; msg: string } | null>(null); + const userRef = useRef(null); + const pendingFavoriteIdsRef = useRef>(new Set()); const navigate = useNavigate(); const location = useLocation(); @@ -106,7 +111,9 @@ const AppContent: React.FC = () => { const decodedError = decodeURIComponent(oauthError).replace(/\+/g, ' '); setGlobalError(decodedError); clearPendingSignInMethod(); - navigate(location.pathname, { replace: true }); + params.delete('oauth_error'); + const remainingSearch = params.toString(); + navigate(`${location.pathname}${remainingSearch ? `?${remainingSearch}` : ''}`, { replace: true }); } }, [location, navigate]); @@ -132,7 +139,11 @@ const AppContent: React.FC = () => { }); }; - const fetchUser = async () => { + useEffect(() => { + userRef.current = user; + }, [user]); + + const fetchUser = useCallback(async () => { if (!hasLikelyAuthCookie()) { setLoadingAuth(false); return; @@ -141,26 +152,30 @@ const AppContent: React.FC = () => { try { const res = await api.get(`/user/me?t=${Date.now()}`); if (res.data) { - setUser(normalizeUser(res.data)); + const normalizedUser = normalizeUser(res.data); + userRef.current = normalizedUser; + setUser(normalizedUser); completeSignInMethod(); if ((res.data as any).is_new_account) { setShowOnboarding(true); } } } catch (e: any) { + userRef.current = null; setUser(null); } finally { setLoadingAuth(false); } - }; + }, []); useEffect(() => { fetchUser(); - }, []); + }, [fetchUser]); const handleLogout = async () => { try { await api.post('/auth/logout'); + userRef.current = null; setUser(null); setShowOnboarding(false); navigate(SiteRoutes.home()); @@ -172,20 +187,37 @@ const AppContent: React.FC = () => { const handleNavigate = (page: string) => { navigate(page === 'home' ? SiteRoutes.home() : `/${page}`); }; const handleUserClick = (userId: string, username?: string) => { navigate(SiteRoutes.creator(userId, username)); }; - const handleToggleFavorite = async (id: string) => { - if (!user) return; - const previousUser = user; - const likedProjectIds = user.likedProjectIds || []; - const isLiked = likedProjectIds.includes(id); - const newProjectLikes = isLiked ? likedProjectIds.filter(lid => lid !== id) : [...likedProjectIds, id]; - setUser({ ...user, likedProjectIds: newProjectLikes }); - try { - await api.post(`/projects/${id}/favorite`); - } catch (e) { - setUser(previousUser); - fetchUser(); - } - }; + const handleToggleFavorite = useCallback((id: string, options?: FavoriteToggleOptions) => { + if (!id || pendingFavoriteIdsRef.current.has(id)) return undefined; + + const currentUser = userRef.current; + if (!currentUser) return undefined; + + const wasLiked = (currentUser.likedProjectIds || []).includes(id); + const nextLiked = !wasLiked; + const nextUser = setProjectLikedState(currentUser, id, nextLiked); + + userRef.current = nextUser; + pendingFavoriteIdsRef.current.add(id); + setUser(nextUser); + + api.post(`/projects/${id}/favorite`) + .catch(() => { + setUser(latestUser => { + if (!latestUser || latestUser.id !== currentUser.id) return latestUser; + const revertedUser = setProjectLikedState(latestUser, id, wasLiked); + userRef.current = revertedUser; + return revertedUser; + }); + options?.onError?.(); + fetchUser(); + }) + .finally(() => { + pendingFavoriteIdsRef.current.delete(id); + }); + + return nextLiked; + }, [fetchUser]); const handleDownload = (id: string) => { if (!downloadedSessionIds.has(id)) setDownloadedSessionIds(prev => new Set(prev).add(id)); }; const onShowStatus = (type: 'success' | 'error' | 'warning' | 'info', title: string, msg: string) => setStatusModal({ type, title, msg }); @@ -314,6 +346,9 @@ const AppContent: React.FC = () => { } /> } /> } /> + } /> + } /> + } /> } /> } /> diff --git a/frontend/src/components/ui/MarkdownRichRenderer.tsx b/frontend/src/components/ui/MarkdownRichRenderer.tsx index 8bd203c5..298f7f04 100644 --- a/frontend/src/components/ui/MarkdownRichRenderer.tsx +++ b/frontend/src/components/ui/MarkdownRichRenderer.tsx @@ -1,4 +1,4 @@ -import React, { Suspense, lazy, useEffect, useState } from 'react'; +import React, { Suspense, lazy, useEffect, useRef, useState } from 'react'; import ReactMarkdown from 'react-markdown'; import rehypeRaw from 'rehype-raw'; import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; @@ -99,6 +99,44 @@ const CodeFallback = ({ content }: { content: string }) => ( ); +const fallbackCopyText = (content: string) => { + if (typeof document === 'undefined') { + return false; + } + + const textarea = document.createElement('textarea'); + textarea.value = content; + textarea.setAttribute('readonly', ''); + textarea.style.position = 'fixed'; + textarea.style.top = '-9999px'; + textarea.style.left = '-9999px'; + textarea.style.opacity = '0'; + document.body.appendChild(textarea); + textarea.select(); + textarea.setSelectionRange(0, textarea.value.length); + + const legacyDocument = document as unknown as { execCommand?: (command: string) => boolean }; + + try { + return legacyDocument.execCommand?.('copy') ?? false; + } finally { + document.body.removeChild(textarea); + } +}; + +const copyText = async (content: string) => { + try { + if (navigator.clipboard?.writeText) { + await navigator.clipboard.writeText(content); + return true; + } + } catch { + // Fall through to the textarea fallback for non-secure or embedded browser contexts. + } + + return fallbackCopyText(content); +}; + const MermaidFallback = ({ content }: { content: string }) => (
    @@ -147,9 +185,16 @@ const DeferredMermaidChart = ({ content }: { content: string }) => { const CodeBlock = ({ node: _node, inline, className, children, ...props }: any) => { const [copied, setCopied] = useState(false); + const resetTimerRef = useRef(null); const match = /language-(\w+)/.exec(className || ''); const isBlock = !inline && (match || String(children).includes('\n')); + useEffect(() => () => { + if (resetTimerRef.current !== null) { + window.clearTimeout(resetTimerRef.current); + } + }, []); + if (isBlock) { const lang = match ? match[1] : 'text'; const content = String(children).replace(/\n$/, ''); @@ -158,10 +203,20 @@ const CodeBlock = ({ node: _node, inline, className, children, ...props }: any) return ; } - const handleCopy = () => { - navigator.clipboard.writeText(content); + const handleCopy = async () => { + const copiedToClipboard = await copyText(content); + if (!copiedToClipboard) { + return; + } + setCopied(true); - setTimeout(() => setCopied(false), 2000); + if (resetTimerRef.current !== null) { + window.clearTimeout(resetTimerRef.current); + } + resetTimerRef.current = window.setTimeout(() => { + setCopied(false); + resetTimerRef.current = null; + }, 2000); }; return ( @@ -169,7 +224,8 @@ const CodeBlock = ({ node: _node, inline, className, children, ...props }: any)
    {lang} diff --git a/frontend/src/data/seo-constants.ts b/frontend/src/data/seo-constants.ts index 12cc186a..b08c4473 100644 --- a/frontend/src/data/seo-constants.ts +++ b/frontend/src/data/seo-constants.ts @@ -111,6 +111,58 @@ export const ROUTE_SEO: Record = { }, ], }, + '/launcher': { + title: 'Modtale Launcher | Native Hytale Mod Manager', + h1: 'Modtale Launcher', + description: 'Download the Modtale Launcher for Windows, macOS, and Linux. Install, update, and manage Hytale projects with a native launcher built for Modtale releases.', + keywords: 'modtale launcher, hytale launcher, hytale mod manager, hytale mods launcher, download hytale mods, modtale download', + intro: 'The Modtale Launcher is a native desktop app for browsing Modtale projects, installing compatible Hytale releases, resolving dependencies, and keeping your local library ready to play.', + contentBlocks: [ + { + title: 'Desktop Launcher Packages', + body: 'Download a self-contained Modtale Launcher package for your desktop platform and manage Hytale mods, plugins, worlds, assets, and modpacks from one app.', + }, + { + title: 'Install Compatible Project Releases', + body: 'The launcher works with Modtale project metadata to help players choose compatible builds, review dependencies, and install projects into the right local Hytale folder.', + }, + { + title: 'Built Alongside the Modtale Platform', + body: 'Launcher releases are published from the same open-source Modtale project, with package formats for Windows, macOS, and Linux.', + }, + ], + relatedLinks: [ + { + href: '/mods', + label: 'Browse Hytale Projects', + description: 'Explore projects before opening them in the launcher.', + }, + { + href: '/modpacks', + label: 'Hytale Modpacks', + description: 'Find curated collections that benefit from dependency-aware installs.', + }, + { + href: '/upload', + label: 'Publish a Project', + description: 'Share your Hytale work with players on Modtale.', + }, + ], + faq: [ + { + question: 'Does the Modtale Launcher need Java installed?', + answer: 'No. The native launcher packages embed their own runtime, so players do not need to install a separate JDK or JRE.', + }, + { + question: 'Which desktop platforms does the Modtale Launcher support?', + answer: 'Modtale publishes launcher packages for Windows, macOS, and Linux. The launcher page detects your platform and links to the best available release asset when GitHub release metadata is available.', + }, + { + question: 'What does the launcher manage?', + answer: 'The launcher can browse Modtale projects, install compatible project releases, help with dependencies, check installed projects for updates, and connect to Hytale launch flows.', + }, + ], + }, '/status': { title: 'System Status | Modtale', h1: 'Modtale System Status', diff --git a/frontend/src/index.css b/frontend/src/index.css index c999efe1..ea35a014 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,3 +1,5 @@ +@import '@fontsource-variable/inter'; + @tailwind base; @tailwind components; @tailwind utilities; @@ -19,6 +21,7 @@ margin: 0; padding: 0; min-height: 100vh; + letter-spacing: 0; } #root { diff --git a/frontend/src/modules/admin/components/PlatformAnalytics.tsx b/frontend/src/modules/admin/components/PlatformAnalytics.tsx index 770f55c4..6c257eff 100644 --- a/frontend/src/modules/admin/components/PlatformAnalytics.tsx +++ b/frontend/src/modules/admin/components/PlatformAnalytics.tsx @@ -24,7 +24,7 @@ const SummaryCard = ({ title, value, subValue, trend, icon: Icon, color, isPerce

    {title}

    -
    +
    {value}{isPercent && %}
    {subValue &&
    {subValue}
    } @@ -143,7 +143,7 @@ export function PlatformAnalytics() { )}
    -

    Platform Analytics

    +

    Platform Analytics

    Monitor platform-wide statistics and growth.

    diff --git a/frontend/src/modules/admin/components/UserManagement.tsx b/frontend/src/modules/admin/components/UserManagement.tsx index 68650b9a..5d4c2476 100644 --- a/frontend/src/modules/admin/components/UserManagement.tsx +++ b/frontend/src/modules/admin/components/UserManagement.tsx @@ -397,7 +397,7 @@ export function UserManagement({ setStatus }: { setStatus: (s: any) => void }) { {foundUser.username}
    -

    {foundUser.username}

    +

    {foundUser.username}

    Active Roles
    diff --git a/frontend/src/modules/admin/components/VerificationQueue.tsx b/frontend/src/modules/admin/components/VerificationQueue.tsx index 5ad38e77..b4ab6064 100644 --- a/frontend/src/modules/admin/components/VerificationQueue.tsx +++ b/frontend/src/modules/admin/components/VerificationQueue.tsx @@ -83,7 +83,7 @@ export const VerificationQueue: React.FC = ({
    -

    +

    {mod.title} {mod.classification}

    diff --git a/frontend/src/modules/admin/views/AdminPanel.tsx b/frontend/src/modules/admin/views/AdminPanel.tsx index beb4f7da..4652d53c 100644 --- a/frontend/src/modules/admin/views/AdminPanel.tsx +++ b/frontend/src/modules/admin/views/AdminPanel.tsx @@ -211,7 +211,7 @@ export function AdminPanel({ currentUser }: AdminPanelProps) { {activeTab === 'verification' && (
    -

    Verification Queue

    +

    Verification Queue

    Review pending projects and updates.

    {queueError && ( @@ -232,7 +232,7 @@ export function AdminPanel({ currentUser }: AdminPanelProps) { {activeTab === 'reports' && (
    -

    Report Queue

    +

    Report Queue

    Handle content violations and user reports.

    {reportsError && ( @@ -259,7 +259,7 @@ export function AdminPanel({ currentUser }: AdminPanelProps) { {activeTab === 'projects' && isSuperAdmin && (
    -

    Project Management

    +

    Project Management

    Manage, unlist, or delete any project.

    @@ -269,7 +269,7 @@ export function AdminPanel({ currentUser }: AdminPanelProps) { {activeTab === 'users' && isSuperAdmin && (
    -

    User Management

    +

    User Management

    Manage roles, tiers, and user statuses.

    @@ -279,7 +279,7 @@ export function AdminPanel({ currentUser }: AdminPanelProps) { {activeTab === 'logs' && isSuperAdmin && (
    -

    Audit Logs

    +

    Audit Logs

    Review all administrative actions.

    diff --git a/frontend/src/modules/admin/views/Review.tsx b/frontend/src/modules/admin/views/Review.tsx index fc0f8620..f51c14a3 100644 --- a/frontend/src/modules/admin/views/Review.tsx +++ b/frontend/src/modules/admin/views/Review.tsx @@ -314,7 +314,7 @@ export const Review: React.FC = ({ reviewingProject, onClose, onApp
    -

    {mod.title}

    +

    {mod.title}

    {mod.id} @@ -857,7 +857,7 @@ export const Review: React.FC = ({ reviewingProject, onClose, onApp
    -

    +

    {isNewProject ? "Approve Project?" : "Approve Update?"}

    diff --git a/frontend/src/modules/auth/api/authClient.ts b/frontend/src/modules/auth/api/authClient.ts index 81f30d62..13fcc278 100644 --- a/frontend/src/modules/auth/api/authClient.ts +++ b/frontend/src/modules/auth/api/authClient.ts @@ -103,5 +103,8 @@ export const authClient = { }, validateMfaLogin: async (data: { pre_auth_token: string | null; code: string }) => { return await api.post('/auth/mfa/validate-login', data); + }, + issueLauncherAuthCode: async (data: { redirectUri: string; state?: string | null }) => { + return await api.post('/auth/launcher/issue', data); } }; diff --git a/frontend/src/modules/auth/components/SignInModal.tsx b/frontend/src/modules/auth/components/SignInModal.tsx index 6a6b5564..355f6deb 100644 --- a/frontend/src/modules/auth/components/SignInModal.tsx +++ b/frontend/src/modules/auth/components/SignInModal.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { X, Github, ArrowRight, Loader2, ArrowLeft, CheckCircle2 } from 'lucide-react'; import { DiscordBrandIcon, GitLabBrandIcon, GoogleBrandIcon } from '@/components/ui/icons/BrandIcons'; import { useLocation, useNavigate } from 'react-router-dom'; -import { BACKEND_URL, extractApiErrorMessage } from '@/utils/api'; +import { API_BASE_URL, extractApiErrorMessage } from '@/utils/api'; import { StatusModal } from '@/components/ui/StatusModal'; import { ModalPortal } from '@/components/ui/ModalPortal'; import { useToast } from '@/components/ui/Toast'; @@ -34,7 +34,7 @@ export function SignInModal({ isOpen, onClose }: SignInModalProps) { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [loading, setLoading] = useState(false); - const [statusModal, setStatusModal] = useState<{ title: string; msg: string } | null>(null); + const [statusModal, setStatusModal] = useState<{ type?: 'error' | 'info'; title: string; msg: string } | null>(null); const [lastSignInMethod, setLastSignInMethod] = useState(null); useEffect(() => { @@ -79,7 +79,10 @@ export function SignInModal({ isOpen, onClose }: SignInModalProps) { const handleOAuthLogin = (provider: OAuthSignInMethod) => { stageSignInMethod(provider); - window.location.href = `${BACKEND_URL}/oauth2/authorization/${provider}`; + const params = new URLSearchParams(); + if (redirectTo) params.set('redirect', redirectTo); + const query = params.toString(); + window.location.href = `${API_BASE_URL}/auth/oauth/${provider}${query ? `?${query}` : ''}`; }; const handleSubmit = async (e: React.FormEvent) => { @@ -151,20 +154,20 @@ export function SignInModal({ isOpen, onClose }: SignInModalProps) {

    {statusModal && ( setStatusModal(null)} /> )} -
    e.stopPropagation()}> +
    e.stopPropagation()}>
    -

    +

    {mode === 'signin' ? 'Welcome Back' : (mode === 'register' ? 'Create Account' : 'Reset Password')}

    @@ -182,8 +185,10 @@ export function SignInModal({ isOpen, onClose }: SignInModalProps) { <>

    + +
    +
    +
    + ); +} diff --git a/frontend/src/modules/core/components/Navbar.tsx b/frontend/src/modules/core/components/Navbar.tsx index 1e029ec3..8e65f8c0 100644 --- a/frontend/src/modules/core/components/Navbar.tsx +++ b/frontend/src/modules/core/components/Navbar.tsx @@ -1,5 +1,5 @@ import React, { lazy, Suspense, useState, useRef, useEffect } from 'react'; -import { Menu, X, Upload, LayoutDashboard, User as UserIcon, LogOut, Shield, Users, LogIn, Code2, ChevronDown, LayoutGrid } from 'lucide-react'; +import { Menu, X, Upload, LayoutDashboard, User as UserIcon, LogOut, Shield, Users, LogIn, ChevronDown, LayoutGrid, MonitorDown } from 'lucide-react'; import { Link, useLocation, useNavigate } from 'react-router-dom'; import { AnimatedThemeToggler } from '@/components/ui/AnimatedThemeToggler'; import { useMobile } from '@/context/MobileContext'; @@ -163,15 +163,15 @@ export const Navbar: React.FC = ({
    - - API + + Launcher {user && ( <> @@ -316,7 +316,7 @@ export const Navbar: React.FC = ({
    - setIsMobileMenuOpen(false)} className="flex items-center p-3 rounded-lg hover:bg-slate-50 dark:hover:bg-white/5 font-bold text-slate-700 dark:text-slate-200 text-left"> API + setIsMobileMenuOpen(false)} className="flex items-center p-3 rounded-lg hover:bg-slate-50 dark:hover:bg-white/5 font-bold text-slate-700 dark:text-slate-200 text-left"> Launcher {user && ( <> setIsMobileMenuOpen(false)} className="flex items-center p-3 rounded-lg hover:bg-slate-50 dark:hover:bg-white/5 font-bold text-slate-700 dark:text-slate-200 text-left"> Dashboard diff --git a/frontend/src/modules/core/views/ApiDocs.tsx b/frontend/src/modules/core/views/ApiDocs.tsx index 1a9a0ba3..7d816f74 100644 --- a/frontend/src/modules/core/views/ApiDocs.tsx +++ b/frontend/src/modules/core/views/ApiDocs.tsx @@ -1387,7 +1387,7 @@ export const ApiDocs: React.FC = () => {
    -

    +

    Modtale API v1

    diff --git a/frontend/src/modules/home/components/FeaturePreviews.tsx b/frontend/src/modules/home/components/FeaturePreviews.tsx index f7a72b53..81e42e18 100644 --- a/frontend/src/modules/home/components/FeaturePreviews.tsx +++ b/frontend/src/modules/home/components/FeaturePreviews.tsx @@ -396,7 +396,7 @@ const PreviewSummaryCard = ({ title, value, subValue, trend, icon: Icon, color,

    {title}

    -
    +
    {value}{isPercent && %}
    {subValue &&
    {subValue}
    } @@ -715,7 +715,7 @@ const CompactFeaturedModCard = ({ project }: { project: Project }) => {
    -

    +

    {project.title}

    @@ -771,7 +771,7 @@ export const TrendingProjectsSection = ({
    -

    +

    Trending

    @@ -823,7 +823,7 @@ export const NewReleasesSection = ({
    -

    +

    New Releases

    @@ -861,7 +861,7 @@ export const ModpackPreviewSection = ({ randomProject }: { randomProject?: Proje return (
    -

    +

    Modpacks, Upgraded

    @@ -883,7 +883,7 @@ export const DirectDownloadsSection = () => { return (

    -

    +

    Direct Downloads

    @@ -901,11 +901,66 @@ export const DirectDownloadsSection = () => { ); }; +export const LauncherPreviewSection = () => { + return ( +

    +
    +

    + Modtale Launcher +

    +

    + Native installs, updates, and Hytale launch flows. +

    +

    + Download a desktop launcher that can browse Modtale, install compatible project releases, prompt for dependencies, and keep your local Hytale library organized. +

    +
    + +
    +
    + +
    +
    +
    +
    + + + + Launcher preview +
    + Modtale Launcher browsing a project page +
    +
    + {['Browse projects', 'Resolve dependencies', 'Check updates'].map((item) => ( +
    +
    + ))} +
    +
    +
    + ); +}; + export const SmartDependenciesSection = ({ randomProject, previewProjects }: { randomProject?: Project; previewProjects?: Project[] }) => { return (
    -

    +

    Smart Dependencies

    @@ -927,7 +982,7 @@ export const ProjectAnalyticsSection = ({ showConversionRate = true }: { showCon return (

    -

    +

    Project Analytics

    @@ -949,7 +1004,7 @@ export const CommunityThreadsSection = ({ project, currentUser }: { project?: Pr return (

    -

    +

    Comment Threads

    @@ -971,7 +1026,7 @@ export const RealTimeAlertsSection = () => { return (

    -

    +

    Push Notifications

    @@ -993,7 +1048,7 @@ export const AccountPreferencesSection = () => { return (

    -

    +

    Notification Control

    diff --git a/frontend/src/modules/home/components/HeroMarquee.tsx b/frontend/src/modules/home/components/HeroMarquee.tsx index 48cc5b12..5eac3c84 100644 --- a/frontend/src/modules/home/components/HeroMarquee.tsx +++ b/frontend/src/modules/home/components/HeroMarquee.tsx @@ -57,7 +57,7 @@ export const FeaturedModCard = memo(({ project, priority = false }: { project: P

    -

    +

    {project.title}

    diff --git a/frontend/src/modules/home/views/Home.tsx b/frontend/src/modules/home/views/Home.tsx index 365655c7..b6159e5f 100644 --- a/frontend/src/modules/home/views/Home.tsx +++ b/frontend/src/modules/home/views/Home.tsx @@ -1,8 +1,7 @@ import React, { useState, useEffect, useMemo, useRef } from 'react'; import { Link } from 'react-router-dom'; import { Helmet } from 'react-helmet-async'; -import { Search, Upload, Github, Code } from 'lucide-react'; -import '@fontsource-variable/inter'; +import { Search, Upload, Github, Code, MonitorDown } from 'lucide-react'; import { api } from '@/utils/api'; import { ROUTE_SEO } from '@/data/seo-constants'; import type { Project, User } from '@/types'; @@ -16,6 +15,7 @@ import { NewReleasesSection, ModpackPreviewSection, DirectDownloadsSection, + LauncherPreviewSection, SmartDependenciesSection, ProjectAnalyticsSection, CommunityThreadsSection, @@ -593,7 +593,6 @@ export const Home: React.FC<{ return (
    {homeSeo.title} @@ -1037,7 +1036,7 @@ export const Home: React.FC<{ />
    -

    +

    The Hytale
    Community
    Repository @@ -1063,26 +1062,33 @@ export const Home: React.FC<{

    - + {formatMetric(stats.totalProjects)} Projects
    + +
    + {list.mods.map((item, index) => ( + + ))} +
    + + ); +}; + +export default WorldModListView; diff --git a/frontend/src/pages/[...all].astro b/frontend/src/pages/[...all].astro index b0f788c5..89a36856 100644 --- a/frontend/src/pages/[...all].astro +++ b/frontend/src/pages/[...all].astro @@ -21,7 +21,6 @@ import { } from '../utils/schema'; import { BACKEND_URL } from '@/utils/api.ts'; -const { all } = Astro.params; const url = Astro.url; const path = url.pathname; const cleanPath = normalizeSeoPath(path); @@ -84,13 +83,14 @@ const isBot = isBotUserAgent(userAgent); const pathSegments = cleanPath.split('/').filter(Boolean); const isProjectRoute = pathSegments.length >= 2 && ['project', 'mod', 'modpack', 'world'].includes(pathSegments[0]); -const identifier = isProjectRoute ? pathSegments[1] : (all ? all.split('/').pop() : ''); -const projectId = identifier ? SiteRoutes.extractId(identifier) : ''; const wikiSegmentIndex = isProjectRoute ? pathSegments.indexOf('wiki', 2) : -1; const wikiPagePath = wikiSegmentIndex >= 0 ? pathSegments.slice(wikiSegmentIndex + 1).join('/') : ''; -let image = (isProjectRoute && identifier) - ? `${BACKEND_URL}/api/v1/og/project/${projectId}.png` +const projectRouteKey = isProjectRoute ? SiteRoutes.projectRouteKeyFromPath(cleanPath) : ''; +const projectLookupKey = projectRouteKey ? SiteRoutes.extractId(projectRouteKey) : ''; + +let image = (isProjectRoute && projectLookupKey) + ? `${BACKEND_URL}/api/v1/og/project/${projectLookupKey}.png` : 'https://modtale.net/assets/logo.svg'; let classification = null; @@ -225,14 +225,18 @@ if (classification) { } else { jsonLd = baseSchemas; } -} else if (isBot && identifier && isProjectRoute) { +} else if (isBot && projectLookupKey && isProjectRoute) { try { - const modData = await fetchJsonWithTimeout(`${BACKEND_URL}/api/v1/projects/${projectId}`, 2500); + const modData = await fetchJsonWithTimeout(`${BACKEND_URL}/api/v1/projects/${projectLookupKey}`, 2500); if (modData) { const projectUrl = SiteRoutes.project(modData); - if (cleanPath !== normalizeSeoPath(projectUrl)) { - return Astro.redirect(projectUrl, 301); + const canonicalBasePath = normalizeSeoPath(projectUrl); + const currentBasePath = normalizeSeoPath(SiteRoutes.projectBasePathFromPath(cleanPath)); + + if (currentBasePath && currentBasePath !== canonicalBasePath) { + const canonicalPath = cleanPath.replace(currentBasePath, canonicalBasePath); + return Astro.redirect(canonicalPath, 301); } initialData = modData; @@ -279,12 +283,12 @@ if (ssrSuccessfullyCompleted && (isHome || isStaticBrowseRequest)) { Astro.response.headers.set('Cache-Control', 'public, max-age=0, s-maxage=0, must-revalidate'); } -const projectBootstrapUrl = !initialData && isProjectRoute && projectId ? `${BACKEND_URL}/api/v1/projects/${projectId}` : undefined; -const wikiBootstrap = wikiSegmentIndex >= 0 && projectId +const projectBootstrapUrl = !initialData && isProjectRoute && projectLookupKey ? `${BACKEND_URL}/api/v1/projects/${projectLookupKey}` : undefined; +const wikiBootstrap = wikiSegmentIndex >= 0 && projectLookupKey ? { - projectId, - metadataUrl: `${BACKEND_URL}/api/v1/wiki/${encodeURIComponent(projectId)}`, - pageUrl: `${BACKEND_URL}/api/v1/wiki/${encodeURIComponent(projectId)}/${wikiPagePath || 'home-1'}`, + projectId: projectLookupKey, + metadataUrl: `${BACKEND_URL}/api/v1/wiki/${encodeURIComponent(projectLookupKey)}`, + pageUrl: `${BACKEND_URL}/api/v1/wiki/${encodeURIComponent(projectLookupKey)}/${wikiPagePath || 'home-1'}`, pageSlug: wikiPagePath || 'home-1', } : undefined; diff --git a/frontend/src/pages/sitemap-static.xml.ts b/frontend/src/pages/sitemap-static.xml.ts index af31f06d..f3a71515 100644 --- a/frontend/src/pages/sitemap-static.xml.ts +++ b/frontend/src/pages/sitemap-static.xml.ts @@ -5,6 +5,7 @@ const STATIC_ROUTES = [ { path: '/mods', changefreq: 'daily', priority: '0.95' }, { path: '/plugins', changefreq: 'daily', priority: '0.9' }, { path: '/modpacks', changefreq: 'daily', priority: '0.8' }, + { path: '/launcher', changefreq: 'weekly', priority: '0.85' }, { path: '/art', changefreq: 'weekly', priority: '0.75' }, { path: '/data', changefreq: 'weekly', priority: '0.75' }, { path: '/worlds', changefreq: 'daily', priority: '0.75' }, diff --git a/frontend/src/styles/theme.ts b/frontend/src/styles/theme.ts index 27e4f305..240c3410 100644 --- a/frontend/src/styles/theme.ts +++ b/frontend/src/styles/theme.ts @@ -29,7 +29,7 @@ export const theme = { buttonDanger: 'bg-red-500 hover:bg-red-600 text-white px-5 py-2.5 rounded-xl font-bold transition-colors shadow-sm disabled:opacity-50', buttonGhost: 'px-5 py-2.5 rounded-xl font-bold text-slate-600 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-white/10 transition-colors disabled:opacity-50', iconButton: 'p-2 rounded-full text-slate-400 hover:text-slate-700 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-white/10 transition-colors', - modalOverlay: 'fixed inset-0 z-[200] flex items-center justify-center bg-slate-900/45 dark:bg-slate-900/70 backdrop-blur-sm p-4 animate-in fade-in duration-200', + modalOverlay: 'fixed inset-0 z-[200] flex items-center justify-center bg-slate-950/55 dark:bg-slate-950/75 p-4 animate-in fade-in duration-200', modalContent: 'bg-white dark:bg-slate-900 border border-slate-200 dark:border-white/10 rounded-2xl shadow-2xl overflow-hidden relative flex flex-col', modalHeader: 'p-6 border-b border-slate-200 dark:border-white/10 flex justify-between items-center bg-slate-50/70 dark:bg-slate-800/55 shrink-0', modalBody: 'p-6 space-y-4 overflow-y-auto bg-transparent flex-1', diff --git a/frontend/src/utils/routes.ts b/frontend/src/utils/routes.ts index c690c3ff..3f24e5c0 100644 --- a/frontend/src/utils/routes.ts +++ b/frontend/src/utils/routes.ts @@ -1,9 +1,25 @@ +type ProjectRouteParts = { + prefix: string; + routeKey: string; + subroute: string; + segmentCount: number; +}; + export class SiteRoutes { + private static readonly PROJECT_ROUTE_PREFIXES = new Set(['project', 'mod', 'modpack', 'world']); + private static readonly PROJECT_MODAL_SUBROUTES = new Set(['download', 'changelog', 'gallery']); + static home() { return '/'; } static upload() { return '/upload'; } static admin() { return '/admin'; } + static launcher() { return '/launcher'; } static apiDocs() { return '/api-docs'; } static swaggerDocs() { return '/api-docs/swagger'; } + static list(id: string) { return `/lists/${id}`; } + static createModpackFromList(id: string) { + const params = new URLSearchParams({ type: 'MODPACK', fromList: id }); + return `/upload?${params.toString()}`; + } static login(redirectTo?: string) { const params = new URLSearchParams(); if (redirectTo) params.set('redirect', redirectTo); @@ -131,4 +147,47 @@ export class SiteRoutes { const match = param.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i); return match ? match[0] : param; } + + private static projectRouteParts(pathname: string | undefined): ProjectRouteParts | null { + if (!pathname) return null; + + const pathOnly = pathname.split(/[?#]/)[0]; + const normalizedPath = (pathOnly || '/').replace(/\/+$/, '') || '/'; + const segments = normalizedPath.split('/').filter(Boolean); + if (segments.length < 2) return null; + + const prefix = segments[0].toLowerCase(); + if (!this.PROJECT_ROUTE_PREFIXES.has(prefix)) return null; + + return { + prefix, + routeKey: segments[1], + subroute: segments[2]?.toLowerCase() || '', + segmentCount: segments.length + }; + } + + static projectRouteKeyFromPath(pathname: string | undefined) { + return this.projectRouteParts(pathname)?.routeKey || ''; + } + + static projectBasePathFromPath(pathname: string | undefined) { + const parts = this.projectRouteParts(pathname); + if (!parts) return ''; + return `/${parts.prefix}/${parts.routeKey}`; + } + + static isProjectModalRoute(pathname: string | undefined) { + const parts = this.projectRouteParts(pathname); + if (!parts) return false; + return parts.segmentCount === 3 && this.PROJECT_MODAL_SUBROUTES.has(parts.subroute); + } + + static isSameProjectModalContext(previousPathname: string | undefined, nextPathname: string | undefined) { + const previousBasePath = this.projectBasePathFromPath(previousPathname); + const nextBasePath = this.projectBasePathFromPath(nextPathname); + + if (!previousBasePath || previousBasePath !== nextBasePath) return false; + return this.isProjectModalRoute(previousPathname) || this.isProjectModalRoute(nextPathname); + } } diff --git a/frontend/tailwind.config.mjs b/frontend/tailwind.config.mjs index dfe6991b..ab21945e 100644 --- a/frontend/tailwind.config.mjs +++ b/frontend/tailwind.config.mjs @@ -20,7 +20,7 @@ export default { } }, fontFamily: { - sans: ['system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'sans-serif'], + sans: ['Inter Variable', 'Inter', 'SF Pro Text', 'Segoe UI', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Roboto', 'Helvetica Neue', 'Arial', 'sans-serif'], } }, }, diff --git a/frontend/tests/components/MarkdownRichRenderer.test.tsx b/frontend/tests/components/MarkdownRichRenderer.test.tsx index 467c4b3c..25f571f7 100644 --- a/frontend/tests/components/MarkdownRichRenderer.test.tsx +++ b/frontend/tests/components/MarkdownRichRenderer.test.tsx @@ -1,8 +1,12 @@ import { act } from 'react'; -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createRoot, type Root } from 'react-dom/client'; import { MarkdownRichRenderer } from '@/components/ui/MarkdownRichRenderer'; +vi.mock('@/components/ui/MarkdownSyntaxHighlighter', () => ({ + HighlightedCode: ({ content }: { content: string }) =>
    {content}
    +})); + describe('MarkdownRichRenderer', () => { let container: HTMLDivElement; let root: Root; @@ -71,4 +75,34 @@ describe('MarkdownRichRenderer', () => { expect(image).not.toBeNull(); expect(image?.getAttribute('src')).toBe('https://cdn.modtale.net/gallery/build.png'); }); + + it('copies markdown code block contents', async () => { + const originalClipboard = navigator.clipboard; + const writeText = vi.fn().mockResolvedValue(undefined); + Object.defineProperty(navigator, 'clipboard', { + configurable: true, + value: { writeText } + }); + + try { + await act(async () => { + root.render(); + }); + + const copyButton = container.querySelector('button[title="Copy code"]') as HTMLButtonElement | null; + expect(copyButton).not.toBeNull(); + + await act(async () => { + copyButton?.click(); + }); + + expect(writeText).toHaveBeenCalledWith('{"ok": true}'); + expect(copyButton?.textContent).toContain('Copied'); + } finally { + Object.defineProperty(navigator, 'clipboard', { + configurable: true, + value: originalClipboard + }); + } + }); }); diff --git a/frontend/tests/modules/auth/api/authClient.test.ts b/frontend/tests/modules/auth/api/authClient.test.ts index e551e849..6d6fc087 100644 --- a/frontend/tests/modules/auth/api/authClient.test.ts +++ b/frontend/tests/modules/auth/api/authClient.test.ts @@ -55,6 +55,14 @@ describe('authClient', () => { expect(mockedApi.post).toHaveBeenCalledWith('/auth/mfa/validate-login', payload); }); + it('issues launcher auth codes through the auth API', async () => { + const payload = { redirectUri: 'http://127.0.0.1:49152/callback', state: 'state-123' }; + + await authClient.issueLauncherAuthCode(payload); + + expect(mockedApi.post).toHaveBeenCalledWith('/auth/launcher/issue', payload); + }); + it('normalizes signin payloads from both camelCase and snake_case responses', () => { expect(normalizeSignInResponse({ status: 'mfa_required', diff --git a/frontend/tests/modules/auth/views/LauncherAuth.test.tsx b/frontend/tests/modules/auth/views/LauncherAuth.test.tsx new file mode 100644 index 00000000..65b4d5b4 --- /dev/null +++ b/frontend/tests/modules/auth/views/LauncherAuth.test.tsx @@ -0,0 +1,86 @@ +import React, { act } from 'react'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { createRoot, type Root } from 'react-dom/client'; +import { MemoryRouter } from 'react-router-dom'; +import { LauncherAuth } from '@/modules/auth/views/LauncherAuth'; +import { authClient } from '@/modules/auth/api/authClient'; +import type { User } from '@/types'; + +vi.mock('@/modules/auth/api/authClient', () => ({ + authClient: { + issueLauncherAuthCode: vi.fn() + } +})); + +const mockedAuthClient = vi.mocked(authClient); + +const signedInUser: User = { + id: 'user-1', + username: 'ada', + displayName: 'Ada Lovelace', + avatarUrl: '/avatar.png', + likedProjectIds: [] +}; + +describe('LauncherAuth', () => { + let container: HTMLDivElement; + let root: Root; + + beforeEach(() => { + vi.clearAllMocks(); + container = document.createElement('div'); + document.body.appendChild(container); + root = createRoot(container); + mockedAuthClient.issueLauncherAuthCode.mockReturnValue( + new Promise(() => {}) as ReturnType + ); + }); + + afterEach(async () => { + await act(async () => { + root.unmount(); + }); + container.remove(); + }); + + it('asks for launcher consent before issuing an auth code', async () => { + await act(async () => { + root.render( + + + + ); + }); + + expect(container.textContent).toContain('Do you want to authenticate with Modtale Launcher?'); + expect(container.textContent).toContain('Ada Lovelace'); + expect(mockedAuthClient.issueLauncherAuthCode).not.toHaveBeenCalled(); + + const authenticateButton = Array.from(container.querySelectorAll('button')) + .find(button => button.textContent?.includes('Authenticate')); + expect(authenticateButton).toBeTruthy(); + + await act(async () => { + authenticateButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + + expect(mockedAuthClient.issueLauncherAuthCode).toHaveBeenCalledWith({ + redirectUri: 'http://127.0.0.1:49152/callback', + state: 'state-123' + }); + }); + + it('rejects non-local launcher callback URLs before consent', async () => { + await act(async () => { + root.render( + + + + ); + }); + + expect(container.textContent).toContain('Launcher Sign-In Failed'); + expect(container.textContent).toContain('The launcher callback URL must point to this device.'); + expect(mockedAuthClient.issueLauncherAuthCode).not.toHaveBeenCalled(); + }); +}); diff --git a/frontend/tests/modules/home/Home.test.tsx b/frontend/tests/modules/home/Home.test.tsx index 1a21b247..c5fc01c9 100644 --- a/frontend/tests/modules/home/Home.test.tsx +++ b/frontend/tests/modules/home/Home.test.tsx @@ -27,6 +27,7 @@ vi.mock('@/modules/home/components/FeaturePreviews', () => ({ NewReleasesSection: () =>
    , ModpackPreviewSection: () =>
    , DirectDownloadsSection: () =>
    , + LauncherPreviewSection: () =>
    , SmartDependenciesSection: () =>
    , ProjectAnalyticsSection: () =>
    , CommunityThreadsSection: () =>
    , diff --git a/frontend/tests/modules/launcher/utils/launcherProtocol.test.ts b/frontend/tests/modules/launcher/utils/launcherProtocol.test.ts new file mode 100644 index 00000000..fc39ee21 --- /dev/null +++ b/frontend/tests/modules/launcher/utils/launcherProtocol.test.ts @@ -0,0 +1,87 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { + buildLauncherInstallUrl, + buildLauncherListInstallUrl, + openLauncherInstallOrFallback, + openLauncherListInstallOrFallback +} from '@/modules/launcher/utils/launcherProtocol'; + +describe('launcherProtocol', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + it('builds launcher install URLs with project and version context', () => { + expect(buildLauncherInstallUrl({ + projectId: 'project-123', + projectHandle: 'cool-mod', + versionNumber: '1.2.3', + gameVersion: '0.5.4' + })).toBe('modtale://install?projectId=project-123&project=cool-mod&version=1.2.3&gameVersion=0.5.4'); + }); + + it('falls back to the project id when no project handle is available', () => { + expect(buildLauncherInstallUrl({ projectId: 'project-123' })) + .toBe('modtale://install?projectId=project-123&project=project-123'); + }); + + it('builds launcher list install URLs with share context', () => { + expect(buildLauncherListInstallUrl({ + listId: 'list-123', + shareUrl: 'https://modtale.net/lists/list-123' + })).toBe('modtale://install-list?listId=list-123&url=https%3A%2F%2Fmodtale.net%2Flists%2Flist-123'); + }); + + it('runs the fallback if the protocol handoff does not leave the page', () => { + vi.useFakeTimers(); + const openUrl = vi.fn(); + const fallback = vi.fn(); + + openLauncherInstallOrFallback( + { projectId: 'project-123', projectHandle: 'cool-mod' }, + fallback, + { openUrl, timeoutMs: 25 } + ); + + expect(openUrl).toHaveBeenCalledWith('modtale://install?projectId=project-123&project=cool-mod'); + + vi.advanceTimersByTime(25); + + expect(fallback).toHaveBeenCalledOnce(); + }); + + it('does not run fallback after a browser handoff signal', () => { + vi.useFakeTimers(); + const openUrl = vi.fn(); + const fallback = vi.fn(); + + openLauncherInstallOrFallback( + { projectId: 'project-123' }, + fallback, + { openUrl, timeoutMs: 25 } + ); + + window.dispatchEvent(new Event('blur')); + vi.advanceTimersByTime(25); + + expect(fallback).not.toHaveBeenCalled(); + }); + + it('opens list install URLs through the same handoff path', () => { + vi.useFakeTimers(); + const openUrl = vi.fn(); + const fallback = vi.fn(); + + openLauncherListInstallOrFallback( + { listId: 'list-123' }, + fallback, + { openUrl, timeoutMs: 25 } + ); + + expect(openUrl).toHaveBeenCalledWith('modtale://install-list?listId=list-123'); + + vi.advanceTimersByTime(25); + + expect(fallback).toHaveBeenCalledOnce(); + }); +}); diff --git a/frontend/tests/modules/project/components/DownloadModal.test.tsx b/frontend/tests/modules/project/components/DownloadModal.test.tsx index 1895e841..059262af 100644 --- a/frontend/tests/modules/project/components/DownloadModal.test.tsx +++ b/frontend/tests/modules/project/components/DownloadModal.test.tsx @@ -12,6 +12,12 @@ const settle = async () => { }); }; +const launcherProtocolMock = vi.hoisted(() => ({ + openLauncherInstallOrFallback: vi.fn() +})); + +vi.mock('@/modules/launcher/utils/launcherProtocol', () => launcherProtocolMock); + describe('DownloadModal Toggle Visibility', () => { let container: HTMLDivElement; let root: Root; @@ -28,6 +34,7 @@ describe('DownloadModal Toggle Visibility', () => { root.unmount(); }); container.remove(); + launcherProtocolMock.openLauncherInstallOrFallback.mockClear(); }); it('hides Alpha/Beta toggle if the project has no alpha/beta versions at all', async () => { @@ -460,8 +467,8 @@ describe('DownloadModal Toggle Visibility', () => { ); }); - expect(container.textContent).toContain('This modpack uses external mods'); - expect(container.textContent).toContain('External Shader'); + expect(pageText()).toContain('This modpack uses external mods'); + expect(pageText()).toContain('External Shader'); }); it('does not show the external mod warning for non-modpack projects', async () => { @@ -503,7 +510,84 @@ describe('DownloadModal Toggle Visibility', () => { ); }); - expect(container.textContent).not.toContain('This modpack uses external mods'); - expect(container.textContent).not.toContain('External Library'); + expect(pageText()).not.toContain('This modpack uses external mods'); + expect(pageText()).not.toContain('External Library'); + }); + + it('keeps the launcher install action hidden without project context', async () => { + const versionsByGame = { + '0.5.4': [ + { id: 'v1', versionNumber: '1.0.0', channel: 'RELEASE', gameVersion: '0.5.4', releaseDate: new Date().toISOString(), fileUrl: '/download.zip' } + ] + }; + + await act(async () => { + root.render( + + + + ); + }); + + expect(pageText()).not.toContain('Install with launcher'); + }); + + it('hands the selected version to the launcher install flow', async () => { + const fallback = vi.fn(); + const versionsByGame = { + '0.5.4': [ + { id: 'v1', versionNumber: '1.0.0', channel: 'RELEASE', gameVersion: '0.5.4', releaseDate: new Date().toISOString(), fileUrl: '/download.zip' } + ] + }; + + await act(async () => { + root.render( + + + + ); + }); + + const launcherButton = Array.from(document.body.querySelectorAll('button')) + .find((button) => button.textContent?.includes('Install with launcher')) as HTMLButtonElement | undefined; + + expect(launcherButton).toBeTruthy(); + + await act(async () => { + launcherButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })); + }); + + expect(launcherProtocolMock.openLauncherInstallOrFallback).toHaveBeenCalledWith( + { + projectId: 'project-123', + projectHandle: 'cool-mod', + versionNumber: '1.0.0', + gameVersion: '0.5.4' + }, + fallback + ); }); }); diff --git a/frontend/tests/modules/project/components/PostDownloadModal.test.tsx b/frontend/tests/modules/project/components/PostDownloadModal.test.tsx new file mode 100644 index 00000000..80d588f4 --- /dev/null +++ b/frontend/tests/modules/project/components/PostDownloadModal.test.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { act } from 'react'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { createRoot, type Root } from 'react-dom/client'; +import { MemoryRouter } from 'react-router-dom'; + +import { PostDownloadModal } from '@/modules/project/components/dialogs/PostDownloadModal'; + +describe('PostDownloadModal', () => { + let container: HTMLDivElement; + let root: Root; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + root = createRoot(container); + }); + + afterEach(async () => { + await act(async () => { + root.unmount(); + }); + container.remove(); + }); + + it('links users to the launcher download page', async () => { + await act(async () => { + root.render( + + + + ); + }); + + expect(document.body.textContent).toContain('You can install mods automatically using the Modtale Launcher.'); + + const launcherLink = document.body.querySelector('a[aria-label="Download Modtale Launcher"]'); + + expect(launcherLink?.getAttribute('href')).toBe('/launcher'); + }); +}); diff --git a/frontend/tests/modules/project/components/ProjectCard.test.tsx b/frontend/tests/modules/project/components/ProjectCard.test.tsx index c3fff583..ba1a096c 100644 --- a/frontend/tests/modules/project/components/ProjectCard.test.tsx +++ b/frontend/tests/modules/project/components/ProjectCard.test.tsx @@ -129,4 +129,45 @@ describe('ProjectCard banner fade', () => { expect(container.textContent).toContain('8'); }); + + it('uses the latest favorite handler after rerendering with unchanged project data', async () => { + const oldToggle = vi.fn(); + const newToggle = vi.fn(); + + await act(async () => { + root.render( + + + + ); + }); + + await act(async () => { + root.render( + + + + ); + }); + + const favoriteButton = container.querySelector('button[aria-label="7 favorites"]') as HTMLButtonElement | null; + expect(favoriteButton).not.toBeNull(); + + await act(async () => { + favoriteButton?.click(); + }); + + expect(oldToggle).not.toHaveBeenCalled(); + expect(newToggle).toHaveBeenCalledWith('project-1'); + }); }); diff --git a/frontend/tests/performance/renderSpeed.test.tsx b/frontend/tests/performance/renderSpeed.test.tsx index 075439fd..38a3660b 100644 --- a/frontend/tests/performance/renderSpeed.test.tsx +++ b/frontend/tests/performance/renderSpeed.test.tsx @@ -11,6 +11,7 @@ import { Browse } from '@/modules/discovery/views/Browse'; import { ProjectDetails } from '@/modules/project/views/ProjectDetails'; import { discoveryClient } from '@/modules/discovery/api/discoveryClient'; import { projectClient } from '@/modules/project/api/projectClient'; +import { theme } from '@/styles/theme'; import type { Project } from '@/types'; vi.mock('@/modules/discovery/api/discoveryClient', () => ({ @@ -256,4 +257,9 @@ describe('critical page render budgets', () => { expect(navbarSource).toContain("import('@/modules/auth/components/SignInModal.tsx')"); expect(navbarSource).toContain("import('@/modules/user/components/NotificationMenu')"); }); + + it('keeps shared modal overlays off backdrop-filter paint paths', () => { + expect(theme.components.modalOverlay).not.toContain('backdrop-blur'); + expect(theme.components.modalOverlay).not.toContain('backdrop-filter'); + }); }); diff --git a/frontend/tests/utils/routes.test.ts b/frontend/tests/utils/routes.test.ts index 7bc1924d..bf8e797a 100644 --- a/frontend/tests/utils/routes.test.ts +++ b/frontend/tests/utils/routes.test.ts @@ -2,6 +2,10 @@ import { describe, expect, it } from 'vitest'; import { SiteRoutes } from '@/utils/routes'; describe('SiteRoutes', () => { + it('returns the launcher route', () => { + expect(SiteRoutes.launcher()).toBe('/launcher'); + }); + it('maps browse routes by classification', () => { expect(SiteRoutes.browse('PLUGIN')).toBe('/plugins'); expect(SiteRoutes.browse('MODPACK')).toBe('/modpacks'); diff --git a/launcher/README.md b/launcher/README.md new file mode 100644 index 00000000..d1137435 --- /dev/null +++ b/launcher/README.md @@ -0,0 +1,81 @@ +# Modtale Launcher + +Native Java 21 JavaFX launcher for installing and updating Modtale projects in a local Hytale mods folder. A linked Hytale account is required before the launcher UI is available. Modtale sign-in is only required for Modtale API-backed features such as browsing, installs, updates, notifications, following, and favorites; local world mod management and game launch can work without a Modtale session. + +The Play tab can launch a locally installed Hytale client with official Hytale authentication. Hytale launch first tries to refresh the Hytale OAuth session and create fresh game-session tokens. If Hytale authentication is unavailable or rejects the active session, Modtale may reuse the last Hytale-issued launch tokens stored for the linked account and still starts the client in authenticated mode so Hytale itself applies its first-party offline restrictions. The launcher does not create offline identities, fabricate tokens, or provide a piracy launch mode. + +## Run From Source + +```bash +./gradlew run +``` + +Launcher sign-in talks to `https://api.modtale.net/api/v1` by default. OAuth provider flows return to a temporary local launcher callback. Browser fallback sign-in opens `https://modtale.net`. For local auth testing, override the site and API URLs with environment variables: + +```bash +MODTALE_SITE_BASE_URL=http://localhost:5173 MODTALE_API_BASE_URL=http://localhost:8080/api/v1 ./gradlew run +``` + +Discord Rich Presence is enabled when a Discord application ID is configured: + +```bash +MODTALE_DISCORD_CLIENT_ID=123456789012345678 ./gradlew run +``` + +The equivalent JVM property is `-Dmodtale.discordClientId=123456789012345678`. `DISCORD_CLIENT_ID` is also accepted as a fallback for environments that already provide the OAuth application ID. +Packaged builds can embed the ID with `./gradlew packageAll -PdiscordClientId=123456789012345678`. + +## Build Packages + +```bash +./gradlew build +``` + +The launcher build produces a self-contained native package for the host OS: + +- Windows hosts: `build/distributions/Modtale Launcher-.exe` +- macOS hosts: `build/distributions/Modtale Launcher-.dmg` +- Linux hosts: `build/distributions/modtale-launcher--.AppImage` + +Each package embeds its own Java runtime and launcher dependencies; users do not need a system JDK or JRE to run it. Windows and macOS builds produce OS installers. Linux `packageLinux` produces a self-contained AppImage; desktop integration is handled by the user's AppImage integration tool when present. `packageAll` is matrix-friendly: run it on Windows, macOS, and Linux hosts to produce the default release artifact for each platform. + +Additional Linux package formats are available: + +```bash +./gradlew packageLinuxDeb +./gradlew packageLinuxRpm +./gradlew packageLinuxFlatpak +./gradlew packageLinuxPacman +./gradlew packageLinuxAll +``` + +These produce: + +- `build/distributions/modtale-launcher_-_.deb` +- `build/distributions/modtale-launcher--..rpm` +- `build/distributions/net.modtale.launcher--.flatpak` +- `build/distributions/modtale-launcher---.pkg.tar.zst` + +Build hosts still need a full JDK 21 because `jpackage` is a JDK tool. Linux AppImage builds also need `appimagetool` on `PATH`; set `APPIMAGETOOL` or `-PappImageTool=/path/to/appimagetool` if it is installed elsewhere. RPM builds need `rpmbuild`, Flatpak builds need `flatpak` plus the configured Freedesktop runtime/SDK, and pacman builds need `zstd`. Windows installer builds require the native packaging tools expected by `jpackage` for `.exe` or `.msi` output. + +Alternative native installer types can be selected per host: + +```bash +./gradlew packageWindows -PwindowsPackageType=msi +./gradlew packageMac -PmacPackageType=pkg +``` + +To smoke-test a self-contained unpacked app image without creating an installer, run: + +```bash +./gradlew jpackageAppImage +build/jpackage/app-image/Modtale\ Launcher/bin/Modtale\ Launcher +``` + +The jar remains available in `build/libs/` as a build artifact for development and diagnostics, but it is not the end-user launcher distribution. + +## GitHub Releases and Updates + +The launcher release workflow builds Windows, macOS, and Linux packages in GitHub Actions and attaches them to a GitHub release. Push a tag like `launcher-v0.2.0`, or run the `Launcher Release` workflow manually with a version, to publish native launcher assets. + +Packaged launchers check `Modtale/modtale` releases for newer launcher builds. The updater matches release assets by platform (`.exe`/`.msi`, `.dmg`/`.pkg`, or `.AppImage`) and opens the matching installer when the user chooses to update. For development or forks, override the release source with `MODTALE_LAUNCHER_UPDATES_REPOSITORY=owner/repo`. diff --git a/launcher/build.gradle b/launcher/build.gradle new file mode 100644 index 00000000..73ada075 --- /dev/null +++ b/launcher/build.gradle @@ -0,0 +1,928 @@ +plugins { + id 'application' +} + +def configuredLauncherVersion = providers.gradleProperty('launcherVersion') + .orElse(providers.environmentVariable('LAUNCHER_VERSION')) + .orElse('0.1.0-SNAPSHOT') + .get() + +group = 'net.modtale' +version = configuredLauncherVersion + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2' + implementation 'com.vladsch.flexmark:flexmark:0.64.8' + implementation 'com.vladsch.flexmark:flexmark-ext-autolink:0.64.8' + implementation 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.64.8' + implementation 'com.vladsch.flexmark:flexmark-ext-tables:0.64.8' + implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.64.8' + implementation 'net.java.dev.jna:jna:5.14.0' + implementation "org.openjfx:javafx-base:21.0.5:${javafxPlatform()}" + implementation "org.openjfx:javafx-graphics:21.0.5:${javafxPlatform()}" + implementation "org.openjfx:javafx-controls:21.0.5:${javafxPlatform()}" + + testImplementation 'org.junit.jupiter:junit-jupiter:5.10.3' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +application { + mainClass = 'net.modtale.launcher.LauncherMain' +} + +def appId = 'net.modtale.launcher' +def appDisplayName = 'Modtale Launcher' +def appSlug = 'modtale-launcher' +def packageVersion = project.version.toString() +def discordClientId = providers.gradleProperty('discordClientId') + .orElse(providers.environmentVariable('MODTALE_DISCORD_CLIENT_ID')) + .orElse(providers.environmentVariable('DISCORD_CLIENT_ID')) + .orElse('') + .get() +def modtaleSiteBaseUrl = providers.gradleProperty('modtaleSiteBaseUrl') + .orElse(providers.gradleProperty('siteBaseUrl')) + .orElse('') + .get() +def modtaleApiBaseUrl = providers.gradleProperty('modtaleApiBaseUrl') + .orElse(providers.gradleProperty('apiBaseUrl')) + .orElse('') + .get() +def launcherJvmArgs = ["-Dmodtale.launcherVersion=${packageVersion}"] +if (!discordClientId.isBlank()) { + launcherJvmArgs.add("-Dmodtale.discordClientId=${discordClientId.trim()}") +} +if (!modtaleSiteBaseUrl.isBlank()) { + launcherJvmArgs.add("-Dmodtale.siteBaseUrl=${modtaleSiteBaseUrl.trim()}") +} +if (!modtaleApiBaseUrl.isBlank()) { + launcherJvmArgs.add("-Dmodtale.apiBaseUrl=${modtaleApiBaseUrl.trim()}") +} +def installerVersionMatcher = packageVersion =~ /\d+(?:\.\d+){0,2}/ +def installerVersion = installerVersionMatcher.find() ? installerVersionMatcher.group() : '0.1.0' +def appDescription = 'Native Modtale launcher for Hytale mods.' +def appVendor = 'Modtale' +def appHomepage = 'https://modtale.net' +def appCopyright = 'Copyright (C) Modtale contributors' +def appLicenseId = 'AGPL-3.0-or-later' +def appLicense = layout.projectDirectory.file('../LICENSE') +def appIconPng = layout.projectDirectory.file('src/main/resources/net/modtale/launcher/ui/nativefx/assets/favicon.png') +def distributionDirectory = layout.buildDirectory.dir('distributions') +def linuxAppImageDirectory = layout.buildDirectory.dir('jpackage/linux-app-image') +def linuxAppDir = layout.buildDirectory.dir("appimage/${appSlug}.AppDir") +def linuxPackageRootDirectory = layout.buildDirectory.dir('linux-package/root') +def linuxPackageWorkDirectory = layout.buildDirectory.dir('linux-package/work') +def linuxInstallDirectory = "/opt/${appSlug}" +def linuxInstallPath = linuxInstallDirectory.replaceFirst('^/', '') +def linuxPackageRelease = providers.gradleProperty('linuxPackageRelease') + .orElse(providers.environmentVariable('LINUX_PACKAGE_RELEASE')) + .orElse('1') + .get() +def linuxDebMaintainer = providers.gradleProperty('linuxDebMaintainer') + .orElse('Modtale contributors ') + .get() +def flatpakRuntimeVersion = providers.gradleProperty('flatpakRuntimeVersion').orElse('25.08').get() +def flatpakRuntime = providers.gradleProperty('flatpakRuntime').orElse('org.freedesktop.Platform').get() +def flatpakSdk = providers.gradleProperty('flatpakSdk').orElse('org.freedesktop.Sdk').get() +def flatpakBranch = providers.gradleProperty('flatpakBranch').orElse('stable').get() +def flatpakBuildDirectory = layout.buildDirectory.dir('flatpak/build') +def flatpakRepoDirectory = layout.buildDirectory.dir('flatpak/repo') +def currentOs = org.gradle.internal.os.OperatingSystem.current() +def javaRuntimeModules = [ + 'java.base', + 'java.datatransfer', + 'java.desktop', + 'java.logging', + 'java.net.http', + 'java.prefs', + 'java.sql', + 'java.xml', + 'jdk.crypto.ec', + 'jdk.httpserver', + 'jdk.unsupported' +] +def jpackageJlinkOptions = [ + '--strip-native-commands', + '--strip-debug', + '--no-man-pages', + '--no-header-files', + '--compress=zip-9' +] + +application { + applicationDefaultJvmArgs = launcherJvmArgs +} + +tasks.named('jar') { + manifest { + attributes( + 'Implementation-Title': appDisplayName, + 'Implementation-Version': packageVersion, + 'Implementation-Vendor': appVendor + ) + } +} + +def appJar = tasks.named('jar').flatMap { it.archiveFile } +def runtimeClasspathFiles = configurations.runtimeClasspath +def windowsPackageType = providers.gradleProperty('windowsPackageType') + .orElse('exe') + .map { it.toLowerCase(Locale.ROOT) } + .get() +def macPackageType = providers.gradleProperty('macPackageType') + .orElse('dmg') + .map { it.toLowerCase(Locale.ROOT) } + .get() +def appImageTool = providers.gradleProperty('appImageTool') + .orElse(providers.environmentVariable('APPIMAGETOOL')) + .orElse('appimagetool') +def linuxAppImageFile = distributionDirectory.map { + it.file("${appSlug}-${installerVersion}-${appImageArch()}.AppImage") +} +def linuxDebFile = distributionDirectory.map { + it.file("${appSlug}_${installerVersion}-${linuxPackageRelease}_${debArchitecture()}.deb") +} +def linuxRpmFile = distributionDirectory.map { + it.file("${appSlug}-${installerVersion}-${linuxPackageRelease}.${rpmArchitecture()}.rpm") +} +def linuxPacmanFile = distributionDirectory.map { + it.file("${appSlug}-${installerVersion}-${linuxPackageRelease}-${pacmanArchitecture()}.pkg.tar.zst") +} +def linuxFlatpakFile = distributionDirectory.map { + it.file("${appId}-${installerVersion}-${flatpakArchitecture()}.flatpak") +} + +tasks.register('prepareJpackageInput', Sync) { + group = 'distribution' + description = 'Collects launcher jars for self-contained jpackage installers.' + dependsOn tasks.named('jar') + into layout.buildDirectory.dir('jpackage/input') + from(appJar) + from(runtimeClasspathFiles) +} + +def java21Launcher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(21) +} + +def jpackageExecutable = java21Launcher.map { + def extension = currentOs.isWindows() ? '.exe' : '' + file("${it.executablePath.asFile.parentFile}/jpackage${extension}") +} + +def commonJpackageArgs = { + [ + '--input', layout.buildDirectory.dir('jpackage/input').get().asFile.absolutePath, + '--name', appDisplayName, + '--main-jar', appJar.get().asFile.name, + '--main-class', application.mainClass.get(), + '--app-version', installerVersion, + '--vendor', appVendor, + '--description', appDescription, + '--add-modules', javaRuntimeModules.join(','), + '--jlink-options', jpackageJlinkOptions.join(' ') + ] + (['-Dfile.encoding=UTF-8'] + launcherJvmArgs).collectMany { ['--java-options', it] } +} + +def installerJpackageArgs = { + [ + '--about-url', appHomepage, + '--copyright', appCopyright, + '--license-file', appLicense.asFile.absolutePath + ] +} + +def desktopFileContent = { String execName, String iconName -> + """[Desktop Entry] +Type=Application +Name=${appDisplayName} +Comment=Install and update Hytale mods from Modtale +Exec=${execName} +Icon=${iconName} +Terminal=false +Categories=Game; +StartupNotify=true +StartupWMClass=net.modtale.launcher.ModtaleLauncher +""" +} + +def metainfoContent = { + """ + + ${appId} + ${appDisplayName} + Install and update Hytale mods from Modtale + CC0-1.0 + ${appLicenseId} + + Modtale contributors + + +

    Install, update, and manage Hytale mods from Modtale with a self-contained native launcher.

    +
    + ${appId}.desktop + ${appHomepage} + +
    +""" +} + +def configureJpackageTask = { TaskProvider packageTask, String packageType, Closure hostPredicate, Closure> platformArgs -> + packageTask.configure { + group = 'distribution' + dependsOn tasks.named('prepareJpackageInput') + onlyIf { + hostPredicate.call() + } + doFirst { + def executable = jpackageExecutable.get() + if (!executable.exists()) { + throw new GradleException("jpackage was not found at ${executable}. Install a full JDK 21 to build native launcher installers.") + } + + delete layout.buildDirectory.dir("jpackage/tmp/${name}") + mkdir distributionDirectory.get().asFile + + commandLine([ + executable.absolutePath, + '--type', packageType, + '--dest', distributionDirectory.get().asFile.absolutePath, + '--temp', layout.buildDirectory.dir("jpackage/tmp/${name}").get().asFile.absolutePath + ] + commonJpackageArgs.call() + installerJpackageArgs.call() + platformArgs.call()) + } + } +} + +configureJpackageTask( + tasks.register('packageWindows', Exec) { + description = 'Builds a self-contained Windows .exe installer with an embedded Java runtime.' + }, + windowsPackageType, + { currentOs.isWindows() }, + { + def args = [ + '--win-menu', + '--win-menu-group', appDisplayName, + '--win-shortcut', + '--win-upgrade-uuid', '3d6c6852-fc6f-4a7e-a617-988263243f90' + ] + if (windowsPackageType == 'exe') { + args += [ + '--win-dir-chooser', + '--win-per-user-install' + ] + } + args + } +) + +configureJpackageTask( + tasks.register('packageMac', Exec) { + description = 'Builds a self-contained macOS .dmg containing a native .app bundle and embedded Java runtime.' + }, + macPackageType, + { currentOs.isMacOsX() }, + { + [ + '--mac-package-identifier', appId, + '--mac-package-name', appDisplayName + ] + } +) + +tasks.register('prepareLinuxAppImageRuntime', Exec) { + group = 'distribution' + description = 'Builds the self-contained Linux runtime image used by the AppImage package.' + dependsOn tasks.named('prepareJpackageInput') + onlyIf { + currentOs.isLinux() + } + doFirst { + def executable = jpackageExecutable.get() + if (!executable.exists()) { + throw new GradleException("jpackage was not found at ${executable}. Install a full JDK 21 to build the Linux AppImage.") + } + + delete linuxAppImageDirectory + commandLine([ + executable.absolutePath, + '--type', 'app-image', + '--dest', linuxAppImageDirectory.get().asFile.absolutePath, + '--icon', appIconPng.asFile.absolutePath + ] + commonJpackageArgs.call()) + } +} + +tasks.register('prepareLinuxAppDir') { + group = 'distribution' + description = 'Assembles the AppDir consumed by appimagetool.' + dependsOn tasks.named('prepareLinuxAppImageRuntime') + onlyIf { + currentOs.isLinux() + } + inputs.dir linuxAppImageDirectory + outputs.dir linuxAppDir + doLast { + def appDir = linuxAppDir.get().asFile + def packagedApp = linuxAppImageDirectory.get().dir(appDisplayName).asFile + if (!packagedApp.exists()) { + throw new GradleException("Expected jpackage app image at ${packagedApp}, but it was not created.") + } + + delete appDir + copy { + from(packagedApp) + into(appDir) + } + + copy { + from(appIconPng) + into(appDir) + rename { "${appSlug}.png" } + } + copy { + from(appIconPng) + into(appDir) + rename { '.DirIcon' } + } + copy { + from(appIconPng) + into(new File(appDir, 'usr/share/icons/hicolor/256x256/apps')) + rename { "${appSlug}.png" } + } + + def appRun = new File(appDir, 'AppRun') + appRun.text = '''#!/usr/bin/env sh +set -eu +APPDIR="${APPDIR:-$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)}" +if [ -n "${WAYLAND_DISPLAY:-}" ]; then + export GDK_BACKEND=x11 +fi +exec "$APPDIR/bin/Modtale Launcher" "$@" +''' + appRun.setExecutable(true, false) + + def appImageDesktopFileContent = desktopFileContent(appSlug, appSlug) + def desktopFile = new File(appDir, "${appId}.desktop") + desktopFile.text = appImageDesktopFileContent + + def desktopInstallFile = new File(appDir, "usr/share/applications/${appId}.desktop") + desktopInstallFile.parentFile.mkdirs() + desktopInstallFile.text = appImageDesktopFileContent + + def metainfo = new File(appDir, "usr/share/metainfo/${appId}.appdata.xml") + metainfo.parentFile.mkdirs() + metainfo.text = metainfoContent() + } +} + +tasks.register('packageLinux', Exec) { + group = 'distribution' + description = 'Builds a self-contained Linux AppImage with an embedded Java runtime.' + dependsOn tasks.named('prepareLinuxAppDir') + onlyIf { + currentOs.isLinux() + } + inputs.dir linuxAppDir + outputs.file linuxAppImageFile + doFirst { + def tool = resolveExecutable(appImageTool.get(), 'appimagetool', 'Install appimagetool, or set -PappImageTool=/path/to/appimagetool or APPIMAGETOOL.') + mkdir distributionDirectory.get().asFile + delete linuxAppImageFile.get().asFile + commandLine tool, linuxAppDir.get().asFile.absolutePath, linuxAppImageFile.get().asFile.absolutePath + } +} + +tasks.register('prepareLinuxPackageRoot') { + group = 'distribution' + description = 'Stages the self-contained Linux launcher tree used by DEB, RPM, and Flatpak packages.' + dependsOn tasks.named('prepareLinuxAppImageRuntime') + onlyIf { + currentOs.isLinux() + } + inputs.dir linuxAppImageDirectory + outputs.dir linuxPackageRootDirectory + doLast { + def packagedApp = linuxAppImageDirectory.get().dir(appDisplayName).asFile + if (!packagedApp.exists()) { + throw new GradleException("Expected jpackage app image at ${packagedApp}, but it was not created.") + } + + def rootDir = linuxPackageRootDirectory.get().asFile + delete rootDir + copy { + from(packagedApp) + into(new File(rootDir, linuxInstallPath)) + } + + def wrapper = new File(rootDir, "usr/bin/${appSlug}") + wrapper.parentFile.mkdirs() +wrapper.text = """#!/usr/bin/env sh +set -eu +APPDIR="${linuxInstallDirectory}" +exec "\$APPDIR/bin/${appDisplayName}" "\$@" +""" + wrapper.setExecutable(true, false) + + copy { + from(appIconPng) + into(new File(rootDir, "usr/share/icons/hicolor/256x256/apps")) + rename { "${appSlug}.png" } + } + + def desktopFile = new File(rootDir, "usr/share/applications/${appId}.desktop") + desktopFile.parentFile.mkdirs() + desktopFile.text = desktopFileContent(appSlug, appSlug) + + def metainfo = new File(rootDir, "usr/share/metainfo/${appId}.appdata.xml") + metainfo.parentFile.mkdirs() + metainfo.text = metainfoContent() + + copy { + from(appLicense) + into(new File(rootDir, "usr/share/licenses/${appSlug}")) + rename { 'LICENSE' } + } + } +} + +tasks.register('packageLinuxDeb') { + group = 'distribution' + description = 'Builds a self-contained Linux .deb package for the launcher.' + dependsOn tasks.named('prepareLinuxPackageRoot') + onlyIf { + currentOs.isLinux() + } + inputs.dir linuxPackageRootDirectory + outputs.file linuxDebFile + doLast { + def tar = resolveExecutable('tar', 'tar', 'Install tar to create Debian packages.') + def ar = resolveExecutable('ar', 'ar', 'Install binutils ar to create Debian packages.') + def rootDir = linuxPackageRootDirectory.get().asFile + def workDir = new File(linuxPackageWorkDirectory.get().asFile, 'deb') + def controlDir = new File(workDir, 'control') + def debianBinary = new File(workDir, 'debian-binary') + def controlTar = new File(workDir, 'control.tar.xz') + def dataTar = new File(workDir, 'data.tar.xz') + def output = linuxDebFile.get().asFile + + delete workDir + controlDir.mkdirs() + mkdir distributionDirectory.get().asFile + delete output + + long installedBytes = 0 + rootDir.eachFileRecurse(groovy.io.FileType.FILES) { file -> + installedBytes += file.length() + } + long installedSizeKb = Math.max(1L, Math.ceil(installedBytes / 1024.0D) as long) + + new File(controlDir, 'control').text = """Package: ${appSlug} +Version: ${installerVersion}-${linuxPackageRelease} +Section: games +Priority: optional +Architecture: ${debArchitecture()} +Maintainer: ${linuxDebMaintainer} +Installed-Size: ${installedSizeKb} +Depends: libc6, libx11-6, libxext6, libxrender1, libxtst6, libxi6, libfreetype6, fontconfig, libgtk-3-0, zlib1g +Homepage: ${appHomepage} +Description: ${appDescription} + Install, update, and manage Hytale mods from Modtale with a self-contained native launcher. +""" + debianBinary.text = '2.0\n' + + runExternalCommand([ + tar, '--sort=name', '--mtime=@0', '--owner=0', '--group=0', '--numeric-owner', + '-C', controlDir.absolutePath, '-cJf', controlTar.absolutePath, 'control' + ], null, ['XZ_OPT': '-9e']) + runExternalCommand([ + tar, '--sort=name', '--mtime=@0', '--owner=0', '--group=0', '--numeric-owner', + '-C', rootDir.absolutePath, '-cJf', dataTar.absolutePath, '.' + ], null, ['XZ_OPT': '-9e']) + runExternalCommand([ar, 'rcs', output.absolutePath, debianBinary.name, controlTar.name, dataTar.name], workDir) + } +} + +tasks.register('packageLinuxRpm') { + group = 'distribution' + description = 'Builds a self-contained Linux .rpm package for the launcher.' + dependsOn tasks.named('prepareLinuxPackageRoot') + onlyIf { + currentOs.isLinux() + } + inputs.dir linuxPackageRootDirectory + outputs.file linuxRpmFile + doLast { + def rpmbuild = resolveExecutable('rpmbuild', 'rpmbuild', 'Install rpm-build to create RPM packages.') + def tar = resolveExecutable('tar', 'tar', 'Install tar to create RPM packages.') + def rootDir = linuxPackageRootDirectory.get().asFile + def workDir = new File(linuxPackageWorkDirectory.get().asFile, 'rpm') + def sourceParent = new File(workDir, 'source') + def sourceRoot = new File(sourceParent, "${appSlug}-${installerVersion}-root") + def sourcesDir = new File(workDir, 'SOURCES') + def specsDir = new File(workDir, 'SPECS') + def specFile = new File(specsDir, "${appSlug}.spec") + def sourceTar = new File(sourcesDir, "${appSlug}-${installerVersion}-root.tar.gz") + def output = linuxRpmFile.get().asFile + + delete workDir + sourceRoot.mkdirs() + sourcesDir.mkdirs() + specsDir.mkdirs() + mkdir new File(workDir, 'BUILD') + mkdir new File(workDir, 'BUILDROOT') + mkdir new File(workDir, 'RPMS') + mkdir new File(workDir, 'SRPMS') + mkdir distributionDirectory.get().asFile + delete output + + copy { + from(rootDir) + into(sourceRoot) + } + runExternalCommand([tar, '-C', sourceParent.absolutePath, '-czf', sourceTar.absolutePath, sourceRoot.name]) + + specFile.text = """Name: ${appSlug} +Version: ${installerVersion} +Release: ${linuxPackageRelease} +Summary: ${appDescription} +License: ${appLicenseId} +URL: ${appHomepage} +BuildArch: ${rpmArchitecture()} +Source0: %{name}-%{version}-root.tar.gz +%global debug_package %{nil} +%global __brp_check_rpaths %{nil} + +%description +Install, update, and manage Hytale mods from Modtale with a self-contained native launcher. + +%prep +%setup -q -n %{name}-%{version}-root + +%build + +%install +mkdir -p %{buildroot} +cp -a . %{buildroot}/ + +%files +%license /usr/share/licenses/${appSlug}/LICENSE +${linuxInstallDirectory} +/usr/bin/${appSlug} +/usr/share/applications/${appId}.desktop +/usr/share/icons/hicolor/256x256/apps/${appSlug}.png +/usr/share/metainfo/${appId}.appdata.xml +""" + + runExternalCommand([ + rpmbuild, '-bb', + '--define', "_topdir ${workDir.absolutePath}", + '--define', '_binary_payload w19.zstdio', + specFile.absolutePath + ], null, ['QA_RPATHS': '0x0002']) + + def builtRpms = fileTree(new File(workDir, "RPMS/${rpmArchitecture()}")).matching { + include '*.rpm' + }.files + if (builtRpms.isEmpty()) { + throw new GradleException("rpmbuild completed but no RPM was produced in ${new File(workDir, "RPMS/${rpmArchitecture()}")}.") + } + copy { + from(builtRpms.first()) + into(distributionDirectory) + rename { output.name } + } + } +} + +tasks.register('packageLinuxPacman') { + group = 'distribution' + description = 'Builds a self-contained Arch Linux pacman package for the launcher.' + dependsOn tasks.named('prepareLinuxPackageRoot') + onlyIf { + currentOs.isLinux() + } + inputs.dir linuxPackageRootDirectory + outputs.file linuxPacmanFile + doLast { + def tar = resolveExecutable('tar', 'tar', 'Install tar to create pacman packages.') + resolveExecutable('zstd', 'zstd', 'Install zstd to create pacman packages.') + def rootDir = linuxPackageRootDirectory.get().asFile + def workDir = new File(linuxPackageWorkDirectory.get().asFile, 'pacman') + def packageRoot = new File(workDir, 'pkg') + def output = linuxPacmanFile.get().asFile + + delete workDir + packageRoot.mkdirs() + mkdir distributionDirectory.get().asFile + delete output + + copy { + from(rootDir) + into(packageRoot) + } + + long installedBytes = 0 + rootDir.eachFileRecurse(groovy.io.FileType.FILES) { file -> + installedBytes += file.length() + } + + new File(packageRoot, '.PKGINFO').text = """pkgname = ${appSlug} +pkgbase = ${appSlug} +pkgver = ${installerVersion}-${linuxPackageRelease} +pkgdesc = ${appDescription} +url = ${appHomepage} +builddate = 0 +packager = Modtale contributors +size = ${installedBytes} +arch = ${pacmanArchitecture()} +license = ${appLicenseId} +depend = glibc +depend = libx11 +depend = libxext +depend = libxrender +depend = libxtst +depend = libxi +depend = freetype2 +depend = fontconfig +depend = gtk3 +""" + + runExternalCommand([ + tar, '--sort=name', '--mtime=@0', '--owner=0', '--group=0', '--numeric-owner', + '--zstd', '-C', packageRoot.absolutePath, '-cf', output.absolutePath, '.' + ], null, ['ZSTD_CLEVEL': '19']) + } +} + +tasks.register('packageLinuxFlatpak') { + group = 'distribution' + description = 'Builds a self-contained Linux Flatpak bundle for the launcher.' + dependsOn tasks.named('prepareLinuxAppImageRuntime') + onlyIf { + currentOs.isLinux() + } + inputs.dir linuxAppImageDirectory + outputs.file linuxFlatpakFile + doLast { + def flatpak = resolveExecutable('flatpak', 'flatpak', 'Install flatpak to create Flatpak bundles.') + def packagedApp = linuxAppImageDirectory.get().dir(appDisplayName).asFile + if (!packagedApp.exists()) { + throw new GradleException("Expected jpackage app image at ${packagedApp}, but it was not created.") + } + + def buildDir = flatpakBuildDirectory.get().asFile + def repoDir = flatpakRepoDirectory.get().asFile + def filesDir = new File(buildDir, 'files') + def output = linuxFlatpakFile.get().asFile + + delete buildDir + delete repoDir + mkdir distributionDirectory.get().asFile + delete output + + runExternalCommand([ + flatpak, 'build-init', "--arch=${flatpakArchitecture()}", + buildDir.absolutePath, appId, flatpakSdk, flatpakRuntime, flatpakRuntimeVersion + ]) + + copy { + from(packagedApp) + into(new File(filesDir, appSlug)) + } + + def wrapper = new File(filesDir, "bin/${appSlug}") + wrapper.parentFile.mkdirs() +wrapper.text = """#!/usr/bin/env sh +set -eu +APPDIR="/app/${appSlug}" +exec "\$APPDIR/bin/${appDisplayName}" "\$@" +""" + wrapper.setExecutable(true, false) + + copy { + from(appIconPng) + into(new File(filesDir, 'share/icons/hicolor/256x256/apps')) + rename { "${appId}.png" } + } + + def desktopFile = new File(filesDir, "share/applications/${appId}.desktop") + desktopFile.parentFile.mkdirs() + desktopFile.text = desktopFileContent(appSlug, appId) + + def metainfo = new File(filesDir, "share/metainfo/${appId}.appdata.xml") + metainfo.parentFile.mkdirs() + metainfo.text = metainfoContent() + + copy { + from(appLicense) + into(new File(filesDir, "share/licenses/${appSlug}")) + rename { 'LICENSE' } + } + + runExternalCommand([ + flatpak, 'build-finish', + "--command=${appSlug}", + '--share=network', + '--share=ipc', + '--socket=x11', + '--socket=wayland', + '--device=dri', + '--filesystem=home', + '--talk-name=org.freedesktop.portal.Desktop', + buildDir.absolutePath + ]) + runExternalCommand([ + flatpak, 'build-export', "--arch=${flatpakArchitecture()}", + repoDir.absolutePath, buildDir.absolutePath, flatpakBranch + ]) + runExternalCommand([ + flatpak, 'build-bundle', "--arch=${flatpakArchitecture()}", + repoDir.absolutePath, output.absolutePath, appId, flatpakBranch + ]) + } +} + +tasks.register('packageLinuxInstallers') { + group = 'distribution' + description = 'Builds Linux Flatpak, RPM, DEB, and pacman launcher packages.' + dependsOn tasks.named('packageLinuxFlatpak'), tasks.named('packageLinuxRpm'), tasks.named('packageLinuxDeb'), tasks.named('packageLinuxPacman') +} + +tasks.register('packageLinuxAll') { + group = 'distribution' + description = 'Builds all Linux launcher package formats, including AppImage, Flatpak, RPM, DEB, and pacman.' + dependsOn tasks.named('packageLinux'), tasks.named('packageLinuxInstallers') +} + +tasks.register('packageAll') { + group = 'distribution' + description = 'Builds the self-contained native installer for the current OS. Run on Windows, macOS, and Linux hosts to produce all release artifacts.' + dependsOn tasks.named('packageMac'), tasks.named('packageWindows'), tasks.named('packageLinux') +} + +tasks.register('jpackageAppImage', Exec) { + group = 'distribution' + description = 'Builds a self-contained unpacked app image for the current host OS.' + dependsOn tasks.named('prepareJpackageInput') + doFirst { + def executable = jpackageExecutable.get() + if (!executable.exists()) { + throw new GradleException("jpackage was not found at ${executable}. Install a full JDK 21 to build native launcher app images.") + } + + delete layout.buildDirectory.dir('jpackage/app-image') + commandLine([ + executable.absolutePath, + '--type', 'app-image', + '--dest', layout.buildDirectory.dir('jpackage/app-image').get().asFile.absolutePath + ] + commonJpackageArgs.call()) + } +} + +tasks.named('assemble') { + dependsOn tasks.named('packageAll') +} + +tasks.named('distZip') { + enabled = false +} + +tasks.named('distTar') { + enabled = false +} + +tasks.named('assembleDist') { + enabled = false +} + +tasks.named('installDist') { + enabled = false +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' + options.compilerArgs += ['-parameters'] +} + +tasks.named('test') { + useJUnitPlatform() +} + +def javafxPlatform() { + def os = org.gradle.internal.os.OperatingSystem.current() + def arch = System.getProperty('os.arch', '').toLowerCase(Locale.ROOT) + if (os.isWindows()) { + return 'win' + } + if (os.isMacOsX()) { + return arch.contains('aarch64') || arch.contains('arm64') ? 'mac-aarch64' : 'mac' + } + return arch.contains('aarch64') || arch.contains('arm64') ? 'linux-aarch64' : 'linux' +} + +def appImageArch() { + def arch = System.getProperty('os.arch', '').toLowerCase(Locale.ROOT) + if (arch == 'amd64' || arch == 'x86_64') { + return 'x86_64' + } + if (arch.contains('aarch64') || arch.contains('arm64')) { + return 'aarch64' + } + return arch.replaceAll(/[^a-z0-9_+-]/, '-') +} + +def debArchitecture() { + def arch = System.getProperty('os.arch', '').toLowerCase(Locale.ROOT) + if (arch == 'amd64' || arch == 'x86_64') { + return 'amd64' + } + if (arch.contains('aarch64') || arch.contains('arm64')) { + return 'arm64' + } + return arch.replaceAll(/[^a-z0-9_+-]/, '-') +} + +def rpmArchitecture() { + def arch = System.getProperty('os.arch', '').toLowerCase(Locale.ROOT) + if (arch == 'amd64') { + return 'x86_64' + } + if (arch.contains('aarch64') || arch.contains('arm64')) { + return 'aarch64' + } + return arch.replaceAll(/[^a-z0-9_+-]/, '-') +} + +def flatpakArchitecture() { + def arch = System.getProperty('os.arch', '').toLowerCase(Locale.ROOT) + if (arch == 'amd64' || arch == 'x86_64') { + return 'x86_64' + } + if (arch.contains('aarch64') || arch.contains('arm64')) { + return 'aarch64' + } + return arch.replaceAll(/[^a-z0-9_+-]/, '-') +} + +def pacmanArchitecture() { + def arch = System.getProperty('os.arch', '').toLowerCase(Locale.ROOT) + if (arch == 'amd64' || arch == 'x86_64') { + return 'x86_64' + } + if (arch.contains('aarch64') || arch.contains('arm64')) { + return 'aarch64' + } + return arch.replaceAll(/[^a-z0-9_+-]/, '-') +} + +def runExternalCommand(List command, File workingDirectory = null, Map environmentOverrides = [:]) { + def normalizedCommand = command.collect { it.toString() } + def processBuilder = new ProcessBuilder(normalizedCommand) + if (workingDirectory != null) { + processBuilder.directory(workingDirectory) + } + processBuilder.environment().putAll(environmentOverrides) + processBuilder.inheritIO() + def process = processBuilder.start() + def exitCode = process.waitFor() + if (exitCode != 0) { + throw new GradleException("Command failed with exit code ${exitCode}: ${normalizedCommand.join(' ')}") + } +} + +def resolveExecutable(String candidate, String displayName, String installHint = "Install ${displayName}, or configure its path.") { + def candidateFile = new File(candidate) + if (candidateFile.isAbsolute() || candidate.contains(File.separator)) { + if (!candidateFile.isAbsolute()) { + candidateFile = file(candidate) + } + if (candidateFile.exists() && candidateFile.canExecute()) { + return candidateFile.absolutePath + } + throw new GradleException("${displayName} was not found or is not executable at ${candidateFile}. ${installHint}") + } + + def path = System.getenv('PATH') ?: '' + for (String entry : path.split(File.pathSeparator)) { + if (entry == null || entry.isBlank()) { + continue + } + def executable = new File(entry, candidate) + if (executable.exists() && executable.canExecute()) { + return executable.absolutePath + } + } + + throw new GradleException("${displayName} was not found on PATH. ${installHint}") +} diff --git a/launcher/gradle/wrapper/gradle-wrapper.jar b/launcher/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..61285a659d17295f1de7c53e24fdf13ad755c379 GIT binary patch literal 46175 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

    pVX@HRij*jw$g4?}Pn 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 literal 0 HcmV?d00001 diff --git a/launcher/gradle/wrapper/gradle-wrapper.properties b/launcher/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..19a6bdeb --- /dev/null +++ b/launcher/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/launcher/gradlew b/launcher/gradlew new file mode 100755 index 00000000..adff685a --- /dev/null +++ b/launcher/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/launcher/gradlew.bat b/launcher/gradlew.bat new file mode 100644 index 00000000..c4bdd3ab --- /dev/null +++ b/launcher/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/launcher/settings.gradle b/launcher/settings.gradle new file mode 100644 index 00000000..de0be0d3 --- /dev/null +++ b/launcher/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'modtale-launcher' + diff --git a/launcher/src/main/java/net/modtale/launcher/LauncherMain.java b/launcher/src/main/java/net/modtale/launcher/LauncherMain.java new file mode 100644 index 00000000..c4a375ef --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/LauncherMain.java @@ -0,0 +1,14 @@ +package net.modtale.launcher; + +import javafx.application.Application; + +public final class LauncherMain { + + private LauncherMain() { + } + + public static void main(String[] args) { + LauncherRenderSettings.configure(); + Application.launch(ModtaleLauncher.class, args); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/LauncherPerformanceProbe.java b/launcher/src/main/java/net/modtale/launcher/LauncherPerformanceProbe.java new file mode 100644 index 00000000..93d11c65 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/LauncherPerformanceProbe.java @@ -0,0 +1,264 @@ +package net.modtale.launcher; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import javafx.animation.AnimationTimer; +import javafx.scene.Scene; + +public final class LauncherPerformanceProbe { + + public static final String PERF_LOG_PROPERTY = "modtale.launcher.perfLog"; + public static final String PERF_REFRESH_RATE_PROPERTY = "modtale.launcher.perfRefreshRate"; + + private static final long REPORT_INTERVAL_NANOS = 1_000_000_000L; + private static final double DEFAULT_REFRESH_RATE = 60.0; + private static final ConcurrentMap OPERATION_STATS = new ConcurrentHashMap<>(); + private static volatile boolean operationTimingEnabled; + + private LauncherPerformanceProbe() { + } + + public static void install(Scene scene) { + String outputPath = System.getProperty(PERF_LOG_PROPERTY); + if (outputPath == null || outputPath.isBlank()) { + return; + } + + operationTimingEnabled = true; + FrameTimer timer = new FrameTimer(Path.of(outputPath), targetFrameMillis()); + scene.windowProperty().addListener((observable, oldWindow, newWindow) -> { + if (newWindow == null) { + timer.stop(); + } else { + timer.start(); + } + }); + if (scene.getWindow() != null) { + timer.start(); + } + } + + public static long operationStartNanos() { + return operationTimingEnabled ? System.nanoTime() : 0; + } + + public static void recordOperation(String name, long startNanos) { + if (!operationTimingEnabled || startNanos == 0 || name == null || name.isBlank()) { + return; + } + OPERATION_STATS.computeIfAbsent(name, ignored -> new OperationStats()).add(System.nanoTime() - startNanos); + } + + private static double targetFrameMillis() { + String configured = System.getProperty(PERF_REFRESH_RATE_PROPERTY, + System.getProperty(LauncherRenderSettings.REFRESH_RATE_OVERRIDE_PROPERTY)); + if (configured != null && !configured.isBlank()) { + try { + double refreshRate = Double.parseDouble(configured.trim()); + if (Double.isFinite(refreshRate) && refreshRate > 0) { + return 1000.0 / refreshRate; + } + } catch (NumberFormatException ignored) { + // Fall back to the default below. + } + } + return 1000.0 / DEFAULT_REFRESH_RATE; + } + + private static final class FrameTimer extends AnimationTimer { + + private final Path outputPath; + private final double targetFrameMillis; + private final List intervals = new ArrayList<>(256); + private long previousFrame; + private long windowStart; + private boolean running; + + private FrameTimer(Path outputPath, double targetFrameMillis) { + this.outputPath = outputPath; + this.targetFrameMillis = targetFrameMillis; + write("start targetFrameMillis=" + format(targetFrameMillis) + " at=" + Instant.now()); + } + + @Override + public void start() { + if (running) { + return; + } + running = true; + previousFrame = 0; + windowStart = 0; + super.start(); + } + + @Override + public void stop() { + if (!running) { + return; + } + report("stop"); + running = false; + previousFrame = 0; + windowStart = 0; + super.stop(); + } + + @Override + public void handle(long now) { + if (previousFrame != 0) { + intervals.add((now - previousFrame) / 1_000_000.0); + } + previousFrame = now; + if (windowStart == 0) { + windowStart = now; + } + if (now - windowStart >= REPORT_INTERVAL_NANOS) { + report("window"); + windowStart = now; + } + } + + private void report(String reason) { + if (intervals.isEmpty()) { + reportOperations(reason); + return; + } + + List sorted = new ArrayList<>(intervals); + Collections.sort(sorted); + double avg = intervals.stream().mapToDouble(Double::doubleValue).average().orElse(0); + double p95 = percentile(sorted, 0.95); + double p99 = percentile(sorted, 0.99); + double max = sorted.get(sorted.size() - 1); + double missedFrameThreshold = targetFrameMillis * 1.35; + long missed = intervals.stream().filter(value -> value > missedFrameThreshold).count(); + long overTwoFrames = intervals.stream().filter(value -> value > targetFrameMillis * 2.0).count(); + write("%s frames=%d avgMs=%s p95Ms=%s p99Ms=%s maxMs=%s missed=%d overTwoFrames=%d thresholdMs=%s at=%s" + .formatted( + reason, + intervals.size(), + format(avg), + format(p95), + format(p99), + format(max), + missed, + overTwoFrames, + format(missedFrameThreshold), + Instant.now() + )); + intervals.clear(); + reportOperations(reason); + } + + private void reportOperations(String reason) { + List reports = OPERATION_STATS.entrySet().stream() + .map(entry -> OperationReport.from(entry.getKey(), entry.getValue().drain())) + .filter(OperationReport::hasSamples) + .sorted(Comparator.comparing(OperationReport::name)) + .toList(); + for (OperationReport report : reports) { + write("operation %s name=%s samples=%d avgUs=%s p95Us=%s p99Us=%s maxUs=%s over1Ms=%d at=%s" + .formatted( + reason, + report.name(), + report.samples(), + format(report.avgMicros()), + format(report.p95Micros()), + format(report.p99Micros()), + format(report.maxMicros()), + report.overOneMillisecond(), + Instant.now() + )); + } + } + + private double percentile(List sorted, double percentile) { + if (sorted.isEmpty()) { + return 0; + } + int index = Math.max(0, Math.min(sorted.size() - 1, + (int) Math.ceil(sorted.size() * percentile) - 1)); + return sorted.get(index); + } + + private void write(String line) { + try { + Path parent = outputPath.getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + Files.writeString(outputPath, line + System.lineSeparator(), + StandardOpenOption.CREATE, StandardOpenOption.APPEND); + } catch (IOException ignored) { + // Diagnostics must never affect launcher behavior. + } + } + + private static String format(double value) { + return String.format(java.util.Locale.US, "%.3f", value); + } + } + + private static final class OperationStats { + + private final List samples = new ArrayList<>(1024); + + private synchronized void add(long nanos) { + samples.add(Math.max(0, nanos)); + } + + private synchronized List drain() { + if (samples.isEmpty()) { + return List.of(); + } + List drained = new ArrayList<>(samples); + samples.clear(); + return drained; + } + } + + private record OperationReport( + String name, + int samples, + double avgMicros, + double p95Micros, + double p99Micros, + double maxMicros, + long overOneMillisecond + ) { + + private boolean hasSamples() { + return samples > 0; + } + + private static OperationReport from(String name, List samples) { + if (samples.isEmpty()) { + return new OperationReport(name, 0, 0, 0, 0, 0, 0); + } + List sorted = new ArrayList<>(samples); + Collections.sort(sorted); + double avgMicros = samples.stream().mapToDouble(value -> value / 1_000.0).average().orElse(0); + double p95Micros = percentile(sorted, 0.95) / 1_000.0; + double p99Micros = percentile(sorted, 0.99) / 1_000.0; + double maxMicros = sorted.getLast() / 1_000.0; + long overOneMillisecond = samples.stream().filter(value -> value > 1_000_000).count(); + return new OperationReport(name, samples.size(), avgMicros, p95Micros, p99Micros, maxMicros, + overOneMillisecond); + } + + private static long percentile(List sorted, double percentile) { + int index = Math.max(0, Math.min(sorted.size() - 1, + (int) Math.ceil(sorted.size() * percentile) - 1)); + return sorted.get(index); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/LauncherRenderSettings.java b/launcher/src/main/java/net/modtale/launcher/LauncherRenderSettings.java new file mode 100644 index 00000000..964e2104 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/LauncherRenderSettings.java @@ -0,0 +1,125 @@ +package net.modtale.launcher; + +import java.awt.AWTError; +import java.awt.DisplayMode; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.util.OptionalInt; +import java.util.Properties; + +final class LauncherRenderSettings { + + static final String REFRESH_RATE_OVERRIDE_PROPERTY = "modtale.launcher.refreshRate"; + static final String JAVAFX_FRAME_RATE_PROPERTY = "javafx.animation.framerate"; + static final String JAVAFX_PULSE_PROPERTY = "javafx.animation.pulse"; + static final String PRISM_ORDER_PROPERTY = "prism.order"; + static final String PRISM_VSYNC_PROPERTY = "prism.vsync"; + + private static final int DEFAULT_REFRESH_RATE = 60; + private static final int MIN_REFRESH_RATE = 30; + private static final int MAX_REFRESH_RATE = 1000; + private static final String WINDOWS_PRISM_ORDER = "d3d,sw"; + private static final String MACOS_PRISM_ORDER = "es2,sw"; + private static final String LINUX_PRISM_ORDER = "es2,sw"; + + private LauncherRenderSettings() { + } + + static void configure() { + configure(System.getProperties(), System.getProperty("os.name"), detectDisplayRefreshRate()); + } + + static void configure(Properties properties, String osName, OptionalInt detectedRefreshRate) { + OptionalInt configuredRefreshRate = parseRefreshRate(properties.getProperty(REFRESH_RATE_OVERRIDE_PROPERTY)); + OptionalInt targetRefreshRate = configuredRefreshRate; + if (configuredRefreshRate.isEmpty()) { + targetRefreshRate = detectedRefreshRate; + } + configureFrameRate(properties, targetRefreshRate, configuredRefreshRate.isPresent()); + setDefault(properties, PRISM_ORDER_PROPERTY, prismOrder(osName)); + setDefault(properties, PRISM_VSYNC_PROPERTY, "true"); + } + + static OptionalInt preferredRefreshRate(int... refreshRates) { + OptionalInt preferred = OptionalInt.empty(); + for (int refreshRate : refreshRates) { + OptionalInt normalized = normalizeRefreshRate(refreshRate); + if (normalized.isPresent() && (preferred.isEmpty() || normalized.getAsInt() > preferred.getAsInt())) { + preferred = normalized; + } + } + return preferred; + } + + private static void configureFrameRate(Properties properties, OptionalInt targetRefreshRate, boolean explicitRefreshRate) { + if (targetRefreshRate.isEmpty() + || (!explicitRefreshRate && targetRefreshRate.getAsInt() <= DEFAULT_REFRESH_RATE) + || hasSetting(properties, JAVAFX_FRAME_RATE_PROPERTY) + || hasSetting(properties, JAVAFX_PULSE_PROPERTY)) { + return; + } + String refreshRate = Integer.toString(targetRefreshRate.getAsInt()); + properties.setProperty(JAVAFX_FRAME_RATE_PROPERTY, refreshRate); + properties.setProperty(JAVAFX_PULSE_PROPERTY, refreshRate); + } + + private static OptionalInt detectDisplayRefreshRate() { + if (GraphicsEnvironment.isHeadless()) { + return OptionalInt.empty(); + } + try { + GraphicsDevice[] devices = GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getScreenDevices(); + int[] refreshRates = new int[devices.length]; + for (int i = 0; i < devices.length; i++) { + refreshRates[i] = devices[i].getDisplayMode().getRefreshRate(); + } + return preferredRefreshRate(refreshRates); + } catch (AWTError | RuntimeException ex) { + return OptionalInt.empty(); + } + } + + private static OptionalInt parseRefreshRate(String value) { + if (value == null || value.isBlank()) { + return OptionalInt.empty(); + } + try { + return normalizeRefreshRate(Integer.parseInt(value.trim())); + } catch (NumberFormatException ex) { + return OptionalInt.empty(); + } + } + + private static OptionalInt normalizeRefreshRate(int refreshRate) { + if (refreshRate == DisplayMode.REFRESH_RATE_UNKNOWN + || refreshRate < MIN_REFRESH_RATE + || refreshRate > MAX_REFRESH_RATE) { + return OptionalInt.empty(); + } + return OptionalInt.of(refreshRate); + } + + private static String prismOrder(String osName) { + String normalized = osName == null ? "" : osName.toLowerCase(); + if (normalized.contains("win")) { + return WINDOWS_PRISM_ORDER; + } + if (normalized.contains("mac") || normalized.contains("darwin")) { + return MACOS_PRISM_ORDER; + } + return LINUX_PRISM_ORDER; + } + + private static void setDefault(Properties properties, String key, String value) { + if (!hasSetting(properties, key)) { + properties.setProperty(key, value); + } + } + + private static boolean hasSetting(Properties properties, String key) { + String value = properties.getProperty(key); + return value != null && !value.isBlank(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ModtaleLauncher.java b/launcher/src/main/java/net/modtale/launcher/ModtaleLauncher.java new file mode 100644 index 00000000..2dc1b44b --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ModtaleLauncher.java @@ -0,0 +1,27 @@ +package net.modtale.launcher; + +import javafx.application.Application; +import javafx.stage.Stage; +import net.modtale.launcher.ui.shell.LauncherRuntime; + +public final class ModtaleLauncher extends Application { + + private LauncherRuntime runtime; + + public static void main(String[] args) { + LauncherMain.main(args); + } + + @Override + public void start(Stage stage) { + runtime = LauncherRuntime.create(); + runtime.start(stage, getParameters()); + } + + @Override + public void stop() { + if (runtime != null) { + runtime.shutdown(); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/ApiCachePolicy.java b/launcher/src/main/java/net/modtale/launcher/api/ApiCachePolicy.java new file mode 100644 index 00000000..2ad47b2b --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ApiCachePolicy.java @@ -0,0 +1,35 @@ +package net.modtale.launcher.api; + +import java.time.Duration; + +final class ApiCachePolicy { + + private ApiCachePolicy() { + } + + static Duration ttlFor(String pathAndQuery) { + if (!isPublicCacheableGet(pathAndQuery)) { + return Duration.ZERO; + } + if (pathAndQuery.startsWith("/meta/")) { + return Duration.ofHours(24); + } + if (pathAndQuery.startsWith("/projects")) { + return Duration.ofHours(26); + } + return Duration.ofHours(2); + } + + static boolean isEnabled(Duration ttl) { + return ttl != null && !ttl.isZero() && !ttl.isNegative(); + } + + private static boolean isPublicCacheableGet(String pathAndQuery) { + String normalized = pathAndQuery == null ? "" : pathAndQuery; + return normalized.startsWith("/meta/") + || (normalized.startsWith("/projects") + && !normalized.contains("/comments") + && !normalized.contains("/download-url") + && !normalized.contains("/download-bundle-url")); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/ApiPathBuilder.java b/launcher/src/main/java/net/modtale/launcher/api/ApiPathBuilder.java new file mode 100644 index 00000000..cf3be589 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ApiPathBuilder.java @@ -0,0 +1,38 @@ +package net.modtale.launcher.api; + +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + +final class ApiPathBuilder { + + private ApiPathBuilder() { + } + + static URI normalizeBaseUri(String apiBaseUrl, String fallbackBaseUrl) { + String value = apiBaseUrl == null || apiBaseUrl.isBlank() ? fallbackBaseUrl : apiBaseUrl.trim(); + return URI.create(value.replaceAll("/+$", "")); + } + + static URI apiUri(URI apiBaseUri, String pathAndQuery) { + String base = apiBaseUri.toString().replaceAll("/+$", ""); + String path = pathAndQuery.startsWith("/") ? pathAndQuery : "/" + pathAndQuery; + return URI.create(base + path); + } + + static void addParam(List params, String name, String value) { + if (value == null || value.isBlank()) { + return; + } + params.add(encodeQuery(name) + "=" + encodeQuery(value)); + } + + static String encodePath(String value) { + return encodeQuery(value).replace("+", "%20"); + } + + static String encodeQuery(String value) { + return URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/ApiResponseCache.java b/launcher/src/main/java/net/modtale/launcher/api/ApiResponseCache.java new file mode 100644 index 00000000..603b0209 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ApiResponseCache.java @@ -0,0 +1,154 @@ +package net.modtale.launcher.api; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.time.Instant; +import java.util.Comparator; +import java.util.HexFormat; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.stream.Stream; +import net.modtale.launcher.cache.LauncherCachePaths; + +final class ApiResponseCache { + + private static final Duration STALE_FALLBACK_TTL = Duration.ofDays(7); + + private final Path cacheDirectory; + private final ObjectMapper mapper; + private final ConcurrentMap memory = new ConcurrentHashMap<>(); + + ApiResponseCache() { + this(LauncherCachePaths.cacheDirectory("api")); + } + + ApiResponseCache(Path cacheDirectory) { + this.cacheDirectory = cacheDirectory; + this.mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + Optional getFresh(URI uri, Duration ttl) { + return get(uri, ttl); + } + + Optional getStaleFallback(URI uri) { + return get(uri, STALE_FALLBACK_TTL); + } + + void put(URI uri, String body) { + if (body == null) { + return; + } + String key = uri.toString(); + CacheEntry entry = new CacheEntry(body, Instant.now()); + memory.put(key, entry); + try { + Files.createDirectories(cacheDirectory); + mapper.writeValue(cacheFile(uri).toFile(), CachedBody.from(entry)); + } catch (IOException ignored) { + // The in-memory cache is still useful if the disk cache cannot be written. + } + } + + void invalidate(URI uri) { + memory.remove(uri.toString()); + try { + Files.deleteIfExists(cacheFile(uri)); + } catch (IOException ignored) { + // Cache cleanup is best-effort. + } + } + + void clear() { + memory.clear(); + if (!Files.exists(cacheDirectory)) { + return; + } + try (Stream stream = Files.walk(cacheDirectory)) { + List paths = stream + .filter(path -> !cacheDirectory.equals(path)) + .sorted(Comparator.reverseOrder()) + .toList(); + for (Path path : paths) { + Files.deleteIfExists(path); + } + } catch (IOException ignored) { + // Cache cleanup is best-effort. + } + } + + private Optional get(URI uri, Duration ttl) { + if (ttl == null || ttl.isNegative() || ttl.isZero()) { + return Optional.empty(); + } + + String key = uri.toString(); + CacheEntry memoryEntry = memory.get(key); + if (memoryEntry != null && memoryEntry.isFresh(ttl)) { + return Optional.of(memoryEntry.body()); + } + + Optional diskEntry = readDisk(uri); + diskEntry.ifPresent(entry -> memory.put(key, entry)); + return diskEntry.filter(entry -> entry.isFresh(ttl)).map(CacheEntry::body); + } + + private Optional readDisk(URI uri) { + Path file = cacheFile(uri); + if (!Files.isRegularFile(file)) { + return Optional.empty(); + } + try { + CachedBody cached = mapper.readValue(file.toFile(), CachedBody.class); + if (cached.body() == null || cached.writtenAtEpochMilli() <= 0) { + invalidate(uri); + return Optional.empty(); + } + return Optional.of(new CacheEntry(cached.body(), Instant.ofEpochMilli(cached.writtenAtEpochMilli()))); + } catch (IOException ex) { + invalidate(uri); + return Optional.empty(); + } + } + + private Path cacheFile(URI uri) { + return cacheDirectory.resolve(sha256(uri.toString()) + ".json"); + } + + private static String sha256(String value) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] bytes = digest.digest(value.getBytes(StandardCharsets.UTF_8)); + return HexFormat.of().formatHex(bytes); + } catch (NoSuchAlgorithmException ex) { + throw new IllegalStateException("SHA-256 is not available.", ex); + } + } + + private record CacheEntry(String body, Instant writtenAt) { + + boolean isFresh(Duration ttl) { + return writtenAt != null && writtenAt.plus(ttl).isAfter(Instant.now()); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private record CachedBody(long writtenAtEpochMilli, String body) { + + static CachedBody from(CacheEntry entry) { + return new CachedBody(entry.writtenAt().toEpochMilli(), entry.body()); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/LauncherSessionStore.java b/launcher/src/main/java/net/modtale/launcher/api/LauncherSessionStore.java new file mode 100644 index 00000000..e6f44703 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/LauncherSessionStore.java @@ -0,0 +1,188 @@ +package net.modtale.launcher.api; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; + +final class LauncherSessionStore { + + private static final Duration MAX_SESSION_AGE = Duration.ofDays(7); + private static final Set SESSION_COOKIE_NAMES = Set.of("SESSION", "JSESSIONID", "XSRF-TOKEN"); + + private final Path sessionPath; + private final ObjectMapper mapper = new ObjectMapper(); + + LauncherSessionStore(Path sessionPath) { + this.sessionPath = sessionPath; + } + + synchronized boolean loadInto(CookieStore cookieStore, URI baseUri) { + if (sessionPath == null || !Files.exists(sessionPath)) { + return false; + } + + try { + List storedCookies = mapper.readValue( + sessionPath.toFile(), + new TypeReference<>() { + } + ); + Instant now = Instant.now(); + int loaded = 0; + for (StoredCookie storedCookie : storedCookies) { + Optional cookie = storedCookie.toHttpCookie(now); + if (cookie.isPresent()) { + cookieStore.add(storedCookie.originUri(baseUri), cookie.get()); + loaded++; + } + } + if (loaded == 0) { + clear(cookieStore); + return false; + } + return true; + } catch (IOException | RuntimeException ex) { + clear(cookieStore); + return false; + } + } + + synchronized void saveFrom(CookieStore cookieStore, URI baseUri) { + if (sessionPath == null) { + return; + } + + Instant now = Instant.now(); + List storedCookies = cookieStore.get(baseUri).stream() + .filter(LauncherSessionStore::isSessionCookie) + .flatMap(cookie -> StoredCookie.from(baseUri, cookie, now).stream()) + .toList(); + + if (storedCookies.isEmpty()) { + clear(cookieStore); + return; + } + + try { + Path parent = sessionPath.getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + mapper.writerWithDefaultPrettyPrinter().writeValue(sessionPath.toFile(), storedCookies); + } catch (IOException ex) { + throw new ModtaleApiException("Could not save launcher session to " + sessionPath, ex); + } + } + + synchronized void clear(CookieStore cookieStore) { + cookieStore.removeAll(); + if (sessionPath == null) { + return; + } + try { + Files.deleteIfExists(sessionPath); + } catch (IOException ex) { + throw new ModtaleApiException("Could not clear launcher session from " + sessionPath, ex); + } + } + + boolean hasSessionFile() { + return sessionPath != null && Files.exists(sessionPath); + } + + private static boolean isSessionCookie(HttpCookie cookie) { + return cookie != null + && SESSION_COOKIE_NAMES.contains(cookie.getName().toUpperCase(Locale.ROOT)) + && !cookie.hasExpired(); + } + + private static final class StoredCookie { + public String name; + public String value; + public String domain; + public String path; + public boolean secure; + public boolean httpOnly; + public int version; + public String portList; + public String originUri; + public long expiresAtEpochSecond; + + public StoredCookie() { + } + + private static Optional from(URI baseUri, HttpCookie cookie, Instant now) { + if (!isSessionCookie(cookie)) { + return Optional.empty(); + } + + long maxAge = cookie.getMaxAge(); + long ttlSeconds = maxAge < 0 + ? MAX_SESSION_AGE.toSeconds() + : Math.min(maxAge, MAX_SESSION_AGE.toSeconds()); + if (ttlSeconds <= 0) { + return Optional.empty(); + } + + StoredCookie storedCookie = new StoredCookie(); + storedCookie.name = cookie.getName(); + storedCookie.value = cookie.getValue(); + storedCookie.domain = cookie.getDomain(); + storedCookie.path = cookie.getPath(); + storedCookie.secure = cookie.getSecure(); + storedCookie.httpOnly = cookie.isHttpOnly(); + storedCookie.version = cookie.getVersion(); + storedCookie.portList = cookie.getPortlist(); + storedCookie.originUri = baseUri.toString(); + storedCookie.expiresAtEpochSecond = now.plusSeconds(ttlSeconds).getEpochSecond(); + return Optional.of(storedCookie); + } + + private Optional toHttpCookie(Instant now) { + if (name == null || name.isBlank() || value == null) { + return Optional.empty(); + } + + long remainingSeconds = expiresAtEpochSecond - now.getEpochSecond(); + if (remainingSeconds <= 0) { + return Optional.empty(); + } + + HttpCookie cookie = new HttpCookie(name, value); + if (domain != null && !domain.isBlank()) { + cookie.setDomain(domain); + } + cookie.setPath(path == null || path.isBlank() ? "/" : path); + cookie.setSecure(secure); + cookie.setHttpOnly(httpOnly); + cookie.setVersion(version); + cookie.setMaxAge(remainingSeconds); + if (portList != null && !portList.isBlank()) { + cookie.setPortlist(portList); + } + return Optional.of(cookie); + } + + private URI originUri(URI fallback) { + if (originUri == null || originUri.isBlank()) { + return fallback; + } + try { + return URI.create(originUri); + } catch (IllegalArgumentException ex) { + return fallback; + } + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiClient.java b/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiClient.java new file mode 100644 index 00000000..5b596dfb --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiClient.java @@ -0,0 +1,524 @@ +package net.modtale.launcher.api; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.net.CookieManager; +import java.net.CookiePolicy; +import java.net.HttpCookie; +import java.net.URI; +import java.net.http.HttpClient; +import java.nio.file.Path; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import net.modtale.launcher.model.auth.SignInResponse; +import net.modtale.launcher.model.notification.LauncherNotification; +import net.modtale.launcher.model.project.DownloadUrlResponse; +import net.modtale.launcher.model.project.GameVersionCatalog; +import net.modtale.launcher.model.project.ProjectComment; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectGallery; +import net.modtale.launcher.model.project.ProjectMeta; +import net.modtale.launcher.model.project.ProjectPage; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.model.project.ProjectVersionChangelog; +import net.modtale.launcher.model.project.VersionDependenciesView; +import net.modtale.launcher.model.sync.LauncherSettingsSnapshot; +import net.modtale.launcher.model.user.CreatorProfile; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.model.user.UserSummary; +import net.modtale.launcher.model.worldlist.CreateWorldModListRequest; +import net.modtale.launcher.model.worldlist.WorldModList; + +public class ModtaleApiClient { + + public static final String DEFAULT_API_BASE_URL = "https://api.modtale.net/api/v1"; + public static final String DEFAULT_SITE_BASE_URL = "https://modtale.net"; + + private final CookieManager cookieManager; + private final ModtaleApiTransport transport; + private final ModtaleDownloadClient downloadClient; + private final LauncherSessionStore sessionStore; + private volatile URI apiBaseUri; + private volatile boolean storedSessionLoaded; + + public ModtaleApiClient(String apiBaseUrl) { + this(apiBaseUrl, null); + } + + public ModtaleApiClient(String apiBaseUrl, Path sessionPath) { + this(defaultCookieManager(), apiBaseUrl, new ApiResponseCache(), + sessionPath == null ? null : new LauncherSessionStore(sessionPath)); + } + + private ModtaleApiClient( + CookieManager cookieManager, + String apiBaseUrl, + ApiResponseCache responseCache, + LauncherSessionStore sessionStore + ) { + this(HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(15)) + .cookieHandler(cookieManager) + .followRedirects(HttpClient.Redirect.NORMAL) + .build(), cookieManager, apiBaseUrl, responseCache, sessionStore); + } + + ModtaleApiClient(HttpClient httpClient, String apiBaseUrl) { + this(httpClient, apiBaseUrl, new ApiResponseCache()); + } + + ModtaleApiClient(HttpClient httpClient, String apiBaseUrl, ApiResponseCache responseCache) { + this(httpClient, null, apiBaseUrl, responseCache, null); + } + + private ModtaleApiClient( + HttpClient httpClient, + CookieManager cookieManager, + String apiBaseUrl, + ApiResponseCache responseCache, + LauncherSessionStore sessionStore + ) { + this.cookieManager = cookieManager; + this.transport = new ModtaleApiTransport(httpClient, responseCache, this::csrfToken); + this.downloadClient = new ModtaleDownloadClient(httpClient, this::apiBaseUri); + this.sessionStore = sessionStore; + configure(apiBaseUrl); + if (this.sessionStore != null && this.cookieManager != null) { + storedSessionLoaded = this.sessionStore.loadInto(this.cookieManager.getCookieStore(), apiBaseUri); + } + } + + public final void configure(String apiBaseUrl) { + this.apiBaseUri = ApiPathBuilder.normalizeBaseUri(apiBaseUrl, DEFAULT_API_BASE_URL); + } + + public URI apiBaseUri() { + return apiBaseUri; + } + + public SignInResponse signIn(String username, char[] password) { + SignInResponse response = post("/auth/signin", java.util.Map.of( + "username", username == null ? "" : username.trim(), + "password", password == null ? "" : new String(password) + ), SignInResponse.class); + if (response != null && !response.mfaRequired()) { + saveStoredSession(); + } + return response; + } + + public void validateMfa(String preAuthToken, String code) { + post("/auth/mfa/validate-login", java.util.Map.of( + "pre_auth_token", preAuthToken == null ? "" : preAuthToken, + "code", code == null ? "" : code.trim() + ), Object.class); + saveStoredSession(); + } + + public void exchangeLauncherCode(String code) { + post("/auth/launcher/exchange", java.util.Map.of( + "code", code == null ? "" : code.trim() + ), Object.class); + saveStoredSession(); + } + + public CurrentUser currentUser() { + CurrentUser user = get("/user/me", CurrentUser.class); + saveStoredSession(); + return user; + } + + public void logout() { + try { + post("/auth/logout", java.util.Map.of(), Object.class); + } finally { + clearStoredSession(); + } + } + + public boolean hasStoredSession() { + return storedSessionLoaded || (sessionStore != null && sessionStore.hasSessionFile()); + } + + public void clearStoredSession() { + storedSessionLoaded = false; + if (sessionStore != null && cookieManager != null) { + sessionStore.clear(cookieManager.getCookieStore()); + } + } + + public void clearResponseCache() { + transport.clearResponseCache(); + } + + public ProjectPage searchProjects(ProjectSearchQuery query) { + List params = new ArrayList<>(); + addParam(params, "page", Integer.toString(query.page())); + addParam(params, "size", Integer.toString(query.size())); + addParam(params, "sort", query.sort()); + addParam(params, "search", query.search()); + addParam(params, "classification", query.classification()); + addParam(params, "gameVersion", query.gameVersion()); + addParam(params, "tags", query.tags()); + if (query.minDownloads() != null) { + addParam(params, "minDownloads", Integer.toString(query.minDownloads())); + } + if (query.minFavorites() != null) { + addParam(params, "minFavorites", Integer.toString(query.minFavorites())); + } + addParam(params, "category", query.category()); + addParam(params, "dateRange", query.dateRange()); + if (Boolean.TRUE.equals(query.openSource())) { + addParam(params, "openSource", "true"); + } + return get("/projects" + (params.isEmpty() ? "" : "?" + String.join("&", params)), ProjectPage.class); + } + + public ProjectDetail getProject(String idOrSlug) { + return get("/projects/" + encodePath(idOrSlug), ProjectDetail.class); + } + + public ProjectGallery getProjectGallery(String idOrSlug) { + ProjectGallery gallery = get("/projects/" + encodePath(idOrSlug) + "/gallery", ProjectGallery.class); + return gallery == null ? new ProjectGallery(List.of(), java.util.Map.of()) : gallery; + } + + public ProjectMeta getProjectMeta(String idOrSlug) { + return get("/projects/" + encodePath(idOrSlug) + "/meta", ProjectMeta.class); + } + + public Map getProjectMetaBatch(List projectIds) { + List ids = projectIds == null + ? List.of() + : projectIds.stream() + .filter(id -> id != null && !id.isBlank()) + .map(String::trim) + .distinct() + .limit(50) + .toList(); + if (ids.isEmpty()) { + return Map.of(); + } + List params = new ArrayList<>(); + addParam(params, "ids", String.join(",", ids)); + return get("/projects/meta?" + String.join("&", params), new TypeReference<>() {}); + } + + public CreatorProfile getUserProfile(String idOrHandle) { + return get("/user/profile/" + encodePath(idOrHandle), CreatorProfile.class); + } + + public ProjectPage getCreatorProjects(String userId, int page, int size) { + List params = new ArrayList<>(); + addParam(params, "page", Integer.toString(Math.max(0, page))); + addParam(params, "size", Integer.toString(Math.max(1, size))); + addParam(params, "sort", "relevance"); + return get("/creators/" + encodePath(userId) + "/projects?" + String.join("&", params), ProjectPage.class); + } + + public List getOrganizationMembers(String organizationId) { + return get("/orgs/" + encodePath(organizationId) + "/members", new TypeReference<>() {}); + } + + public List getUserOrganizations(String userId) { + return get("/users/" + encodePath(userId) + "/organizations", new TypeReference<>() {}); + } + + public List getUsersBatch(List userIds) { + List ids = userIds == null + ? List.of() + : userIds.stream() + .filter(id -> id != null && !id.isBlank()) + .distinct() + .toList(); + if (ids.isEmpty()) { + return List.of(); + } + return post("/users/batch", java.util.Map.of("userIds", ids), new TypeReference<>() {}); + } + + public List getComments(String projectId) { + CommentsResponse response = get("/projects/" + encodePath(projectId) + "/comments", CommentsResponse.class); + return response == null ? List.of() : response.comments(); + } + + public void postComment(String projectId, String content) { + post("/projects/" + encodePath(projectId) + "/comments", + java.util.Map.of("content", content == null ? "" : content), Object.class); + } + + public void updateComment(String projectId, String commentId, String content) { + put("/projects/" + encodePath(projectId) + "/comments/" + encodePath(commentId), + java.util.Map.of("content", content == null ? "" : content), Object.class); + } + + public void deleteComment(String projectId, String commentId) { + delete("/projects/" + encodePath(projectId) + "/comments/" + encodePath(commentId), Object.class); + } + + public void replyToComment(String projectId, String commentId, String reply) { + post("/projects/" + encodePath(projectId) + "/comments/" + encodePath(commentId) + "/reply", + java.util.Map.of("reply", reply == null ? "" : reply), Object.class); + } + + public void voteComment(String projectId, String commentId, boolean upvote, boolean reply) { + String target = reply + ? "/projects/" + encodePath(projectId) + "/comments/" + encodePath(commentId) + "/reply/vote" + : "/projects/" + encodePath(projectId) + "/comments/" + encodePath(commentId) + "/vote"; + post(target + "?upvote=" + upvote, java.util.Map.of(), Object.class); + } + + public String submitReport(String targetId, String targetType, String reason, String description) { + ReportResponse response = post("/reports", java.util.Map.of( + "targetId", targetId == null ? "" : targetId, + "targetType", targetType == null ? "" : targetType, + "reason", reason == null ? "" : reason, + "description", description == null ? "" : description + ), ReportResponse.class); + return response == null ? "" : response.id(); + } + + public List getProjectVersionChangelogs(String idOrSlug) { + return get("/projects/" + encodePath(idOrSlug) + "/versions/changelogs", new TypeReference<>() {}); + } + + public List getProjectVersions(String idOrSlug) { + ProjectVersionsResponse response = get("/projects/" + encodePath(idOrSlug) + "/versions", ProjectVersionsResponse.class); + return response == null ? List.of() : response.versions(); + } + + public void toggleFavorite(String projectId) { + post("/projects/" + encodePath(projectId) + "/favorite", java.util.Map.of(), Object.class); + } + + public List getNotifications() { + return get("/notifications", new TypeReference<>() {}); + } + + public void markNotificationRead(String notificationId, boolean read) { + post("/notifications/" + encodePath(notificationId) + "/" + (read ? "read" : "unread"), + java.util.Map.of(), Object.class); + } + + public void markAllNotificationsRead() { + post("/notifications/read-all", java.util.Map.of(), Object.class); + } + + public void deleteNotification(String notificationId) { + delete("/notifications/" + encodePath(notificationId), Object.class); + } + + public void clearNotifications() { + delete("/notifications/clear-all", Object.class); + } + + public void updateNotificationPreferences(CurrentUser.NotificationPreferences preferences) { + put("/user/settings/notifications", + preferences == null ? CurrentUser.NotificationPreferences.defaults() : preferences, + Object.class); + } + + public LauncherSettingsSnapshot getLauncherSettings() { + return get("/user/launcher-settings", LauncherSettingsSnapshot.class); + } + + public LauncherSettingsSnapshot updateLauncherSettings(LauncherSettingsSnapshot snapshot) { + return put("/user/launcher-settings", + snapshot == null ? new LauncherSettingsSnapshot() : snapshot, + LauncherSettingsSnapshot.class); + } + + public LauncherSettingsSnapshot updateLauncherSettingsPreferences(LauncherSettingsSnapshot snapshot) { + LauncherSettingsSnapshot payload = snapshot == null + ? new LauncherSettingsSnapshot() + : snapshot.preferencesOnly(); + return put("/user/launcher-settings/preferences", payload, LauncherSettingsSnapshot.class); + } + + public List getFollowing(String userId) { + return get("/users/" + encodePath(userId) + "/following", new TypeReference<>() {}); + } + + public void followUser(String userId) { + post("/user/follow/" + encodePath(userId), java.util.Map.of(), Object.class); + } + + public void unfollowUser(String userId) { + post("/user/unfollow/" + encodePath(userId), java.util.Map.of(), Object.class); + } + + public void resolveNotificationAction(LauncherNotification notification, boolean accept) { + if (notification == null) { + throw new ModtaleApiException("Notification is missing."); + } + LauncherNotification.ActionType actionType = notification.actionType() + .orElseThrow(() -> new ModtaleApiException("This notification does not have an accept or decline action.")); + java.util.Map metadata = notification.metadata(); + switch (actionType) { + case TRANSFER_REQUEST -> { + String projectId = metadata.get("modId"); + if (projectId == null || projectId.isBlank()) { + throw new ModtaleApiException("Transfer request is missing its project id."); + } + post("/projects/" + encodePath(projectId) + "/transfer/resolve", + java.util.Map.of("accept", accept), Object.class); + } + case ORG_INVITE -> { + String orgId = metadata.get("orgId"); + if (orgId == null || orgId.isBlank()) { + throw new ModtaleApiException("Organization invite is missing its organization id."); + } + post("/orgs/" + encodePath(orgId) + "/invite/" + (accept ? "accept" : "decline"), + java.util.Map.of(), Object.class); + } + case CONTRIBUTOR_INVITE -> { + String projectId = metadata.get("modId"); + if (projectId == null || projectId.isBlank()) { + throw new ModtaleApiException("Contributor invite is missing its project id."); + } + post("/projects/" + encodePath(projectId) + "/invite/" + (accept ? "accept" : "decline"), + java.util.Map.of(), Object.class); + } + } + } + + public List getGameVersions() { + return get("/meta/game-versions", new TypeReference<>() {}); + } + + public GameVersionCatalog getGameVersionCatalog() { + return get("/meta/game-versions/catalog", GameVersionCatalog.class); + } + + public VersionDependenciesView getDependencies(String projectId, String versionNumber, String gameVersion) { + String query = gameVersion == null || gameVersion.isBlank() + ? "" + : "?gameVersion=" + encodeQuery(gameVersion); + return get("/projects/" + encodePath(projectId) + "/versions/" + encodePath(versionNumber) + "/dependencies" + query, + VersionDependenciesView.class); + } + + public WorldModList createWorldModList(CreateWorldModListRequest request) { + return post("/lists", request, WorldModList.class); + } + + public WorldModList getWorldModListForInstall(String listId) { + return get("/lists/" + encodePath(listId) + "/install", WorldModList.class); + } + + public DownloadUrlResponse getDownloadUrl(String projectId, String versionNumber, String gameVersion) { + String query = gameVersion == null || gameVersion.isBlank() + ? "" + : "?gameVersion=" + encodeQuery(gameVersion); + return get("/projects/" + encodePath(projectId) + "/versions/" + encodePath(versionNumber) + "/download-url" + query, + DownloadUrlResponse.class); + } + + public DownloadUrlResponse getBundleDownloadUrl( + String projectId, + String versionNumber, + List dependencyProjectIds, + String gameVersion + ) { + List params = new ArrayList<>(); + if (dependencyProjectIds != null && !dependencyProjectIds.isEmpty()) { + addParam(params, "deps", String.join(",", dependencyProjectIds)); + } + addParam(params, "gameVersion", gameVersion); + String query = params.isEmpty() ? "" : "?" + String.join("&", params); + return get("/projects/" + encodePath(projectId) + "/versions/" + encodePath(versionNumber) + "/download-bundle-url" + query, + DownloadUrlResponse.class); + } + + public DownloadedFile download(String rawUrl) { + return downloadClient.download(rawUrl); + } + + URI resolveDownloadUri(String rawUrl) { + return downloadClient.resolve(rawUrl); + } + + private T get(String pathAndQuery, Class type) { + return transport.get(apiUri(pathAndQuery), type, ApiCachePolicy.ttlFor(pathAndQuery)); + } + + private T get(String pathAndQuery, TypeReference type) { + return transport.get(apiUri(pathAndQuery), type, ApiCachePolicy.ttlFor(pathAndQuery)); + } + + private T post(String pathAndQuery, Object payload, Class type) { + return transport.post(apiUri(pathAndQuery), payload, type); + } + + private T post(String pathAndQuery, Object payload, TypeReference type) { + return transport.post(apiUri(pathAndQuery), payload, type); + } + + private T put(String pathAndQuery, Object payload, Class type) { + return transport.put(apiUri(pathAndQuery), payload, type); + } + + private T delete(String pathAndQuery, Class type) { + return transport.delete(apiUri(pathAndQuery), type); + } + + private void saveStoredSession() { + if (sessionStore != null && cookieManager != null) { + sessionStore.saveFrom(cookieManager.getCookieStore(), apiBaseUri); + storedSessionLoaded = sessionStore.hasSessionFile(); + } + } + + private Optional csrfToken() { + if (cookieManager == null || apiBaseUri == null) { + return Optional.empty(); + } + return cookieManager.getCookieStore().get(apiBaseUri).stream() + .filter(cookie -> "XSRF-TOKEN".equalsIgnoreCase(cookie.getName())) + .filter(cookie -> !cookie.hasExpired()) + .map(HttpCookie::getValue) + .filter(value -> value != null && !value.isBlank()) + .findFirst(); + } + + private static CookieManager defaultCookieManager() { + return new CookieManager(null, CookiePolicy.ACCEPT_ALL); + } + + private URI apiUri(String pathAndQuery) { + return ApiPathBuilder.apiUri(apiBaseUri, pathAndQuery); + } + + private static void addParam(List params, String name, String value) { + ApiPathBuilder.addParam(params, name, value); + } + + private static String encodePath(String value) { + return ApiPathBuilder.encodePath(value); + } + + private static String encodeQuery(String value) { + return ApiPathBuilder.encodeQuery(value); + } + + public record DownloadedFile(Path path, String filename, String contentType) { + } + + private record ProjectVersionsResponse(List versions) { + private ProjectVersionsResponse { + versions = versions == null ? List.of() : List.copyOf(versions); + } + } + + private record CommentsResponse(List comments) { + private CommentsResponse { + comments = comments == null ? List.of() : List.copyOf(comments); + } + } + + private record ReportResponse(String id) { + } + +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiException.java b/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiException.java new file mode 100644 index 00000000..7a381b2c --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiException.java @@ -0,0 +1,24 @@ +package net.modtale.launcher.api; + +public class ModtaleApiException extends RuntimeException { + + private final int statusCode; + + public ModtaleApiException(String message) { + this(message, -1, null); + } + + public ModtaleApiException(String message, Throwable cause) { + this(message, -1, cause); + } + + public ModtaleApiException(String message, int statusCode, Throwable cause) { + super(message, cause); + this.statusCode = statusCode; + } + + public int statusCode() { + return statusCode; + } +} + diff --git a/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiTransport.java b/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiTransport.java new file mode 100644 index 00000000..843e5798 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ModtaleApiTransport.java @@ -0,0 +1,261 @@ +package net.modtale.launcher.api; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; + +final class ModtaleApiTransport { + + private static final String CSRF_HEADER_NAME = "X-XSRF-TOKEN"; + + private final HttpClient httpClient; + private final ObjectMapper mapper; + private final ApiResponseCache responseCache; + private final Supplier> csrfTokenSupplier; + + ModtaleApiTransport(HttpClient httpClient, ApiResponseCache responseCache) { + this(httpClient, responseCache, Optional::empty); + } + + ModtaleApiTransport( + HttpClient httpClient, + ApiResponseCache responseCache, + Supplier> csrfTokenSupplier + ) { + this.httpClient = httpClient; + this.responseCache = responseCache; + this.csrfTokenSupplier = csrfTokenSupplier == null ? Optional::empty : csrfTokenSupplier; + this.mapper = new ObjectMapper() + .registerModule(new JavaTimeModule()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + T get(URI uri, Class type, Duration cacheTtl) { + return sendJson(requestBuilder(uri).GET().build(), type, cacheTtl); + } + + T get(URI uri, TypeReference type, Duration cacheTtl) { + return sendJson(requestBuilder(uri).GET().build(), type, cacheTtl); + } + + T post(URI uri, Object payload, Class type) { + try { + HttpRequest request = writeRequestBuilder(uri) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload), StandardCharsets.UTF_8)) + .build(); + return sendJson(request, type, Duration.ZERO); + } catch (IOException ex) { + throw new ModtaleApiException("Could not write API request body for " + uri, ex); + } + } + + T post(URI uri, Object payload, TypeReference type) { + try { + HttpRequest request = writeRequestBuilder(uri) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload), StandardCharsets.UTF_8)) + .build(); + return sendJson(request, type, Duration.ZERO); + } catch (IOException ex) { + throw new ModtaleApiException("Could not write API request body for " + uri, ex); + } + } + + T put(URI uri, Object payload, Class type) { + try { + HttpRequest request = writeRequestBuilder(uri) + .header("Content-Type", "application/json") + .PUT(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(payload), StandardCharsets.UTF_8)) + .build(); + return sendJson(request, type); + } catch (IOException ex) { + throw new ModtaleApiException("Could not write API request body for " + uri, ex); + } + } + + T delete(URI uri, Class type) { + return sendJson(writeRequestBuilder(uri).DELETE().build(), type); + } + + void clearResponseCache() { + responseCache.clear(); + } + + private T sendJson(HttpRequest request, Class type) { + return sendJson(request, type, Duration.ZERO); + } + + private T sendJson(HttpRequest request, Class type, Duration cacheTtl) { + if (ApiCachePolicy.isEnabled(cacheTtl)) { + Optional cached = responseCache.getFresh(request.uri(), cacheTtl); + if (cached.isPresent()) { + try { + return mapper.readValue(cached.get(), type); + } catch (IOException ex) { + responseCache.invalidate(request.uri()); + } + } + } + + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + ensureSuccess(response.statusCode(), request.uri().toString(), response.body()); + if (ApiCachePolicy.isEnabled(cacheTtl)) { + responseCache.put(request.uri(), response.body()); + } + return readResponseBody(response.body(), type); + } catch (IOException ex) { + Optional stale = readStaleFallback(request, type, cacheTtl); + if (stale.isPresent()) { + return stale.get(); + } + throw new ModtaleApiException("Could not read API response from " + request.uri(), ex); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + Optional stale = readStaleFallback(request, type, cacheTtl); + if (stale.isPresent()) { + return stale.get(); + } + throw new ModtaleApiException("API request was interrupted.", ex); + } + } + + private T sendJson(HttpRequest request, TypeReference type, Duration cacheTtl) { + if (ApiCachePolicy.isEnabled(cacheTtl)) { + Optional cached = responseCache.getFresh(request.uri(), cacheTtl); + if (cached.isPresent()) { + try { + return mapper.readValue(cached.get(), type); + } catch (IOException ex) { + responseCache.invalidate(request.uri()); + } + } + } + + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + ensureSuccess(response.statusCode(), request.uri().toString(), response.body()); + if (ApiCachePolicy.isEnabled(cacheTtl)) { + responseCache.put(request.uri(), response.body()); + } + return mapper.readValue(response.body(), type); + } catch (IOException ex) { + Optional stale = readStaleFallback(request, type, cacheTtl); + if (stale.isPresent()) { + return stale.get(); + } + throw new ModtaleApiException("Could not read API response from " + request.uri(), ex); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + Optional stale = readStaleFallback(request, type, cacheTtl); + if (stale.isPresent()) { + return stale.get(); + } + throw new ModtaleApiException("API request was interrupted.", ex); + } + } + + private T readResponseBody(String body, Class type) throws IOException { + if (body == null || body.isBlank()) { + if (type == Void.class || type == Object.class) { + return null; + } + } + return mapper.readValue(body, type); + } + + private Optional readStaleFallback(HttpRequest request, Class type, Duration cacheTtl) { + if (!ApiCachePolicy.isEnabled(cacheTtl)) { + return Optional.empty(); + } + Optional cached = responseCache.getStaleFallback(request.uri()); + if (cached.isEmpty()) { + return Optional.empty(); + } + try { + return Optional.of(mapper.readValue(cached.get(), type)); + } catch (IOException ex) { + responseCache.invalidate(request.uri()); + return Optional.empty(); + } + } + + private Optional readStaleFallback(HttpRequest request, TypeReference type, Duration cacheTtl) { + if (!ApiCachePolicy.isEnabled(cacheTtl)) { + return Optional.empty(); + } + Optional cached = responseCache.getStaleFallback(request.uri()); + if (cached.isEmpty()) { + return Optional.empty(); + } + try { + return Optional.of(mapper.readValue(cached.get(), type)); + } catch (IOException ex) { + responseCache.invalidate(request.uri()); + return Optional.empty(); + } + } + + static HttpRequest.Builder requestBuilder(URI uri) { + return HttpRequest.newBuilder(uri) + .timeout(Duration.ofSeconds(60)) + .header("Accept", "application/json") + .header("User-Agent", "ModtaleLauncher/0.1"); + } + + private HttpRequest.Builder writeRequestBuilder(URI uri) { + HttpRequest.Builder builder = requestBuilder(uri); + csrfTokenSupplier.get() + .filter(token -> !token.isBlank()) + .ifPresent(token -> builder.header(CSRF_HEADER_NAME, token)); + return builder; + } + + static void ensureSuccess(int status, String target) { + if (status < 200 || status >= 300) { + throw new ModtaleApiException("Modtale API returned HTTP " + status + " for " + target, status, null); + } + } + + private void ensureSuccess(int status, String target, String body) { + if (status >= 200 && status < 300) { + return; + } + String serverMessage = serverErrorMessage(body); + if (serverMessage == null || serverMessage.isBlank()) { + throw new ModtaleApiException("Modtale API returned HTTP " + status + " for " + target, status, null); + } + throw new ModtaleApiException(serverMessage, status, null); + } + + private String serverErrorMessage(String body) { + if (body == null || body.isBlank()) { + return null; + } + try { + JsonNode root = mapper.readTree(body); + for (String field : List.of("message", "error", "detail", "title")) { + JsonNode value = root.get(field); + if (value != null && value.isTextual() && !value.asText().isBlank()) { + return value.asText(); + } + } + } catch (IOException ignored) { + return null; + } + return null; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/ModtaleDownloadClient.java b/launcher/src/main/java/net/modtale/launcher/api/ModtaleDownloadClient.java new file mode 100644 index 00000000..0a9299a9 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ModtaleDownloadClient.java @@ -0,0 +1,103 @@ +package net.modtale.launcher.api; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.function.Supplier; + +final class ModtaleDownloadClient { + + private final HttpClient httpClient; + private final Supplier apiBaseUri; + + ModtaleDownloadClient(HttpClient httpClient, Supplier apiBaseUri) { + this.httpClient = httpClient; + this.apiBaseUri = apiBaseUri; + } + + ModtaleApiClient.DownloadedFile download(String rawUrl) { + URI uri = resolve(rawUrl); + HttpRequest request = ModtaleApiTransport.requestBuilder(uri) + .GET() + .header("Accept", "application/octet-stream, application/zip, */*") + .build(); + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); + ModtaleApiTransport.ensureSuccess(response.statusCode(), uri.toString()); + String filename = filenameFromDisposition(response.headers().firstValue("Content-Disposition")) + .or(() -> filenameFromUri(uri)) + .orElse("download.bin"); + Path tempFile = Files.createTempFile("modtale-", "-" + SafeDownloadName.sanitize(filename)); + try (InputStream body = response.body()) { + Files.copy(body, tempFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } + return new ModtaleApiClient.DownloadedFile( + tempFile, + filename, + response.headers().firstValue("Content-Type").orElse("") + ); + } catch (IOException ex) { + throw new ModtaleApiException("Could not download " + uri, ex); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new ModtaleApiException("Download was interrupted.", ex); + } + } + + URI resolve(String rawUrl) { + if (rawUrl == null || rawUrl.isBlank()) { + throw new ModtaleApiException("The API returned an empty download URL."); + } + if (rawUrl.startsWith("http://") || rawUrl.startsWith("https://")) { + return URI.create(rawUrl); + } + + String base = apiBaseUri.get().toString().replaceAll("/+$", ""); + String path = rawUrl.startsWith("/") ? rawUrl : "/" + rawUrl; + return URI.create(base + path); + } + + private static Optional filenameFromDisposition(Optional header) { + return header.flatMap(value -> { + for (String part : value.split(";")) { + String trimmed = part.trim(); + if (trimmed.toLowerCase().startsWith("filename=")) { + String filename = trimmed.substring("filename=".length()).trim(); + if (filename.startsWith("\"") && filename.endsWith("\"") && filename.length() >= 2) { + filename = filename.substring(1, filename.length() - 1); + } + if (!filename.isBlank()) { + return Optional.of(filename); + } + } + } + return Optional.empty(); + }); + } + + private static Optional filenameFromUri(URI uri) { + String path = uri.getPath(); + if (path == null || path.isBlank()) { + return Optional.empty(); + } + int slash = path.lastIndexOf('/'); + String filename = slash >= 0 ? path.substring(slash + 1) : path; + return filename.isBlank() ? Optional.empty() : Optional.of(filename); + } + + private static final class SafeDownloadName { + private SafeDownloadName() { + } + + private static String sanitize(String value) { + String sanitized = value == null ? "download.bin" : value.replaceAll("[^A-Za-z0-9._-]+", "-"); + return sanitized.isBlank() ? "download.bin" : sanitized; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/api/ProjectSearchQuery.java b/launcher/src/main/java/net/modtale/launcher/api/ProjectSearchQuery.java new file mode 100644 index 00000000..c796b0d9 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/api/ProjectSearchQuery.java @@ -0,0 +1,28 @@ +package net.modtale.launcher.api; + +public record ProjectSearchQuery( + String search, + String classification, + String gameVersion, + String sort, + int page, + int size, + String tags, + Integer minDownloads, + Integer minFavorites, + String category, + String dateRange, + Boolean openSource +) { + private static final String DEFAULT_SORT = "relevance"; + + public ProjectSearchQuery { + sort = sort == null || sort.isBlank() ? DEFAULT_SORT : sort; + page = Math.max(0, page); + size = Math.max(1, Math.min(100, size)); + minDownloads = minDownloads == null || minDownloads <= 0 ? null : minDownloads; + minFavorites = minFavorites == null || minFavorites <= 0 ? null : minFavorites; + dateRange = dateRange == null || dateRange.isBlank() ? null : dateRange; + openSource = Boolean.TRUE.equals(openSource) ? Boolean.TRUE : null; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/cache/LauncherCachePaths.java b/launcher/src/main/java/net/modtale/launcher/cache/LauncherCachePaths.java new file mode 100644 index 00000000..43978cda --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/cache/LauncherCachePaths.java @@ -0,0 +1,17 @@ +package net.modtale.launcher.cache; + +import java.nio.file.Path; + +public final class LauncherCachePaths { + + private LauncherCachePaths() { + } + + public static Path rootDirectory() { + return Path.of(System.getProperty("user.home", "."), ".modtale", "launcher", "cache"); + } + + public static Path cacheDirectory(String name) { + return rootDirectory().resolve(name); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/cache/LauncherCacheService.java b/launcher/src/main/java/net/modtale/launcher/cache/LauncherCacheService.java new file mode 100644 index 00000000..d709ade0 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/cache/LauncherCacheService.java @@ -0,0 +1,44 @@ +package net.modtale.launcher.cache; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Stream; + +public final class LauncherCacheService { + + private final Path cacheRoot; + + public LauncherCacheService() { + this(LauncherCachePaths.rootDirectory()); + } + + LauncherCacheService(Path cacheRoot) { + this.cacheRoot = cacheRoot; + } + + public ClearResult clear() throws IOException { + if (!Files.exists(cacheRoot)) { + return new ClearResult(0); + } + + try (Stream stream = Files.walk(cacheRoot)) { + List paths = stream + .filter(path -> !cacheRoot.equals(path)) + .sorted(Comparator.reverseOrder()) + .toList(); + int deletedEntries = 0; + for (Path path : paths) { + if (Files.deleteIfExists(path)) { + deletedEntries++; + } + } + return new ClearResult(deletedEntries); + } + } + + public record ClearResult(int deletedEntries) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/discord/DiscordRichPresenceService.java b/launcher/src/main/java/net/modtale/launcher/discord/DiscordRichPresenceService.java new file mode 100644 index 00000000..9e92c47a --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/discord/DiscordRichPresenceService.java @@ -0,0 +1,329 @@ +package net.modtale.launcher.discord; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.SocketChannel; +import java.nio.file.Path; +import java.time.Instant; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicBoolean; +import net.modtale.launcher.settings.LauncherConfig; + +public final class DiscordRichPresenceService { + + private static final int DISCORD_IPC_PIPE_COUNT = 10; + private static final int OPCODE_HANDSHAKE = 0; + private static final int OPCODE_FRAME = 1; + private static final String OPEN_MODTALE_URL = "https://modtale.net"; + private static final String MODTALE_FAVICON_URL = "https://modtale.net/assets/favicon.svg"; + + private final ObjectMapper mapper = new ObjectMapper(); + private final AtomicBoolean closed = new AtomicBoolean(); + private final Object connectionLock = new Object(); + private final String clientId; + private final ExecutorService executor; + private final long launcherStartedAt; + + private DiscordIpcConnection connection; + + public DiscordRichPresenceService(String clientId) { + this.clientId = LauncherConfig.normalizeDiscordClientId(clientId).orElse(null); + this.launcherStartedAt = Instant.now().getEpochSecond(); + this.executor = Executors.newSingleThreadExecutor(daemonThreadFactory()); + } + + public static DiscordRichPresenceService fromConfig() { + return new DiscordRichPresenceService(LauncherConfig.discordClientId().orElse(null)); + } + + public boolean isEnabled() { + return clientId != null; + } + + public void start() { + showLauncher(); + } + + public void showLauncher() { + if (!isEnabled()) { + return; + } + submit(() -> setActivity(launcherActivity(mapper, launcherStartedAt))); + } + + public void showPlayingHytale(String buildLabel, long startedAtMillis) { + if (!isEnabled()) { + return; + } + long startedAt = Math.max(0, startedAtMillis / 1000); + submit(() -> setActivity(hytaleActivity(mapper, buildLabel, startedAt))); + } + + public void shutdown() { + closed.set(true); + executor.shutdownNow(); + synchronized (connectionLock) { + closeConnection(); + } + } + + private void submit(Runnable task) { + if (closed.get()) { + return; + } + try { + executor.execute(() -> { + if (!closed.get()) { + task.run(); + } + }); + } catch (RejectedExecutionException ignored) { + // The launcher is shutting down; Discord presence is best effort. + } + } + + private void setActivity(ObjectNode activity) { + ObjectNode command = setActivityCommand(mapper, ProcessHandle.current().pid(), activity, UUID.randomUUID().toString()); + sendCommand(command); + } + + private void sendCommand(ObjectNode command) { + byte[] payload; + try { + payload = mapper.writeValueAsBytes(command); + } catch (IOException ignored) { + return; + } + + synchronized (connectionLock) { + for (int attempt = 0; attempt < 2 && !closed.get(); attempt++) { + try { + DiscordIpcConnection activeConnection = ensureConnection(); + activeConnection.write(frame(OPCODE_FRAME, payload)); + return; + } catch (IOException | UnsupportedOperationException ignored) { + closeConnection(); + } + } + } + } + + private DiscordIpcConnection ensureConnection() throws IOException { + if (connection != null) { + return connection; + } + + DiscordIpcConnection opened = DiscordIpcConnection.open(); + ObjectNode handshake = mapper.createObjectNode(); + handshake.put("v", 1); + handshake.put("client_id", clientId); + opened.write(frame(OPCODE_HANDSHAKE, mapper.writeValueAsBytes(handshake))); + connection = opened; + return opened; + } + + private void closeConnection() { + if (connection == null) { + return; + } + try { + connection.close(); + } catch (IOException ignored) { + // Discord may have closed the IPC pipe first. + } finally { + connection = null; + } + } + + static ObjectNode launcherActivity(ObjectMapper mapper, long startedAt) { + ObjectNode activity = baseActivity(mapper, startedAt); + activity.put("details", "Browsing Modtale"); + activity.put("state", "Managing Hytale mods"); + return activity; + } + + static ObjectNode hytaleActivity(ObjectMapper mapper, String buildLabel, long startedAt) { + ObjectNode activity = baseActivity(mapper, startedAt); + activity.put("details", "Playing Hytale"); + String label = buildLabel == null || buildLabel.isBlank() || "Unset".equals(buildLabel) + ? "Launched from Modtale" + : buildLabel.trim(); + activity.put("state", label); + return activity; + } + + static ObjectNode setActivityCommand(ObjectMapper mapper, long pid, ObjectNode activity, String nonce) { + ObjectNode command = mapper.createObjectNode(); + command.put("cmd", "SET_ACTIVITY"); + ObjectNode args = command.putObject("args"); + args.put("pid", pid); + if (activity == null) { + args.putNull("activity"); + } else { + args.set("activity", activity); + } + command.put("nonce", nonce); + return command; + } + + static byte[] frame(int opcode, byte[] payload) { + ByteBuffer buffer = ByteBuffer.allocate(8 + payload.length).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(opcode); + buffer.putInt(payload.length); + buffer.put(payload); + return buffer.array(); + } + + private static ObjectNode baseActivity(ObjectMapper mapper, long startedAt) { + ObjectNode activity = mapper.createObjectNode(); + ObjectNode timestamps = activity.putObject("timestamps"); + timestamps.put("start", startedAt); + ObjectNode assets = activity.putObject("assets"); + assets.put("large_image", MODTALE_FAVICON_URL); + assets.put("large_text", "Modtale"); + activity.putArray("buttons") + .addObject() + .put("label", "Open Modtale") + .put("url", OPEN_MODTALE_URL); + return activity; + } + + private static ThreadFactory daemonThreadFactory() { + return runnable -> { + Thread thread = new Thread(runnable, "modtale-discord-rpc"); + thread.setDaemon(true); + return thread; + }; + } + + private interface DiscordIpcConnection extends AutoCloseable { + + void write(byte[] bytes) throws IOException; + + @Override + void close() throws IOException; + + static DiscordIpcConnection open() throws IOException { + IOException lastError = null; + for (String path : ipcPaths()) { + try { + return isWindows() ? WindowsPipeConnection.open(path) : UnixSocketConnection.open(path); + } catch (IOException ex) { + lastError = ex; + } + } + throw lastError == null ? new IOException("Discord IPC pipe was not found.") : lastError; + } + + private static List ipcPaths() { + Set paths = new LinkedHashSet<>(); + for (int index = 0; index < DISCORD_IPC_PIPE_COUNT; index++) { + if (isWindows()) { + paths.add("\\\\.\\pipe\\discord-ipc-" + index); + } else { + for (Path root : unixIpcRoots()) { + paths.add(root.resolve("discord-ipc-" + index).toString()); + } + } + } + return List.copyOf(paths); + } + + private static List unixIpcRoots() { + Set roots = new LinkedHashSet<>(); + addRoot(roots, System.getenv("XDG_RUNTIME_DIR")); + addRoot(roots, System.getProperty("java.io.tmpdir")); + addRoot(roots, System.getenv("TMPDIR")); + addRoot(roots, System.getenv("TEMP")); + addRoot(roots, System.getenv("TMP")); + String xdgRuntime = System.getenv("XDG_RUNTIME_DIR"); + if (xdgRuntime != null && !xdgRuntime.isBlank()) { + Path runtimeRoot = Path.of(xdgRuntime); + roots.add(runtimeRoot.resolve(Path.of("app", "com.discordapp.Discord"))); + roots.add(runtimeRoot.resolve("snap.discord")); + } + roots.add(Path.of("/tmp")); + return List.copyOf(roots); + } + + private static void addRoot(Set roots, String rawPath) { + if (rawPath != null && !rawPath.isBlank()) { + roots.add(Path.of(rawPath)); + } + } + + private static boolean isWindows() { + return System.getProperty("os.name", "").toLowerCase(Locale.ROOT).contains("win"); + } + } + + private static final class UnixSocketConnection implements DiscordIpcConnection { + + private final SocketChannel channel; + + private UnixSocketConnection(SocketChannel channel) { + this.channel = channel; + } + + static UnixSocketConnection open(String path) throws IOException { + SocketChannel channel = SocketChannel.open(StandardProtocolFamily.UNIX); + try { + channel.connect(UnixDomainSocketAddress.of(Path.of(path))); + return new UnixSocketConnection(channel); + } catch (IOException | UnsupportedOperationException ex) { + channel.close(); + throw ex; + } + } + + @Override + public void write(byte[] bytes) throws IOException { + ByteBuffer buffer = ByteBuffer.wrap(bytes); + while (buffer.hasRemaining()) { + channel.write(buffer); + } + } + + @Override + public void close() throws IOException { + channel.close(); + } + } + + private static final class WindowsPipeConnection implements DiscordIpcConnection { + + private final RandomAccessFile pipe; + + private WindowsPipeConnection(RandomAccessFile pipe) { + this.pipe = pipe; + } + + static WindowsPipeConnection open(String path) throws IOException { + return new WindowsPipeConnection(new RandomAccessFile(path, "rw")); + } + + @Override + public void write(byte[] bytes) throws IOException { + pipe.write(bytes); + } + + @Override + public void close() throws IOException { + pipe.close(); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiClient.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiClient.java new file mode 100644 index 00000000..cb2bb9ff --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiClient.java @@ -0,0 +1,1076 @@ +package net.modtale.launcher.hytale; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public class HytaleApiClient { + + static final String AUTH_URL = "https://oauth.accounts.hytale.com/oauth2/auth"; + static final String TOKEN_URL = "https://oauth.accounts.hytale.com/oauth2/token"; + static final String LAUNCHER_DATA_URL = "https://account-data.hytale.com/my-account/get-launcher-data"; + static final String PUBLIC_PROFILE_BY_UUID_URL = "https://account-data.hytale.com/profile/uuid"; + static final String SOCIAL_FRIENDS_URL = "https://social.hytale.com/friends"; + static final String SESSION_URL = "https://sessions.hytale.com/game-session/new"; + static final String PATCHES_BASE_URL = "https://account-data.hytale.com/patches"; + static final String LAUNCHER_INFO_URL = "https://launcher.hytale.com/version/release/launcher.json"; + static final String BLOG_URL = "https://hytale.com/news"; + static final String BLOG_RSS_URL = "https://hytale.com/rss.xml"; + static final String CLIENT_ID = "hytale-launcher"; + static final String REDIRECT_URI = "https://accounts.hytale.com/consent/client"; + static final String SCOPES = "openid offline auth:launcher"; + + private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(60); + private static final Duration BLOG_CACHE_TTL = Duration.ofMinutes(15); + private static final String FALLBACK_LAUNCHER_VERSION = "unknown"; + private static final String RELEASE_PATCHLINE = "release"; + private static final String PRE_RELEASE_PATCHLINE = "pre-release"; + private static final Pattern VERSIONED_PATCHLINE_PATTERN = Pattern.compile("v?\\d+\\.\\d+"); + private static final Pattern BLOG_ARTICLE_PATTERN = Pattern.compile("", Pattern.CASE_INSENSITIVE); + private static final Pattern BLOG_LINK_PATTERN = Pattern.compile("]*href=\"([^\"]+)\"", Pattern.CASE_INSENSITIVE); + private static final Pattern BLOG_IMAGE_PATTERN = Pattern.compile("]*src=\"([^\"]+)\"", Pattern.CASE_INSENSITIVE); + private static final Pattern BLOG_TITLE_PATTERN = Pattern.compile("]*>([\\s\\S]*?)", Pattern.CASE_INSENSITIVE); + private static final Pattern BLOG_DATE_PATTERN = Pattern.compile("\\b((?:January|February|March|April|May|June|July|August|September|October|November|December)\\s+\\d{1,2},\\s+\\d{4})\\b"); + private static final DateTimeFormatter BLOG_PAGE_DATE = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .appendPattern("MMMM d, yyyy") + .toFormatter(Locale.ENGLISH); + + private final HttpClient httpClient; + private final ObjectMapper mapper; + private volatile String launcherVersion; + private volatile long launcherVersionFetchedAt; + private volatile List blogPostCache = List.of(); + private volatile long blogPostFetchedAt; + + public HytaleApiClient() { + this(HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(15)) + .followRedirects(HttpClient.Redirect.NORMAL) + .build()); + } + + HytaleApiClient(HttpClient httpClient) { + this.httpClient = httpClient; + this.mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + public TokenResponse exchangeCode(String code, String codeVerifier) { + return postForm(TOKEN_URL, Map.of( + "grant_type", "authorization_code", + "code", code == null ? "" : code, + "redirect_uri", REDIRECT_URI, + "client_id", CLIENT_ID, + "code_verifier", codeVerifier == null ? "" : codeVerifier + ), TokenResponse.class); + } + + public TokenResponse refreshToken(String refreshToken) { + return postForm(TOKEN_URL, Map.of( + "grant_type", "refresh_token", + "refresh_token", refreshToken == null ? "" : refreshToken, + "client_id", CLIENT_ID + ), TokenResponse.class); + } + + public HytaleProfile fetchProfile(String accessToken) { + return fetchProfiles(accessToken).getFirst(); + } + + public List fetchProfiles(String accessToken) { + HttpRequest request = officialRequestBuilder(launcherDataUrl(), "release") + .GET() + .header("Authorization", "Bearer " + accessToken) + .build(); + ProfilesResponse response = sendJson(request, ProfilesResponse.class); + if (response.profiles == null || response.profiles.isEmpty()) { + throw new HytaleApiException("No Hytale game profile was returned for this account."); + } + + String owner = response.owner == null ? "" : response.owner; + return response.profiles.stream() + .map(profile -> new HytaleProfile(profile.username, profile.uuid, owner, profile.playtimeSeconds)) + .toList(); + } + + public List fetchFriends(String sessionToken) { + HttpRequest request = officialRequestBuilder(URI.create(SOCIAL_FRIENDS_URL), "release") + .GET() + .header("Authorization", "Bearer " + sessionToken) + .build(); + return parseFriends(sendJson(request, JsonNode.class)); + } + + public Map fetchPublicProfileUsernames(String sessionToken, List uuids) { + if (sessionToken == null || sessionToken.isBlank() || uuids == null || uuids.isEmpty()) { + return Map.of(); + } + Map usernames = new LinkedHashMap<>(); + Set seen = new HashSet<>(); + for (String uuid : uuids) { + String normalizedUuid = uuid == null ? "" : uuid.trim(); + String key = normalizedUuid.toLowerCase(Locale.ROOT); + if (normalizedUuid.isBlank() || !seen.add(key)) { + continue; + } + try { + HttpRequest request = officialRequestBuilder( + URI.create(PUBLIC_PROFILE_BY_UUID_URL + "/" + encodePathSegment(normalizedUuid)), + "release") + .GET() + .header("Authorization", "Bearer " + sessionToken) + .build(); + parsePublicProfileUsername(sendJson(request, JsonNode.class)) + .ifPresent(username -> usernames.put(key, username)); + } catch (HytaleApiException ex) { + if (ex.isAuthFailure()) { + throw ex; + } + } + } + return usernames; + } + + public HytaleGameSession createGameSession(String accessToken, String uuid) { + try { + HttpRequest request = officialRequestBuilder(URI.create(SESSION_URL), "release") + .header("Authorization", "Bearer " + accessToken) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString( + mapper.writeValueAsString(Map.of("uuid", uuid == null ? "" : uuid)), + StandardCharsets.UTF_8)) + .build(); + GameSessionResponse response = sendJson(request, GameSessionResponse.class); + return new HytaleGameSession( + response.sessionToken == null ? "" : response.sessionToken, + response.identityToken == null ? "" : response.identityToken + ); + } catch (IOException ex) { + throw new HytaleApiException("Could not write Hytale game-session request.", ex); + } + } + + public List getAvailableVersions(String accessToken, String branch) { + String normalizedBranch = normalizeBranch(branch); + String os = HytalePlatform.os(); + String arch = HytalePlatform.arch(); + Map versionsByBuild = new LinkedHashMap<>(); + + OfficialPatchesResponse latest = fetchPatches(accessToken, os, arch, normalizedBranch, 0); + if (latest.steps != null) { + latest.steps.stream() + .max(Comparator.comparingInt(step -> step.to)) + .ifPresent(step -> versionsByBuild.put(step.to, toVersion(normalizedBranch, step, true))); + } + + try { + OfficialPatchesResponse chain = fetchPatches(accessToken, os, arch, normalizedBranch, 1); + if (chain.steps != null) { + chain.steps.stream() + .sorted(Comparator.comparingInt((OfficialPatchStep step) -> step.to).reversed()) + .forEach(step -> versionsByBuild.putIfAbsent(step.to, toVersion(normalizedBranch, step, false))); + } + } catch (HytaleApiException ex) { + if (ex.isAuthFailure()) { + throw ex; + } + } + + return versionsByBuild.values().stream() + .sorted(Comparator.comparingInt(HytaleVersion::build).reversed()) + .toList(); + } + + public List getAvailablePatchlines(String accessToken, List candidatePatchlines) { + String os = HytalePlatform.os(); + String arch = HytalePlatform.arch(); + LinkedHashSet patchlines = new LinkedHashSet<>(); + addAvailablePatchline(accessToken, os, arch, RELEASE_PATCHLINE, patchlines, true); + + LinkedHashSet candidates = new LinkedHashSet<>(); + candidates.add(PRE_RELEASE_PATCHLINE); + launcherDataPatchlines(accessToken).forEach(candidates::add); + if (candidatePatchlines != null) { + candidatePatchlines.stream() + .map(HytaleApiClient::normalizePatchlineId) + .flatMap(Optional::stream) + .forEach(candidates::add); + } + + for (String candidate : candidates) { + if (!RELEASE_PATCHLINE.equals(candidate)) { + addAvailablePatchline(accessToken, os, arch, candidate, patchlines, false); + } + } + return List.copyOf(patchlines); + } + + public List getBlogPosts(int count) { + int safeCount = Math.max(1, count); + return getAllBlogPosts().stream().limit(safeCount).toList(); + } + + public List getAllBlogPosts() { + long now = System.currentTimeMillis(); + List cached = blogPostCache; + if (!cached.isEmpty() && now - blogPostFetchedAt < BLOG_CACHE_TTL.toMillis()) { + return cached; + } + + HytaleApiException rssError = null; + List posts; + try { + posts = getBlogPostsFromRss(Integer.MAX_VALUE); + } catch (HytaleApiException ex) { + rssError = ex; + posts = List.of(); + } + if (!posts.isEmpty()) { + posts = enrichRssPostsWithNewsImages(posts); + } + if (posts.isEmpty()) { + try { + posts = getBlogPostsFromHtml(Integer.MAX_VALUE); + } catch (HytaleApiException ex) { + if (rssError != null) { + throw rssError; + } + throw ex; + } + } + blogPostCache = posts; + blogPostFetchedAt = now; + return posts; + } + + private List getBlogPostsFromHtml(int count) { + HttpRequest request = HttpRequest.newBuilder(URI.create(BLOG_URL)) + .timeout(REQUEST_TIMEOUT) + .header("Accept", "text/html, application/xhtml+xml") + .GET() + .build(); + return parseBlogPosts(sendString(request), count); + } + + private List getBlogPostsFromRss(int count) { + HttpRequest request = HttpRequest.newBuilder(URI.create(BLOG_RSS_URL)) + .timeout(REQUEST_TIMEOUT) + .header("Accept", "application/rss+xml, application/xml, text/xml") + .GET() + .build(); + return parseBlogPosts(sendString(request), count); + } + + private List enrichRssPostsWithNewsImages(List rssPosts) { + List htmlPosts; + try { + htmlPosts = getBlogPostsFromHtml(Integer.MAX_VALUE); + } catch (HytaleApiException ex) { + return rssPosts; + } + if (htmlPosts.isEmpty()) { + return rssPosts; + } + + Map imageByUrl = new LinkedHashMap<>(); + Map imageByTitle = new LinkedHashMap<>(); + for (HytaleBlogPost post : htmlPosts) { + if (post.imageUrl().isBlank()) { + continue; + } + imageByUrl.put(normalizedBlogUrl(post.url()), post.imageUrl()); + imageByTitle.put(normalizedBlogTitle(post.title()), post.imageUrl()); + } + + return rssPosts.stream() + .map(post -> { + if (!post.imageUrl().isBlank()) { + return post; + } + String imageUrl = imageByUrl.getOrDefault( + normalizedBlogUrl(post.url()), + imageByTitle.getOrDefault(normalizedBlogTitle(post.title()), "") + ); + return imageUrl.isBlank() + ? post + : new HytaleBlogPost(post.title(), post.url(), imageUrl, post.publishedAt()); + }) + .toList(); + } + + private OfficialPatchesResponse fetchPatches(String accessToken, String os, String arch, String branch, int fromBuild) { + URI uri = URI.create(PATCHES_BASE_URL + "/" + os + "/" + arch + "/" + normalizeBranch(branch) + "/" + fromBuild); + HttpRequest request = officialRequestBuilder(uri, branch) + .GET() + .header("Authorization", "Bearer " + accessToken) + .build(); + return sendJson(request, OfficialPatchesResponse.class); + } + + private void addAvailablePatchline( + String accessToken, + String os, + String arch, + String patchline, + LinkedHashSet patchlines, + boolean required + ) { + try { + OfficialPatchesResponse response = fetchPatches(accessToken, os, arch, patchline, 0); + if (response.steps != null) { + patchlines.add(patchline); + } + } catch (HytaleApiException ex) { + if (required || ex.statusCode() == 429) { + throw ex; + } + } + } + + private List launcherDataPatchlines(String accessToken) { + try { + HttpRequest request = officialRequestBuilder(launcherDataUrl(), RELEASE_PATCHLINE) + .GET() + .header("Authorization", "Bearer " + accessToken) + .build(); + return parsePatchlines(sendJson(request, JsonNode.class)); + } catch (HytaleApiException ex) { + if (ex.isAuthFailure() || ex.statusCode() == 429) { + throw ex; + } + return List.of(); + } + } + + private HytaleVersion toVersion(String branch, OfficialPatchStep step, boolean latest) { + return new HytaleVersion( + branch, + step.to, + step.from, + latest, + emptyIfNull(step.pwr), + emptyIfNull(step.pwrHead), + emptyIfNull(step.sig) + ); + } + + private URI launcherDataUrl() { + return URI.create(LAUNCHER_DATA_URL + "?client_id=" + CLIENT_ID); + } + + private HttpRequest.Builder officialRequestBuilder(URI uri, String branch) { + String version = launcherVersion(); + return HttpRequest.newBuilder(uri) + .timeout(REQUEST_TIMEOUT) + .header("Accept", "application/json") + .header("User-Agent", "hytale-launcher/" + version) + .header("x-hytale-launcher-version", version) + .header("x-hytale-launcher-branch", normalizeHeaderBranch(branch)); + } + + private String launcherVersion() { + long now = System.currentTimeMillis(); + if (launcherVersion != null && now - launcherVersionFetchedAt < Duration.ofHours(6).toMillis()) { + return launcherVersion; + } + + try { + HttpRequest request = HttpRequest.newBuilder(URI.create(LAUNCHER_INFO_URL)) + .timeout(Duration.ofSeconds(10)) + .header("Accept", "application/json") + .GET() + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() >= 200 && response.statusCode() < 300) { + launcherVersion = extractLauncherVersion(response.body()).orElse(FALLBACK_LAUNCHER_VERSION); + } else if (launcherVersion == null) { + launcherVersion = FALLBACK_LAUNCHER_VERSION; + } + } catch (IOException ex) { + if (launcherVersion == null) { + launcherVersion = FALLBACK_LAUNCHER_VERSION; + } + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + if (launcherVersion == null) { + launcherVersion = FALLBACK_LAUNCHER_VERSION; + } + } + + launcherVersionFetchedAt = now; + return launcherVersion; + } + + private Optional extractLauncherVersion(String json) throws IOException { + JsonNode root = mapper.readTree(json); + for (String key : List.of("version", "launcher_version", "build", "id")) { + JsonNode node = root.get(key); + if (node != null && !node.asText("").isBlank()) { + return Optional.of(node.asText()); + } + } + return Optional.empty(); + } + + private T postForm(String url, Map values, Class type) { + HttpRequest request = HttpRequest.newBuilder(URI.create(url)) + .timeout(REQUEST_TIMEOUT) + .header("Accept", "application/json") + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString(formEncode(values), StandardCharsets.UTF_8)) + .build(); + return sendJson(request, type); + } + + private T sendJson(HttpRequest request, Class type) { + String body = sendString(request); + try { + return mapper.readValue(body, type); + } catch (IOException ex) { + throw new HytaleApiException("Could not read Hytale API response from " + request.uri(), ex); + } + } + + private String sendString(HttpRequest request) { + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() < 200 || response.statusCode() >= 300) { + throw new HytaleApiException("Hytale API returned HTTP " + response.statusCode() + + " for " + request.uri() + responseSnippet(response.body()), + response.statusCode(), + null, + retryAfterMillis(response.headers(), Instant.now())); + } + return response.body(); + } catch (IOException ex) { + throw new HytaleApiException("Could not read Hytale API response from " + request.uri(), ex); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new HytaleApiException("Hytale API request was interrupted.", ex); + } + } + + private static String formEncode(Map values) { + List encoded = new ArrayList<>(); + values.forEach((key, value) -> encoded.add(encode(key) + "=" + encode(value))); + return String.join("&", encoded); + } + + private static String encode(String value) { + return URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8); + } + + private static String encodePathSegment(String value) { + return encode(value).replace("+", "%20"); + } + + public static String normalizeBranch(String branch) { + return normalizePatchlineId(branch).orElse(RELEASE_PATCHLINE); + } + + public static Optional normalizePatchlineId(String branch) { + if (branch == null || branch.isBlank()) { + return Optional.empty(); + } + String normalized = branch.trim().toLowerCase(Locale.ROOT); + return switch (normalized) { + case "release", "latest", "latest-release" -> Optional.of(RELEASE_PATCHLINE); + case "pre-release", "pre release", "prerelease", "pre_release" -> Optional.of(PRE_RELEASE_PATCHLINE); + default -> VERSIONED_PATCHLINE_PATTERN.matcher(normalized).matches() + ? Optional.of(normalized.startsWith("v") ? normalized : "v" + normalized) + : Optional.empty(); + }; + } + + private static String normalizeHeaderBranch(String branch) { + return switch (normalizeBranch(branch)) { + case PRE_RELEASE_PATCHLINE -> RELEASE_PATCHLINE; + default -> RELEASE_PATCHLINE; + }; + } + + private static String responseSnippet(String body) { + if (body == null || body.isBlank()) { + return ""; + } + String compact = body.replaceAll("\\s+", " ").trim(); + return ": " + compact.substring(0, Math.min(compact.length(), 240)); + } + + private static long retryAfterMillis(HttpHeaders headers, Instant now) { + if (headers == null) { + return 0; + } + Optional retryAfter = headers.firstValue("Retry-After"); + if (retryAfter.isPresent()) { + long millis = parseRetryAfterMillis(retryAfter.get(), now); + if (millis > 0) { + return millis; + } + } + for (String header : List.of("X-RateLimit-Reset", "RateLimit-Reset")) { + Optional reset = headers.firstValue(header); + if (reset.isPresent()) { + long millis = parseRateLimitResetMillis(reset.get(), now); + if (millis > 0) { + return millis; + } + } + } + return 0; + } + + private static long parseRetryAfterMillis(String value, Instant now) { + if (value == null || value.isBlank()) { + return 0; + } + String trimmed = value.trim(); + try { + return Math.max(0, Long.parseLong(trimmed) * 1000L); + } catch (NumberFormatException ignored) { + // Retry-After may be an HTTP-date. + } + try { + Instant resetAt = ZonedDateTime.parse(trimmed, DateTimeFormatter.RFC_1123_DATE_TIME).toInstant(); + return Math.max(0, resetAt.toEpochMilli() - now.toEpochMilli()); + } catch (DateTimeParseException ignored) { + return 0; + } + } + + private static long parseRateLimitResetMillis(String value, Instant now) { + if (value == null || value.isBlank()) { + return 0; + } + try { + long parsed = Long.parseLong(value.trim()); + long epochSeconds = now.getEpochSecond(); + if (parsed > epochSeconds) { + return Math.max(0, (parsed - epochSeconds) * 1000L); + } + return Math.max(0, parsed * 1000L); + } catch (NumberFormatException ex) { + return parseRetryAfterMillis(value, now); + } + } + + private static String emptyIfNull(String value) { + return value == null ? "" : value; + } + + static List parseBlogPosts(String content, int count) { + if (content == null || content.isBlank() || count <= 0) { + return List.of(); + } + String trimmed = content.trim(); + if (trimmed.startsWith(" parseBlogHtml(String html, int count) { + List posts = new ArrayList<>(); + Set seen = new HashSet<>(); + Matcher articleMatcher = BLOG_ARTICLE_PATTERN.matcher(html); + while (articleMatcher.find() && posts.size() < count) { + String article = articleMatcher.group(); + String link = absoluteHytaleUrl(firstMatch(BLOG_LINK_PATTERN, article)); + String title = cleanRssText(firstMatch(BLOG_TITLE_PATTERN, article)); + if (title.isBlank() || link.isBlank() || !seen.add(link)) { + continue; + } + posts.add(new HytaleBlogPost( + title, + link, + absoluteHytaleUrl(firstMatch(BLOG_IMAGE_PATTERN, article)), + parseBlogPageDate(firstMatch(BLOG_DATE_PATTERN, article)) + )); + } + return posts; + } + + private static List parseBlogRss(String xml, int count) { + if (xml == null || xml.isBlank() || count <= 0) { + return List.of(); + } + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + configureSecureXml(factory); + Document document = factory.newDocumentBuilder().parse( + new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)) + ); + NodeList items = document.getElementsByTagName("item"); + List posts = new ArrayList<>(); + Set seen = new HashSet<>(); + for (int index = 0; index < items.getLength() && posts.size() < count; index++) { + if (!(items.item(index) instanceof Element item)) { + continue; + } + String title = cleanRssText(childText(item, "title")); + String link = cleanRssText(childText(item, "link")); + if (title.isBlank() || link.isBlank() || !seen.add(link)) { + continue; + } + posts.add(new HytaleBlogPost( + title, + link, + rssImageUrl(item), + parseRssDate(childText(item, "pubDate")) + )); + } + return posts; + } catch (IOException | ParserConfigurationException | SAXException ex) { + throw new HytaleApiException("Could not parse Hytale blog feed.", ex); + } + } + + private static String rssImageUrl(Element item) { + String imageUrl = childAttribute(item, "enclosure", "url"); + if (imageUrl.isBlank()) { + imageUrl = childAttribute(item, "media:content", "url"); + } + if (imageUrl.isBlank()) { + imageUrl = childAttribute(item, "media:thumbnail", "url"); + } + if (imageUrl.isBlank()) { + imageUrl = firstMatch(BLOG_IMAGE_PATTERN, childText(item, "description")); + } + return absoluteHytaleUrl(imageUrl); + } + + private static String firstMatch(Pattern pattern, String value) { + if (value == null || value.isBlank()) { + return ""; + } + Matcher matcher = pattern.matcher(value); + return matcher.find() ? matcher.group(1) : ""; + } + + private static String absoluteHytaleUrl(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String trimmed = value.trim(); + if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) { + return trimmed; + } + if (trimmed.startsWith("//")) { + return "https:" + trimmed; + } + if (trimmed.startsWith("/")) { + return "https://hytale.com" + trimmed; + } + return "https://hytale.com/" + trimmed; + } + + private static String normalizedBlogUrl(String value) { + if (value == null || value.isBlank()) { + return ""; + } + return value.trim().replaceAll("/+$", "").toLowerCase(Locale.ROOT); + } + + private static String normalizedBlogTitle(String value) { + if (value == null || value.isBlank()) { + return ""; + } + return cleanRssText(value).toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]+", " ").trim(); + } + + private static Instant parseBlogPageDate(String value) { + if (value == null || value.isBlank()) { + return Instant.EPOCH; + } + try { + LocalDate date = LocalDate.parse(value.trim(), BLOG_PAGE_DATE); + return date.atTime(LocalTime.NOON).toInstant(ZoneOffset.UTC); + } catch (DateTimeParseException ex) { + return Instant.EPOCH; + } + } + + static List parseFriends(JsonNode root) { + if (root == null || root.isMissingNode() || root.isNull()) { + return List.of(); + } + List friends = new ArrayList<>(); + Set seen = new HashSet<>(); + if (root.isArray()) { + addFriends(root, friends, seen); + } + List friendArrays = new ArrayList<>(); + collectFriendArrays(root, "", friendArrays); + for (JsonNode array : friendArrays) { + addFriends(array, friends, seen); + } + return friends; + } + + static Optional parsePublicProfileUsername(JsonNode root) { + if (root == null || root.isMissingNode() || root.isNull()) { + return Optional.empty(); + } + if (root.isArray()) { + for (JsonNode candidate : root) { + Optional username = parsePublicProfileUsername(candidate); + if (username.isPresent()) { + return username; + } + } + return Optional.empty(); + } + if (!root.isObject()) { + return Optional.empty(); + } + String username = firstText(root, "username", "displayName", "display_name", "name", "playerName", "player_name"); + if (!username.isBlank()) { + return Optional.of(username); + } + JsonNode profile = firstObject(root, "profile", "player", "user"); + username = firstText(profile, "username", "displayName", "display_name", "name", "playerName", "player_name"); + return username.isBlank() ? Optional.empty() : Optional.of(username); + } + + static List parsePatchlines(JsonNode root) { + if (root == null || root.isMissingNode() || root.isNull()) { + return List.of(); + } + LinkedHashSet patchlines = new LinkedHashSet<>(); + collectPatchlines(root, "", patchlines); + return List.copyOf(patchlines); + } + + private static void collectPatchlines(JsonNode node, String fieldName, LinkedHashSet patchlines) { + if (node == null || node.isNull()) { + return; + } + String field = fieldName == null ? "" : fieldName.toLowerCase(Locale.ROOT); + boolean patchlineContext = field.contains("patchline") || field.contains("channel"); + if (node.isTextual()) { + if (patchlineContext) { + normalizePatchlineId(node.asText()).ifPresent(patchlines::add); + } + return; + } + if (node.isArray()) { + node.forEach(child -> collectPatchlines(child, fieldName, patchlines)); + return; + } + if (!node.isObject()) { + return; + } + if (patchlineContext) { + for (String identityField : List.of("id", "name", "patchline", "channel", "selected_channel")) { + JsonNode identity = node.get(identityField); + if (identity != null && identity.isTextual()) { + normalizePatchlineId(identity.asText()).ifPresent(patchlines::add); + } + } + } + node.fields().forEachRemaining(entry -> { + if (patchlineContext) { + normalizePatchlineId(entry.getKey()).ifPresent(patchlines::add); + } + collectPatchlines(entry.getValue(), entry.getKey(), patchlines); + }); + } + + private static void addFriends(JsonNode array, List friends, Set seen) { + for (JsonNode candidate : array) { + Optional friend = toFriend(candidate); + if (friend.isEmpty()) { + continue; + } + HytaleFriend value = friend.get(); + String key = value.uuid().isBlank() + ? value.displayName().toLowerCase(Locale.ROOT) + : value.uuid().toLowerCase(Locale.ROOT); + if (seen.add(key)) { + friends.add(value); + } + } + } + + private static void collectFriendArrays(JsonNode node, String fieldName, List friendArrays) { + if (node == null || node.isNull()) { + return; + } + String normalized = fieldName == null ? "" : fieldName.toLowerCase(); + if (node.isArray()) { + if (normalized.contains("friend")) { + friendArrays.add(node); + return; + } + node.forEach(child -> collectFriendArrays(child, "", friendArrays)); + return; + } + if (!node.isObject()) { + return; + } + node.fields().forEachRemaining(entry -> collectFriendArrays(entry.getValue(), entry.getKey(), friendArrays)); + } + + private static Optional toFriend(JsonNode node) { + if (node == null || !node.isObject()) { + return Optional.empty(); + } + JsonNode identity = firstObject(node, "friend", "profile", "player", "user", "account", "member"); + String username = firstIdentityText(node, identity, + "username", "displayName", "display_name", "name", "playerName", "player_name"); + String uuid = firstIdentityText(node, identity, + "uuid", "profileUuid", "profile_uuid", "playerUuid", "player_uuid", "id", "playerId", "player_id"); + if (username.isBlank() && uuid.isBlank()) { + return Optional.empty(); + } + String status = firstText(node, "status", "presence", "activity", "state"); + JsonNode presence = firstObject(node, "presence", "activity", "state"); + String normalizedStatus = status.toLowerCase(Locale.ROOT).replace('_', ' ').replace('-', ' '); + boolean online = firstBoolean(node, "online", "isOnline", "is_online") + || firstBoolean(presence, "online", "isOnline", "is_online") + || normalizedStatus.contains("online") + || normalizedStatus.contains("playing") + || normalizedStatus.contains("in game"); + return Optional.of(new HytaleFriend( + username, + uuid, + readablePresence(status, online), + firstIdentityText(node, identity, "avatarUrl", "avatar_url", "avatar", "imageUrl", "image_url"), + online + )); + } + + private static String firstIdentityText(JsonNode node, JsonNode identity, String... fields) { + String direct = firstText(node, fields); + if (!direct.isBlank()) { + return direct; + } + String nested = firstText(identity, fields); + if (!nested.isBlank()) { + return nested; + } + JsonNode nestedIdentity = firstObject(identity, "friend", "profile", "player", "user", "account", "member"); + return firstText(nestedIdentity, fields); + } + + private static JsonNode firstObject(JsonNode node, String... fields) { + if (node == null || !node.isObject()) { + return null; + } + for (String field : fields) { + JsonNode child = node.get(field); + if (child != null && child.isObject()) { + return child; + } + } + return null; + } + + private static String firstText(JsonNode node, String... fields) { + if (node == null) { + return ""; + } + for (String field : fields) { + JsonNode child = node.get(field); + String value = textValue(child); + if (!value.isBlank()) { + return value; + } + } + return ""; + } + + private static String textValue(JsonNode node) { + if (node == null || node.isNull()) { + return ""; + } + if (node.isObject()) { + return firstText(node, "status", "state", "activity", "text", "value", "username", + "displayName", "display_name", "name"); + } + if (node.isArray()) { + return ""; + } + return node.asText("").trim(); + } + + private static boolean firstBoolean(JsonNode node, String... fields) { + if (node == null) { + return false; + } + for (String field : fields) { + JsonNode child = node.get(field); + if (child != null && child.isBoolean() && child.asBoolean()) { + return true; + } + } + return false; + } + + private static String readablePresence(String rawStatus, boolean online) { + if (rawStatus == null || rawStatus.isBlank()) { + return online ? "Online" : "Offline"; + } + String compact = rawStatus.trim().replace('_', ' ').replace('-', ' '); + if (compact.equalsIgnoreCase("online")) { + return "Online"; + } + if (compact.equalsIgnoreCase("offline")) { + return "Offline"; + } + if (compact.equalsIgnoreCase("playing")) { + return "Playing"; + } + if (compact.equalsIgnoreCase("in game")) { + return "In game"; + } + return compact; + } + + private static void configureSecureXml(DocumentBuilderFactory factory) throws ParserConfigurationException { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + setXmlFeature(factory, "http://apache.org/xml/features/disallow-doctype-decl", true); + setXmlFeature(factory, "http://xml.org/sax/features/external-general-entities", false); + setXmlFeature(factory, "http://xml.org/sax/features/external-parameter-entities", false); + factory.setExpandEntityReferences(false); + } + + private static void setXmlFeature(DocumentBuilderFactory factory, String feature, boolean value) throws ParserConfigurationException { + try { + factory.setFeature(feature, value); + } catch (ParserConfigurationException ex) { + throw ex; + } catch (Exception ignored) { + // Some XML implementations do not support every hardening flag. + } + } + + private static String childText(Element element, String tagName) { + NodeList nodes = element.getElementsByTagName(tagName); + if (nodes.getLength() == 0 || nodes.item(0) == null) { + return ""; + } + return nodes.item(0).getTextContent(); + } + + private static String childAttribute(Element element, String tagName, String attributeName) { + NodeList nodes = element.getElementsByTagName(tagName); + if (nodes.getLength() == 0 || !(nodes.item(0) instanceof Element child)) { + return ""; + } + return child.getAttribute(attributeName); + } + + private static String cleanRssText(String value) { + if (value == null || value.isBlank()) { + return ""; + } + return value + .replaceAll("<[^>]+>", " ") + .replace(""", "\"") + .replace(""", "\"") + .replace("'", "'") + .replace("'", "'") + .replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replaceAll("\\s+", " ") + .trim(); + } + + private static Instant parseRssDate(String value) { + if (value == null || value.isBlank()) { + return Instant.EPOCH; + } + try { + return ZonedDateTime.parse(value.trim(), DateTimeFormatter.RFC_1123_DATE_TIME).toInstant(); + } catch (DateTimeParseException ex) { + return Instant.EPOCH; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class TokenResponse { + @JsonProperty("access_token") + public String accessToken = ""; + + @JsonProperty("refresh_token") + public String refreshToken = ""; + + @JsonProperty("expires_in") + public long expiresIn = 0; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private static final class ProfilesResponse { + public String owner = ""; + public List profiles = List.of(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private static final class ProfileEntry { + public String uuid = ""; + public String username = ""; + public long playtimeSeconds; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private static final class GameSessionResponse { + public String sessionToken = ""; + public String identityToken = ""; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private static final class OfficialPatchesResponse { + public List steps = List.of(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private static final class OfficialPatchStep { + public int from; + public int to; + public String pwr = ""; + public String pwrHead = ""; + public String sig = ""; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiException.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiException.java new file mode 100644 index 00000000..ff6e1dbe --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleApiException.java @@ -0,0 +1,43 @@ +package net.modtale.launcher.hytale; + +public class HytaleApiException extends RuntimeException { + + private final int statusCode; + private final long retryAfterMillis; + + public HytaleApiException(String message) { + this(message, -1, null); + } + + public HytaleApiException(String message, Throwable cause) { + this(message, -1, cause); + } + + public HytaleApiException(String message, int statusCode, Throwable cause) { + this(message, statusCode, cause, 0); + } + + public HytaleApiException(String message, int statusCode, Throwable cause, long retryAfterMillis) { + super(message, cause); + this.statusCode = statusCode; + this.retryAfterMillis = Math.max(0, retryAfterMillis); + } + + public int statusCode() { + return statusCode; + } + + public long retryAfterMillis() { + return retryAfterMillis; + } + + public boolean isAuthFailure() { + return statusCode == 401 || statusCode == 403; + } + + public boolean requiresSignIn() { + String message = getMessage(); + return isAuthFailure() + || (statusCode == 400 && message != null && message.contains("invalid_grant")); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthService.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthService.java new file mode 100644 index 00000000..e9bb3504 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthService.java @@ -0,0 +1,599 @@ +package net.modtale.launcher.hytale; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpServer; +import java.awt.Desktop; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.time.Instant; +import java.util.Base64; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import net.modtale.launcher.settings.LauncherSettings; +import net.modtale.launcher.settings.SettingsStore; + +public class HytaleAuthService { + + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + private static final long LOGIN_TIMEOUT_MINUTES = 15; + private static final Pattern JWT_EXP_PATTERN = Pattern.compile("\"exp\"\\s*:\\s*(\\d+)"); + private static final Pattern GAME_VERSION_PATTERN = Pattern.compile("^(\\d+)\\.(\\d+)(?:\\.(\\d+))?.*$"); + + private final HytaleApiClient apiClient; + private final SettingsStore settingsStore; + + public HytaleAuthService(HytaleApiClient apiClient, SettingsStore settingsStore) { + this.apiClient = apiClient; + this.settingsStore = settingsStore; + } + + public HytaleAuthSession loginAndSave(LauncherSettings settings) { + OAuthGrant grant = requestAuthorizationCode(); + HytaleApiClient.TokenResponse token = apiClient.exchangeCode(grant.code(), grant.codeVerifier()); + List profiles = apiClient.fetchProfiles(token.accessToken); + HytaleProfile profile = profiles.getFirst(); + HytaleGameSession gameSession = apiClient.createGameSession(token.accessToken, profile.uuid()); + if (!gameSession.hasLaunchTokens()) { + throw new HytaleApiException("Hytale did not return launch session tokens. The game was not launched."); + } + + HytaleAuthSession session = new HytaleAuthSession(); + session.setAccessToken(token.accessToken); + session.setRefreshToken(token.refreshToken); + session.setExpiresAt(expiresAt(token.expiresIn)); + session.setUsername(profile.username()); + session.setUuid(profile.uuid()); + session.setAccountOwnerId(profile.owner()); + session.setProfiles(profiles); + session.setSessionToken(gameSession.sessionToken()); + session.setIdentityToken(gameSession.identityToken()); + settings.upsertHytaleAuthSession(session); + settingsStore.save(settings); + return session; + } + + public void selectAccount(LauncherSettings settings, String accountId) { + if (settings == null || accountId == null || accountId.isBlank()) { + return; + } + settings.selectHytaleAccount(accountId); + settingsStore.save(settings); + } + + public void selectProfile(LauncherSettings settings, HytaleProfile selectedProfile) { + if (settings == null || selectedProfile == null || selectedProfile.uuid().isBlank()) { + return; + } + HytaleAuthSession session = settings.getHytaleAuthSession(); + if (session == null) { + throw new HytaleApiException("Sign in with Hytale before choosing a profile."); + } + HytaleProfile profile = session.getProfiles().stream() + .filter(candidate -> selectedProfile.uuid().equals(candidate.uuid())) + .findFirst() + .orElse(selectedProfile); + session.setUsername(profile.username()); + session.setUuid(profile.uuid()); + settings.upsertHytaleAuthSession(session); + settingsStore.save(settings); + } + + public void logout(LauncherSettings settings) { + settings.removeActiveHytaleAuthSession(); + settingsStore.save(settings); + } + + public void logoutAccount(LauncherSettings settings, String accountId) { + if (settings == null || accountId == null || accountId.isBlank()) { + return; + } + settings.removeHytaleAuthSession(accountId); + settingsStore.save(settings); + } + + public List getAvailableVersions(LauncherSettings settings, String branch) { + HytaleAuthSession session = ensureValidAccessToken(settings); + try { + return HytaleGameVersionResolver.labelVersions(settings, branch, + apiClient.getAvailableVersions(session.getAccessToken(), branch)); + } catch (HytaleApiException ex) { + if (!ex.isAuthFailure()) { + throw ex; + } + session = refresh(settings, session); + return HytaleGameVersionResolver.labelVersions(settings, branch, + apiClient.getAvailableVersions(session.getAccessToken(), branch)); + } + } + + public List getAvailablePatchlines(LauncherSettings settings) { + HytaleAuthSession session = ensureValidAccessToken(settings); + List candidates = previousPatchlineCandidates(settings); + try { + return apiClient.getAvailablePatchlines(session.getAccessToken(), candidates); + } catch (HytaleApiException ex) { + if (!ex.isAuthFailure()) { + throw ex; + } + session = refresh(settings, session); + return apiClient.getAvailablePatchlines(session.getAccessToken(), candidates); + } + } + + public List getFriends(LauncherSettings settings) { + HytaleAuthSession cachedSession = settings.getHytaleAuthSession(); + if (canUseCachedFriendsSession(cachedSession)) { + try { + return enrichFriendsWithPublicProfiles( + cachedSession.getSessionToken(), + apiClient.fetchFriends(cachedSession.getSessionToken()) + ); + } catch (HytaleApiException ex) { + if (!ex.isAuthFailure()) { + throw ex; + } + } + } + + HytaleAuthSession session = ensureValidAccessToken(settings); + try { + return fetchFriendsWithFreshGameSession(settings, session); + } catch (HytaleApiException ex) { + if (!ex.isAuthFailure()) { + throw ex; + } + session = refresh(settings, session); + return fetchFriendsWithFreshGameSession(settings, session); + } + } + + public long getProfilePlaytimeSeconds(LauncherSettings settings) { + HytaleAuthSession session = ensureValidAccessToken(settings); + try { + return refreshProfilesAndGetPlaytime(settings, session); + } catch (HytaleApiException ex) { + if (!ex.isAuthFailure()) { + throw ex; + } + session = refresh(settings, session); + return refreshProfilesAndGetPlaytime(settings, session); + } + } + + public List getBlogPosts(int count) { + return apiClient.getBlogPosts(count); + } + + public List getAllBlogPosts() { + return apiClient.getAllBlogPosts(); + } + + public HytaleAuthSession ensureFreshSessionForLaunch(LauncherSettings settings) { + HytaleAuthSession existingSession = settings.getHytaleAuthSession(); + if (existingSession == null || !existingSession.hasRefreshToken()) { + throw new HytaleApiException("Sign in with Hytale before launching or loading Hytale versions."); + } + try { + HytaleAuthSession session = ensureValidAccessToken(settings); + HytaleGameSession gameSession = createGameSessionWithRefresh(settings, session); + if (!gameSession.hasLaunchTokens()) { + throw new HytaleApiException("Hytale did not return launch session tokens. The game was not launched."); + } + return saveGameSession(settings, session, gameSession); + } catch (HytaleApiException ex) { + HytaleAuthSession cachedSession = settings.getHytaleAuthSession(); + if (canUseCachedLaunchSession(cachedSession, ex)) { + return cachedSession; + } + throw ex; + } + } + + private List fetchFriendsWithFreshGameSession(LauncherSettings settings, HytaleAuthSession session) { + HytaleGameSession gameSession = createGameSessionWithRefresh(settings, session); + if (!gameSession.hasLaunchTokens()) { + throw new HytaleApiException("Hytale did not return social session tokens."); + } + HytaleAuthSession updatedSession = saveGameSession(settings, session, gameSession); + return enrichFriendsWithPublicProfiles( + updatedSession.getSessionToken(), + apiClient.fetchFriends(updatedSession.getSessionToken()) + ); + } + + private long refreshProfilesAndGetPlaytime(LauncherSettings settings, HytaleAuthSession session) { + List profiles = apiClient.fetchProfiles(session.getAccessToken()); + String selectedUuid = session.getUuid(); + HytaleProfile selectedProfile = profiles.stream() + .filter(profile -> profile.uuid().equals(selectedUuid)) + .findFirst() + .orElseGet(() -> profiles.isEmpty() ? null : profiles.getFirst()); + session.setProfiles(profiles); + if (selectedProfile != null) { + session.setUsername(selectedProfile.username()); + session.setUuid(selectedProfile.uuid()); + session.setAccountOwnerId(selectedProfile.owner()); + } + settings.upsertHytaleAuthSession(session); + settingsStore.save(settings); + return selectedProfile == null ? 0 : selectedProfile.playtimeSeconds(); + } + + static List previousPatchlineCandidates(LauncherSettings settings) { + LinkedHashSet candidates = new LinkedHashSet<>(); + if (settings != null) { + HytaleApiClient.normalizePatchlineId(settings.getHytaleBranch()) + .filter(patchline -> patchline.startsWith("v")) + .ifPresent(candidates::add); + } + HytaleGameVersionResolver.resolveBuildVersions(settings).values().stream() + .map(HytaleAuthService::parseGameVersion) + .flatMap(Optional::stream) + .max(GameVersion::compareTo) + .flatMap(GameVersion::previousPatchline) + .ifPresent(candidates::add); + return List.copyOf(candidates); + } + + private static Optional parseGameVersion(String value) { + if (value == null || value.isBlank()) { + return Optional.empty(); + } + Matcher matcher = GAME_VERSION_PATTERN.matcher(value.trim()); + if (!matcher.matches()) { + return Optional.empty(); + } + return Optional.of(new GameVersion( + parseVersionPart(matcher.group(1)), + parseVersionPart(matcher.group(2)), + parseVersionPart(matcher.group(3)) + )); + } + + private static int parseVersionPart(String value) { + if (value == null || value.isBlank()) { + return 0; + } + try { + return Integer.parseInt(value); + } catch (NumberFormatException ex) { + return 0; + } + } + + private List enrichFriendsWithPublicProfiles(String sessionToken, List friends) { + if (friends == null || friends.isEmpty()) { + return List.of(); + } + List unresolvedUuids = friends.stream() + .filter(friend -> friend.username().isBlank() && !friend.uuid().isBlank()) + .map(HytaleFriend::uuid) + .toList(); + if (unresolvedUuids.isEmpty()) { + return friends; + } + Map usernamesByUuid = apiClient.fetchPublicProfileUsernames(sessionToken, unresolvedUuids); + if (usernamesByUuid.isEmpty()) { + return friends; + } + return friends.stream() + .map(friend -> { + if (!friend.username().isBlank() || friend.uuid().isBlank()) { + return friend; + } + String username = usernamesByUuid.get(friend.uuid().toLowerCase(Locale.ROOT)); + return username == null || username.isBlank() ? friend : friend.withUsername(username); + }) + .toList(); + } + + private HytaleAuthSession saveGameSession( + LauncherSettings settings, + HytaleAuthSession session, + HytaleGameSession gameSession + ) { + session.setSessionToken(gameSession.sessionToken()); + session.setIdentityToken(gameSession.identityToken()); + settings.upsertHytaleAuthSession(session); + settingsStore.save(settings); + return session; + } + + private HytaleGameSession createGameSessionWithRefresh(LauncherSettings settings, HytaleAuthSession session) { + try { + return apiClient.createGameSession(session.getAccessToken(), session.getUuid()); + } catch (HytaleApiException ex) { + if (!ex.isAuthFailure()) { + throw ex; + } + HytaleAuthSession refreshed = refresh(settings, session); + return apiClient.createGameSession(refreshed.getAccessToken(), refreshed.getUuid()); + } + } + + private HytaleAuthSession ensureValidAccessToken(LauncherSettings settings) { + HytaleAuthSession session = settings.getHytaleAuthSession(); + if (session == null || !session.hasRefreshToken()) { + throw new HytaleApiException("Sign in with Hytale before launching or loading Hytale versions."); + } + if (!session.hasAccessToken() || session.getExpiresAt().isBefore(Instant.now().plusSeconds(60))) { + return refresh(settings, session); + } + return session; + } + + private HytaleAuthSession refresh(LauncherSettings settings, HytaleAuthSession session) { + try { + HytaleApiClient.TokenResponse token = apiClient.refreshToken(session.getRefreshToken()); + session.setAccessToken(token.accessToken); + if (token.refreshToken != null && !token.refreshToken.isBlank()) { + session.setRefreshToken(token.refreshToken); + } + session.setExpiresAt(expiresAt(token.expiresIn)); + settings.upsertHytaleAuthSession(session); + settingsStore.save(settings); + return session; + } catch (HytaleApiException ex) { + if (ex.requiresSignIn()) { + removeExpiredSession(settings, session); + } + throw ex; + } + } + + private void removeExpiredSession(LauncherSettings settings, HytaleAuthSession session) { + String accountId = LauncherSettings.hytaleAccountId(session); + if (accountId.isBlank()) { + settings.removeActiveHytaleAuthSession(); + } else { + settings.removeHytaleAuthSession(accountId); + } + settingsStore.save(settings); + } + + private static boolean canUseCachedLaunchSession(HytaleAuthSession session, HytaleApiException failure) { + return session != null + && session.hasRefreshToken() + && session.hasLaunchTokens() + && permitsCachedLaunchSession(failure); + } + + private static boolean permitsCachedLaunchSession(HytaleApiException failure) { + return failure != null + && (failure.isAuthFailure() || failure.statusCode() < 0 || failure.statusCode() >= 500); + } + + private static boolean canUseCachedFriendsSession(HytaleAuthSession session) { + return session != null + && session.hasLaunchTokens() + && jwtExpiresAfter(session.getSessionToken(), Instant.now().plusSeconds(60)); + } + + private static boolean jwtExpiresAfter(String token, Instant threshold) { + if (token == null || token.isBlank() || threshold == null) { + return false; + } + String[] parts = token.split("\\."); + if (parts.length < 2) { + return false; + } + try { + String payload = new String(Base64.getUrlDecoder().decode(padBase64Url(parts[1])), StandardCharsets.UTF_8); + Matcher matcher = JWT_EXP_PATTERN.matcher(payload); + if (!matcher.find()) { + return false; + } + return Instant.ofEpochSecond(Long.parseLong(matcher.group(1))).isAfter(threshold); + } catch (IllegalArgumentException ex) { + return false; + } + } + + private static String padBase64Url(String value) { + int padding = (4 - value.length() % 4) % 4; + return value + "=".repeat(padding); + } + + private OAuthGrant requestAuthorizationCode() { + String codeVerifier = generateCodeVerifier(); + String codeChallenge = codeChallenge(codeVerifier); + CompletableFuture codeFuture = new CompletableFuture<>(); + HttpServer server = null; + try { + server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 1); + int port = server.getAddress().getPort(); + OAuthState state = stateForPort(port); + server.createContext("/", exchange -> handleCallback(exchange, codeFuture, state)); + server.start(); + + URI authUri = URI.create(HytaleApiClient.AUTH_URL + + "?access_type=offline" + + "&client_id=" + encode(HytaleApiClient.CLIENT_ID) + + "&code_challenge=" + encode(codeChallenge) + + "&code_challenge_method=S256" + + "&redirect_uri=" + encode(HytaleApiClient.REDIRECT_URI) + + "&response_type=code" + + "&scope=" + encode(HytaleApiClient.SCOPES) + + "&state=" + encode(state.encodedState())); + openBrowser(authUri); + return new OAuthGrant(codeFuture.get(LOGIN_TIMEOUT_MINUTES, TimeUnit.MINUTES), codeVerifier); + } catch (TimeoutException ex) { + throw new HytaleApiException("Hytale sign-in timed out. Please try again.", ex); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new HytaleApiException("Hytale sign-in was interrupted.", ex); + } catch (Exception ex) { + if (ex instanceof HytaleApiException hytaleEx) { + throw hytaleEx; + } + throw new HytaleApiException("Hytale sign-in failed: " + ex.getMessage(), ex); + } finally { + if (server != null) { + server.stop(0); + } + } + } + + private void handleCallback(HttpExchange exchange, CompletableFuture codeFuture, OAuthState expectedState) throws IOException { + Map query = parseQuery(exchange.getRequestURI().getRawQuery()); + String code = query.get("code"); + String error = query.get("error"); + String returnedState = query.get("state"); + + String html; + if (error != null && !error.isBlank()) { + codeFuture.completeExceptionally(new HytaleApiException("Hytale authorization failed: " + error)); + html = page("Authorization failed", "Return to Modtale and try signing in again."); + } else if (code != null && !code.isBlank()) { + if (expectedState.matches(returnedState)) { + codeFuture.complete(code); + html = page("Authorization successful", "You can close this window and return to Modtale."); + } else { + codeFuture.completeExceptionally(new HytaleApiException("Hytale authorization returned an unexpected state.")); + html = page("Authorization failed", "Return to Modtale and try signing in again."); + } + } else { + html = page("Waiting for authorization", "Return to the Hytale authorization page to finish signing in."); + } + + byte[] body = html.getBytes(StandardCharsets.UTF_8); + exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8"); + exchange.sendResponseHeaders(200, body.length); + try (OutputStream output = exchange.getResponseBody()) { + output.write(body); + } + } + + private static void openBrowser(URI uri) { + if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + throw new HytaleApiException("Desktop browser integration is not available. Could not open Hytale sign-in."); + } + try { + Desktop.getDesktop().browse(uri); + } catch (IOException ex) { + throw new HytaleApiException("Could not open Hytale sign-in in your browser.", ex); + } + } + + private static Map parseQuery(String rawQuery) { + Map values = new LinkedHashMap<>(); + if (rawQuery == null || rawQuery.isBlank()) { + return values; + } + for (String pair : rawQuery.split("&")) { + int separator = pair.indexOf('='); + String key = separator >= 0 ? pair.substring(0, separator) : pair; + String value = separator >= 0 ? pair.substring(separator + 1) : ""; + values.put(decode(key), decode(value)); + } + return values; + } + + private static String page(String title, String message) { + return """ + + %s +

    %s

    %s

    + + """.formatted(title, title, message); + } + + private static String generateCodeVerifier() { + byte[] bytes = new byte[32]; + SECURE_RANDOM.nextBytes(bytes); + return base64Url(bytes); + } + + private static String codeChallenge(String verifier) { + try { + return base64Url(MessageDigest.getInstance("SHA-256").digest(verifier.getBytes(StandardCharsets.US_ASCII))); + } catch (NoSuchAlgorithmException ex) { + throw new HytaleApiException("SHA-256 is not available for Hytale sign-in.", ex); + } + } + + static OAuthState stateForPort(int port) { + String callbackState = randomBase32(26); + String json = "{\"state\":\"" + callbackState + "\",\"port\":\"" + port + "\"}"; + String encodedState = Base64.getEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8)); + return new OAuthState(encodedState, callbackState, port); + } + + private static String randomBase32(int length) { + char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".toCharArray(); + byte[] bytes = new byte[length]; + SECURE_RANDOM.nextBytes(bytes); + char[] result = new char[length]; + for (int index = 0; index < length; index++) { + result[index] = chars[Byte.toUnsignedInt(bytes[index]) % chars.length]; + } + return new String(result); + } + + private static String base64Url(byte[] bytes) { + return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); + } + + private static String encode(String value) { + return java.net.URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8); + } + + private static String decode(String value) { + return URLDecoder.decode(value == null ? "" : value, StandardCharsets.UTF_8); + } + + private static Instant expiresAt(long expiresInSeconds) { + long seconds = expiresInSeconds <= 0 ? 3600 : expiresInSeconds; + return Instant.now().plusSeconds(seconds); + } + + private record OAuthGrant(String code, String codeVerifier) { + } + + private record GameVersion(int major, int minor, int patch) implements Comparable { + + private Optional previousPatchline() { + if (minor <= 0) { + return Optional.empty(); + } + return Optional.of("v" + major + "." + (minor - 1)); + } + + @Override + public int compareTo(GameVersion other) { + int majorCompare = Integer.compare(major, other.major); + if (majorCompare != 0) { + return majorCompare; + } + int minorCompare = Integer.compare(minor, other.minor); + if (minorCompare != 0) { + return minorCompare; + } + return Integer.compare(patch, other.patch); + } + } + + record OAuthState(String encodedState, String callbackState, int port) { + + boolean matches(String returnedState) { + return returnedState != null && !returnedState.isBlank() + && (returnedState.equals(callbackState) || returnedState.equals(encodedState)); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthSession.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthSession.java new file mode 100644 index 00000000..263295b7 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleAuthSession.java @@ -0,0 +1,111 @@ +package net.modtale.launcher.hytale; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class HytaleAuthSession { + + private String accessToken = ""; + private String refreshToken = ""; + private Instant expiresAt = Instant.EPOCH; + private String sessionToken = ""; + private String identityToken = ""; + private String username = ""; + private String uuid = ""; + private String accountOwnerId = ""; + private List profiles = new ArrayList<>(); + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken == null ? "" : accessToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken == null ? "" : refreshToken; + } + + public Instant getExpiresAt() { + return expiresAt; + } + + public void setExpiresAt(Instant expiresAt) { + this.expiresAt = expiresAt == null ? Instant.EPOCH : expiresAt; + } + + public String getSessionToken() { + return sessionToken; + } + + public void setSessionToken(String sessionToken) { + this.sessionToken = sessionToken == null ? "" : sessionToken; + } + + public String getIdentityToken() { + return identityToken; + } + + public void setIdentityToken(String identityToken) { + this.identityToken = identityToken == null ? "" : identityToken; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username == null ? "" : username; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid == null ? "" : uuid; + } + + public String getAccountOwnerId() { + return accountOwnerId; + } + + public void setAccountOwnerId(String accountOwnerId) { + this.accountOwnerId = accountOwnerId == null ? "" : accountOwnerId; + } + + public List getProfiles() { + return List.copyOf(profiles); + } + + public void setProfiles(List profiles) { + this.profiles = profiles == null ? new ArrayList<>() : new ArrayList<>(profiles); + } + + public boolean hasRefreshToken() { + return refreshToken != null && !refreshToken.isBlank(); + } + + public boolean hasAccessToken() { + return accessToken != null && !accessToken.isBlank(); + } + + public boolean hasLaunchTokens() { + return identityToken != null && !identityToken.isBlank() + && sessionToken != null && !sessionToken.isBlank() + && uuid != null && !uuid.isBlank(); + } + + @Override + public String toString() { + return username == null || username.isBlank() ? "Hytale account" : username; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleBlogPost.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleBlogPost.java new file mode 100644 index 00000000..6802f0f6 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleBlogPost.java @@ -0,0 +1,13 @@ +package net.modtale.launcher.hytale; + +import java.time.Instant; + +public record HytaleBlogPost(String title, String url, String imageUrl, Instant publishedAt) { + + public HytaleBlogPost { + title = title == null ? "" : title.trim(); + url = url == null ? "" : url.trim(); + imageUrl = imageUrl == null ? "" : imageUrl.trim(); + publishedAt = publishedAt == null ? Instant.EPOCH : publishedAt; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleFriend.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleFriend.java new file mode 100644 index 00000000..1c161ab2 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleFriend.java @@ -0,0 +1,29 @@ +package net.modtale.launcher.hytale; + +public record HytaleFriend(String username, String uuid, String status, String avatarUrl, boolean online) { + + public HytaleFriend { + username = username == null ? "" : username.trim(); + uuid = uuid == null ? "" : uuid.trim(); + status = status == null ? "" : status.trim(); + avatarUrl = avatarUrl == null ? "" : avatarUrl.trim(); + } + + public String displayName() { + if (!username.isBlank()) { + return username; + } + return uuid.isBlank() ? "Hytale friend" : uuid; + } + + public HytaleFriend withUsername(String username) { + return new HytaleFriend(username, uuid, status, avatarUrl, online); + } + + public String displayStatus() { + if (!status.isBlank()) { + return status; + } + return online ? "Online" : "Offline"; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameLauncher.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameLauncher.java new file mode 100644 index 00000000..2f20e3d6 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameLauncher.java @@ -0,0 +1,264 @@ +package net.modtale.launcher.hytale; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import net.modtale.launcher.settings.HytalePathDetector; +import net.modtale.launcher.settings.LauncherSettings; + +public class HytaleGameLauncher { + + private final HytaleAuthService authService; + + public HytaleGameLauncher(HytaleAuthService authService) { + this.authService = authService; + } + + public HytaleLaunchResult launch(LauncherSettings settings) { + HytaleAuthSession session = authService.ensureFreshSessionForLaunch(settings); + if (!session.hasLaunchTokens()) { + throw new HytaleApiException("A fresh Hytale-authenticated session is required before launch."); + } + + LaunchPaths paths = resolvePaths(settings); + try { + Files.createDirectories(paths.userDataDirectory()); + ProcessBuilder builder = new ProcessBuilder(command(paths, session)); + builder.directory(paths.workingDirectory().toFile()); + builder.redirectErrorStream(true); + applyEnvironment(builder.environment(), paths); + Process process = builder.start(); + return new HytaleLaunchResult(process, paths.executable(), session.getUsername(), session.getUuid()); + } catch (IOException ex) { + throw new HytaleApiException("Could not launch Hytale: " + ex.getMessage(), ex); + } + } + + static List command(LaunchPaths paths, HytaleAuthSession session) { + List command = new ArrayList<>(); + command.add(paths.executable().toString()); + command.addAll(authenticatedArguments(paths.gameDirectory(), paths.userDataDirectory(), paths.javaExecutable(), session)); + return command; + } + + static List authenticatedArguments( + Path gameDirectory, + Path userDataDirectory, + Path javaExecutable, + HytaleAuthSession session + ) { + if (session == null || !session.hasLaunchTokens()) { + throw new HytaleApiException("A fresh Hytale-authenticated session is required before launch."); + } + List args = new ArrayList<>(); + args.add("--app-dir"); + args.add(gameDirectory.toString()); + args.add("--user-dir"); + args.add(userDataDirectory.toString()); + args.add("--java-exec"); + args.add(javaExecutable.toString()); + args.add("--name"); + args.add(session.getUsername()); + args.add("--auth-mode"); + args.add("authenticated"); + args.add("--uuid"); + args.add(session.getUuid()); + args.add("--identity-token"); + args.add(session.getIdentityToken()); + args.add("--session-token"); + args.add(session.getSessionToken()); + return args; + } + + static LaunchPaths resolvePaths(LauncherSettings settings) { + Path configuredGameDirectory = settings.hytaleGameDirectory(); + if (configuredGameDirectory.toString().isBlank()) { + throw new HytaleApiException("Choose the Hytale game folder before launching."); + } + Path gameDirectory = resolveGameDirectory( + configuredGameDirectory, + settings.getHytaleBranch(), + settings.getHytaleBuild() + ); + Path executable = resolveExecutable(gameDirectory); + if (!Files.isRegularFile(executable)) { + throw new HytaleApiException("Hytale client was not found. Choose the Hytale data folder or a game folder containing " + + resolveExecutable(configuredGameDirectory)); + } + + Path userDataDirectory = settings.hytaleUserDataDirectory(); + Path javaExecutable = resolveJavaExecutable( + settings.hytaleJavaExecutable(), + gameDirectory, + userDataDirectory, + settings.getHytaleBranch() + ); + if (!Files.isRegularFile(javaExecutable)) { + throw new HytaleApiException("Java executable was not found at " + javaExecutable); + } + + Path workingDirectory = HytalePlatform.isMac() + ? executable.getParent() + : gameDirectory.resolve("Client"); + return new LaunchPaths(gameDirectory, userDataDirectory, javaExecutable, executable, workingDirectory); + } + + static Path resolveGameDirectory(Path configuredDirectory, String branch, int build) { + return gameDirectoryCandidates(configuredDirectory, branch, build).stream() + .filter(HytaleGameLauncher::containsClientExecutable) + .findFirst() + .orElse(configuredDirectory); + } + + static Path resolveJavaExecutable(Path configuredJava, Path gameDirectory, Path userDataDirectory, String branch) { + if (Files.isRegularFile(configuredJava) && !HytalePathDetector.isCurrentJavaExecutable(configuredJava)) { + return configuredJava; + } + + Optional bundledJava = bundledJavaCandidates(gameDirectory, userDataDirectory, branch).stream() + .filter(Files::isRegularFile) + .findFirst(); + if (bundledJava.isPresent()) { + return bundledJava.get(); + } + + if (Files.isRegularFile(configuredJava)) { + return configuredJava; + } + + return HytalePathDetector.detectExistingJavaExecutable().orElse(configuredJava); + } + + static Path resolveExecutable(Path gameDirectory) { + if (HytalePlatform.isMac()) { + return gameDirectory.resolve(Path.of("Client", "Hytale.app", "Contents", "MacOS", "HytaleClient")); + } + if (HytalePlatform.isWindows()) { + return gameDirectory.resolve(Path.of("Client", "HytaleClient.exe")); + } + return gameDirectory.resolve(Path.of("Client", "HytaleClient")); + } + + private static void applyEnvironment(Map environment, LaunchPaths paths) { + Path clientDirectory = paths.gameDirectory().resolve("Client"); + if (HytalePlatform.isWindows()) { + return; + } + + String separator = System.getProperty("path.separator", ":"); + String existingLd = environment.getOrDefault("LD_LIBRARY_PATH", ""); + environment.put("LD_LIBRARY_PATH", clientDirectory + (existingLd.isBlank() ? "" : separator + existingLd)); + + if (HytalePlatform.isMac()) { + String existingDyld = environment.getOrDefault("DYLD_LIBRARY_PATH", ""); + environment.put("DYLD_LIBRARY_PATH", clientDirectory + (existingDyld.isBlank() ? "" : separator + existingDyld)); + } + } + + private static boolean containsClientExecutable(Path path) { + return Files.isRegularFile(resolveExecutable(path)); + } + + private static List gameDirectoryCandidates(Path configuredDirectory, String branch, int build) { + LinkedHashSet paths = new LinkedHashSet<>(); + paths.add(configuredDirectory); + addVersionFolders(paths, configuredDirectory, build); + addOfficialGameFolders(paths, configuredDirectory, branch, build); + dataRootFromOfficialGameDirectory(configuredDirectory).ifPresent(root -> addOfficialGameFolders(paths, root, branch, build)); + return List.copyOf(paths); + } + + private static void addOfficialGameFolders(LinkedHashSet paths, Path hytaleDataRoot, String branch, int build) { + for (String branchName : branchNames(branch)) { + Path gameRoot = hytaleDataRoot.resolve(Path.of("install", branchName, "package", "game")); + addVersionFolders(paths, gameRoot, build); + paths.add(gameRoot); + } + } + + private static void addVersionFolders(LinkedHashSet paths, Path root, int build) { + if (build > 0) { + paths.add(root.resolve(Integer.toString(build))); + } + paths.add(root.resolve("latest")); + } + + private static List bundledJavaCandidates(Path gameDirectory, Path userDataDirectory, String branch) { + LinkedHashSet paths = new LinkedHashSet<>(); + dataRootFromOfficialGameDirectory(gameDirectory).ifPresent(root -> addOfficialJavaFolders(paths, root, branch)); + dataRootFromUserDataDirectory(userDataDirectory).ifPresent(root -> addOfficialJavaFolders(paths, root, branch)); + return List.copyOf(paths); + } + + private static void addOfficialJavaFolders(LinkedHashSet paths, Path hytaleDataRoot, String branch) { + String executable = HytalePlatform.isWindows() ? "java.exe" : "java"; + for (String branchName : branchNames(branch)) { + paths.add(hytaleDataRoot.resolve(Path.of("install", branchName, "package", "jre", "latest", "bin", executable))); + } + paths.add(hytaleDataRoot.resolve(Path.of("jre", "latest", "bin", executable))); + } + + private static List branchNames(String branch) { + String normalized = HytaleApiClient.normalizeBranch(branch); + if ("pre-release".equals(normalized)) { + return List.of("pre-release", "prerelease", "release"); + } + if (!"release".equals(normalized)) { + return List.of(normalized); + } + return List.of("release"); + } + + private static Optional dataRootFromUserDataDirectory(Path userDataDirectory) { + if (userDataDirectory == null || userDataDirectory.getFileName() == null) { + return Optional.empty(); + } + String name = userDataDirectory.getFileName().toString(); + if ("UserData".equalsIgnoreCase(name) || "userdata".equalsIgnoreCase(name)) { + return Optional.ofNullable(userDataDirectory.getParent()); + } + return Optional.empty(); + } + + private static Optional dataRootFromOfficialGameDirectory(Path gameDirectory) { + if (gameDirectory == null) { + return Optional.empty(); + } + Path candidate = gameDirectory.toAbsolutePath().normalize(); + if (candidate.getFileName() != null && !"game".equals(candidate.getFileName().toString())) { + candidate = candidate.getParent(); + } + if (candidate == null || candidate.getFileName() == null || !"game".equals(candidate.getFileName().toString())) { + return Optional.empty(); + } + Path packageDirectory = candidate.getParent(); + if (packageDirectory == null || packageDirectory.getFileName() == null + || !"package".equals(packageDirectory.getFileName().toString())) { + return Optional.empty(); + } + Path branchDirectory = packageDirectory.getParent(); + if (branchDirectory == null) { + return Optional.empty(); + } + Path installDirectory = branchDirectory.getParent(); + if (installDirectory == null || installDirectory.getFileName() == null + || !"install".equals(installDirectory.getFileName().toString())) { + return Optional.empty(); + } + return Optional.ofNullable(installDirectory.getParent()); + } + + public record LaunchPaths( + Path gameDirectory, + Path userDataDirectory, + Path javaExecutable, + Path executable, + Path workingDirectory + ) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameSession.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameSession.java new file mode 100644 index 00000000..bab828d0 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameSession.java @@ -0,0 +1,9 @@ +package net.modtale.launcher.hytale; + +public record HytaleGameSession(String sessionToken, String identityToken) { + + public boolean hasLaunchTokens() { + return sessionToken != null && !sessionToken.isBlank() + && identityToken != null && !identityToken.isBlank(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameVersionResolver.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameVersionResolver.java new file mode 100644 index 00000000..a884bbd6 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleGameVersionResolver.java @@ -0,0 +1,226 @@ +package net.modtale.launcher.hytale; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import net.modtale.launcher.settings.HytalePathDetector; +import net.modtale.launcher.settings.LauncherSettings; + +public final class HytaleGameVersionResolver { + + private static final Pattern LOG_GAME_PROCESS = Pattern.compile("\\bgame_build=(\\d+)\\s+game_version=([^\\s\"]+)"); + private static final Pattern LOG_RELEASE = Pattern.compile("\\{build:(\\d+)\\s+version:([^}]+)}"); + private static final Pattern BUILD_DIRECTORY = Pattern.compile("build-(\\d+)"); + + private HytaleGameVersionResolver() { + } + + public static List labelVersions(LauncherSettings settings, List versions) { + return labelVersions(settings, settings == null ? "release" : settings.getHytaleBranch(), versions); + } + + public static List labelVersions(LauncherSettings settings, String branch, List versions) { + if (versions == null || versions.isEmpty()) { + return List.of(); + } + + Map labels = resolveBuildVersions(settings, branch); + if (labels.isEmpty()) { + return List.copyOf(versions); + } + + return versions.stream() + .map(version -> { + String label = labels.get(version.build()); + return label == null || label.isBlank() ? version : version.withGameVersion(label); + }) + .toList(); + } + + public static Map resolveBuildVersions(LauncherSettings settings) { + return resolveBuildVersions(settings, settings == null ? "release" : settings.getHytaleBranch()); + } + + public static Map resolveBuildVersions(LauncherSettings settings, String branch) { + Map labels = new LinkedHashMap<>(); + hytaleRoots(settings).forEach(root -> readOfficialLauncherLog(root.resolve("hytale-launcher.log"), labels)); + installedBuild(settings, branch).ifPresent(build -> installedServerVersion(settings, branch) + .ifPresent(version -> labels.put(build, version))); + return labels; + } + + public static Optional installedServerVersion(LauncherSettings settings) { + return installedServerVersion(settings, settings == null ? "release" : settings.getHytaleBranch()); + } + + public static Optional installedServerVersion(LauncherSettings settings, String branch) { + if (settings == null) { + return Optional.empty(); + } + return installedGameDirectory(settings, branch) + .flatMap(gameDirectory -> serverVersionFromJar(gameDirectory.resolve(Path.of("Server", "HytaleServer.jar")))); + } + + static Optional serverVersionFromJar(Path jarPath) { + if (jarPath == null || !Files.isRegularFile(jarPath)) { + return Optional.empty(); + } + try (JarFile jar = new JarFile(jarPath.toFile())) { + Manifest manifest = jar.getManifest(); + if (manifest != null) { + String implementationVersion = manifest.getMainAttributes().getValue("Implementation-Version"); + if (implementationVersion != null && !implementationVersion.isBlank()) { + return Optional.of(implementationVersion.trim()); + } + } + } catch (IOException ignored) { + return Optional.empty(); + } + return Optional.empty(); + } + + static void readOfficialLauncherLog(Path logPath, Map labels) { + if (logPath == null || !Files.isRegularFile(logPath)) { + return; + } + try (Stream lines = Files.lines(logPath)) { + lines.forEach(line -> { + Matcher process = LOG_GAME_PROCESS.matcher(line); + while (process.find()) { + labels.put(parseBuild(process.group(1)), process.group(2).trim()); + } + Matcher release = LOG_RELEASE.matcher(line); + while (release.find()) { + labels.put(parseBuild(release.group(1)), release.group(2).trim()); + } + }); + } catch (IOException ignored) { + // Best-effort: the official launcher may be writing this file while we read. + } + } + + static Optional installedBuild(LauncherSettings settings) { + return installedBuild(settings, settings == null ? "release" : settings.getHytaleBranch()); + } + + static Optional installedBuild(LauncherSettings settings, String branch) { + if (settings == null) { + return Optional.empty(); + } + + Path packageDirectory = installedGameDirectory(settings, branch) + .flatMap(HytaleGameVersionResolver::packageDirectory) + .orElse(null); + if (packageDirectory == null) { + return Optional.empty(); + } + Path sigDirectory = packageDirectory.resolve("sig"); + if (!Files.isDirectory(sigDirectory)) { + return Optional.empty(); + } + try (Stream children = Files.list(sigDirectory)) { + return children + .filter(Files::isDirectory) + .map(path -> BUILD_DIRECTORY.matcher(path.getFileName().toString())) + .filter(Matcher::matches) + .map(matcher -> parseBuild(matcher.group(1))) + .max(Integer::compareTo); + } catch (IOException ignored) { + return Optional.empty(); + } + } + + private static Optional installedGameDirectory(LauncherSettings settings, String branch) { + if (settings == null) { + return Optional.empty(); + } + String normalizedBranch = HytaleApiClient.normalizeBranch(branch); + for (Path root : hytaleRoots(settings)) { + for (String branchName : branchDirectoryNames(normalizedBranch)) { + Path gameRoot = root.resolve(Path.of("install", branchName, "package", "game")); + Path latest = gameRoot.resolve("latest"); + if (Files.isDirectory(latest)) { + return Optional.of(latest); + } + if (Files.isDirectory(gameRoot)) { + return Optional.of(gameRoot); + } + } + } + if (normalizedBranch.equals(HytaleApiClient.normalizeBranch(settings.getHytaleBranch())) + && Files.isDirectory(settings.hytaleGameDirectory())) { + return Optional.of(settings.hytaleGameDirectory()); + } + return Optional.empty(); + } + + private static List branchDirectoryNames(String branch) { + String normalized = HytaleApiClient.normalizeBranch(branch); + if ("pre-release".equals(normalized)) { + return List.of("pre-release", "prerelease"); + } + return List.of(normalized); + } + + private static Optional packageDirectory(Path gameDirectory) { + if (gameDirectory == null) { + return Optional.empty(); + } + + Path current = gameDirectory.toAbsolutePath().normalize(); + while (current != null) { + if ("package".equals(current.getFileName() == null ? "" : current.getFileName().toString())) { + return Optional.of(current); + } + current = current.getParent(); + } + return Optional.empty(); + } + + private static List hytaleRoots(LauncherSettings settings) { + List roots = new ArrayList<>(); + if (settings != null) { + dataRootFromPackageDirectory(settings.hytaleGameDirectory()).ifPresent(roots::add); + Path userData = settings.hytaleUserDataDirectory(); + if (userData != null && userData.getParent() != null) { + roots.add(userData.getParent()); + } + } + roots.addAll(HytalePathDetector.hytaleDataDirectoryCandidates()); + return roots.stream().map(path -> path.toAbsolutePath().normalize()).distinct().toList(); + } + + private static Optional dataRootFromPackageDirectory(Path gameDirectory) { + Optional packageDirectory = packageDirectory(gameDirectory); + if (packageDirectory.isEmpty()) { + return Optional.empty(); + } + Path branchDirectory = packageDirectory.get().getParent(); + if (branchDirectory == null) { + return Optional.empty(); + } + Path installDirectory = branchDirectory.getParent(); + if (installDirectory == null) { + return Optional.empty(); + } + return Optional.ofNullable(installDirectory.getParent()); + } + + private static int parseBuild(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException ex) { + return 0; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleLaunchResult.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleLaunchResult.java new file mode 100644 index 00000000..7a4485eb --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleLaunchResult.java @@ -0,0 +1,6 @@ +package net.modtale.launcher.hytale; + +import java.nio.file.Path; + +public record HytaleLaunchResult(Process process, Path executable, String username, String uuid) { +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytalePlatform.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytalePlatform.java new file mode 100644 index 00000000..0d934ab1 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytalePlatform.java @@ -0,0 +1,36 @@ +package net.modtale.launcher.hytale; + +import java.util.Locale; + +public final class HytalePlatform { + + private HytalePlatform() { + } + + public static String os() { + String osName = System.getProperty("os.name", "").toLowerCase(Locale.ROOT); + if (osName.contains("win")) { + return "windows"; + } + if (osName.contains("mac") || osName.contains("darwin")) { + return "darwin"; + } + return "linux"; + } + + public static String arch() { + String arch = System.getProperty("os.arch", "").toLowerCase(Locale.ROOT); + if (arch.contains("aarch64") || arch.contains("arm64")) { + return "arm64"; + } + return "amd64"; + } + + public static boolean isWindows() { + return "windows".equals(os()); + } + + public static boolean isMac() { + return "darwin".equals(os()); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleProfile.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleProfile.java new file mode 100644 index 00000000..8d47ace2 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleProfile.java @@ -0,0 +1,24 @@ +package net.modtale.launcher.hytale; + +public record HytaleProfile(String username, String uuid, String owner, long playtimeSeconds) { + + public HytaleProfile(String username, String uuid, String owner) { + this(username, uuid, owner, 0); + } + + public HytaleProfile { + username = username == null ? "" : username; + uuid = uuid == null ? "" : uuid; + owner = owner == null ? "" : owner; + playtimeSeconds = Math.max(0, playtimeSeconds); + } + + public String displayName() { + return username.isBlank() ? "Hytale profile" : username; + } + + @Override + public String toString() { + return displayName(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleVersion.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleVersion.java new file mode 100644 index 00000000..3c52cee3 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleVersion.java @@ -0,0 +1,45 @@ +package net.modtale.launcher.hytale; + +public record HytaleVersion( + String branch, + int build, + int fromBuild, + boolean latest, + String gameVersion, + String pwrUrl, + String pwrHeadUrl, + String sigUrl +) { + + public HytaleVersion( + String branch, + int build, + int fromBuild, + boolean latest, + String pwrUrl, + String pwrHeadUrl, + String sigUrl + ) { + this(branch, build, fromBuild, latest, "", pwrUrl, pwrHeadUrl, sigUrl); + } + + public HytaleVersion withGameVersion(String gameVersion) { + return new HytaleVersion(branch, build, fromBuild, latest, gameVersion, pwrUrl, pwrHeadUrl, sigUrl); + } + + public String displayVersion() { + if (gameVersion != null && !gameVersion.isBlank()) { + return gameVersion; + } + return "Build " + build; + } + + @Override + public String toString() { + String suffix = latest ? " (latest)" : ""; + if (gameVersion != null && !gameVersion.isBlank()) { + return gameVersion + " - Build " + build + suffix; + } + return displayVersion() + suffix; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/hytale/HytaleWorldManager.java b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleWorldManager.java new file mode 100644 index 00000000..4067fc2f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/hytale/HytaleWorldManager.java @@ -0,0 +1,378 @@ +package net.modtale.launcher.hytale; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Comparator; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import net.modtale.launcher.api.ModtaleApiException; +import net.modtale.launcher.settings.HytalePathDetector; +import net.modtale.launcher.settings.LauncherSettings; + +public final class HytaleWorldManager { + + private static final ObjectMapper MAPPER = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT); + + public List loadWorlds(LauncherSettings settings) { + Path savesDirectory = savesDirectory(settings); + if (!Files.isDirectory(savesDirectory)) { + return List.of(); + } + try (var stream = Files.list(savesDirectory)) { + return stream + .filter(Files::isDirectory) + .map(this::worldFromDirectory) + .sorted(Comparator.comparing(HytaleWorld::name, String.CASE_INSENSITIVE_ORDER)) + .toList(); + } catch (IOException ex) { + throw new ModtaleApiException("Could not read Hytale worlds from " + savesDirectory, ex); + } + } + + public HytaleWorldConfig loadConfig(Path configPath) { + ObjectNode root = readConfigRoot(configPath); + JsonNode mods = root.get("Mods"); + Map enabledByMod = new LinkedHashMap<>(); + if (mods != null && mods.isObject()) { + mods.fields().forEachRemaining(entry -> { + JsonNode enabled = entry.getValue().get("Enabled"); + enabledByMod.put(entry.getKey(), enabled != null && enabled.asBoolean(false)); + }); + } + return new HytaleWorldConfig(configPath, enabledByMod); + } + + public void setModEnabled(Path configPath, String modId, boolean enabled) { + setModsEnabled(configPath, List.of(modId), enabled); + } + + public void setModsEnabled(Path configPath, Collection modIds, boolean enabled) { + if (configPath == null || modIds == null || modIds.isEmpty()) { + return; + } + ObjectNode root = readConfigRoot(configPath); + ObjectNode mods = objectNode(root, "Mods"); + for (String modId : modIds) { + if (modId == null || modId.isBlank()) { + continue; + } + ObjectNode mod = objectNode(mods, modId.trim()); + mod.put("Enabled", enabled); + } + try { + Files.createDirectories(configPath.getParent()); + MAPPER.writeValue(configPath.toFile(), root); + } catch (IOException ex) { + throw new ModtaleApiException("Could not update Hytale world config " + configPath, ex); + } + } + + public List loadInstalledMods(LauncherSettings settings) { + Path modsDirectory = modsDirectory(settings); + if (!Files.isDirectory(modsDirectory)) { + return List.of(); + } + try (var stream = Files.list(modsDirectory)) { + return stream + .filter(Files::isRegularFile) + .filter(HytaleWorldManager::isJar) + .map(this::installedModFromJar) + .sorted(Comparator.comparing(HytaleInstalledMod::name, String.CASE_INSENSITIVE_ORDER)) + .toList(); + } catch (IOException ex) { + throw new ModtaleApiException("Could not read Hytale mods from " + modsDirectory, ex); + } + } + + public Path savesDirectory(LauncherSettings settings) { + Path configured = settings.hytaleUserDataDirectory().resolve("Saves"); + if (Files.isDirectory(configured)) { + return configured; + } + return HytalePathDetector.detectExistingSavesDirectory().orElse(configured); + } + + public Path modsDirectory(LauncherSettings settings) { + Path paired = pairedModsDirectory(settings); + if (paired != null && Files.isDirectory(paired)) { + return paired; + } + Path configured = settings.hytaleModsDirectory(); + if (Files.isDirectory(configured)) { + return configured; + } + return HytalePathDetector.detectExistingModsDirectory().orElse(configured); + } + + private Path pairedModsDirectory(LauncherSettings settings) { + Path savesDirectory = savesDirectory(settings); + Path userDataDirectory = savesDirectory.getParent(); + return userDataDirectory == null ? null : userDataDirectory.resolve("Mods"); + } + + private HytaleWorld worldFromDirectory(Path directory) { + Path configPath = directory.resolve("config.json"); + HytaleWorldConfig config = loadConfig(configPath); + HytaleWorldMetadata metadata = readMetadata(directory); + long enabledMods = config.enabledByMod().values().stream().filter(Boolean::booleanValue).count(); + return new HytaleWorld( + directory.toAbsolutePath().normalize(), + directory.getFileName() == null ? directory.toString() : directory.getFileName().toString(), + configPath.toAbsolutePath().normalize(), + metadata.patchline(), + metadata.previewImage(), + (int) enabledMods, + config.enabledByMod().size(), + lastModified(directory, configPath) + ); + } + + private HytaleWorldMetadata readMetadata(Path directory) { + Path metadata = directory.resolve("client_metadata.json"); + JsonNode root = null; + if (!Files.isRegularFile(metadata)) { + return new HytaleWorldMetadata("", previewImage(directory, null)); + } + try { + root = MAPPER.readTree(metadata.toFile()); + return new HytaleWorldMetadata( + root.path("CreatedWithPatchline").asText(""), + previewImage(directory, root) + ); + } catch (IOException ignored) { + return new HytaleWorldMetadata("", previewImage(directory, root)); + } + } + + private String previewImage(Path directory, JsonNode metadata) { + String fromMetadata = previewImageFromMetadata(directory, metadata); + if (!fromMetadata.isBlank()) { + return fromMetadata; + } + for (String filename : List.of( + "preview.png", + "preview.jpg", + "preview.jpeg", + "preview.webp", + "thumbnail.png", + "thumbnail.jpg", + "screenshot.png", + "screenshot.jpg" + )) { + Path candidate = directory.resolve(filename); + if (Files.isRegularFile(candidate)) { + return candidate.toAbsolutePath().normalize().toUri().toString(); + } + } + return ""; + } + + private String previewImageFromMetadata(Path directory, JsonNode metadata) { + if (metadata == null || metadata.isMissingNode() || metadata.isNull()) { + return ""; + } + Deque nodes = new ArrayDeque<>(); + nodes.add(metadata); + while (!nodes.isEmpty()) { + JsonNode node = nodes.removeFirst(); + if (node == null || node.isNull() || node.isMissingNode()) { + continue; + } + if (node.isObject()) { + Iterator> fields = node.fields(); + while (fields.hasNext()) { + Map.Entry field = fields.next(); + if (isPreviewField(field.getKey())) { + String resolved = resolveImageValue(directory, field.getValue().asText("")); + if (!resolved.isBlank()) { + return resolved; + } + } + nodes.addLast(field.getValue()); + } + } else if (node.isArray()) { + node.forEach(nodes::addLast); + } + } + return ""; + } + + private boolean isPreviewField(String field) { + if (field == null || field.isBlank()) { + return false; + } + String normalized = field.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]+", ""); + return List.of( + "preview", + "previewimage", + "previewimagepath", + "previewpath", + "thumbnail", + "thumbnailimage", + "thumbnailimagepath", + "thumbnailpath", + "screenshot", + "screenshotimage", + "screenshotpath", + "image", + "imagepath" + ).contains(normalized); + } + + private String resolveImageValue(Path directory, String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim(); + if (normalized.startsWith("http://") + || normalized.startsWith("https://") + || normalized.startsWith("file:") + || normalized.startsWith("data:")) { + return normalized; + } + try { + Path path = Path.of(normalized); + if (!path.isAbsolute()) { + path = directory.resolve(path); + } + path = path.toAbsolutePath().normalize(); + return Files.isRegularFile(path) ? path.toUri().toString() : ""; + } catch (IllegalArgumentException ignored) { + try { + URI uri = URI.create(normalized); + return uri.isAbsolute() ? normalized : ""; + } catch (IllegalArgumentException ignoredAgain) { + return ""; + } + } + } + + private Instant lastModified(Path directory, Path configPath) { + try { + Instant directoryTime = Files.getLastModifiedTime(directory).toInstant(); + if (!Files.exists(configPath)) { + return directoryTime; + } + Instant configTime = Files.getLastModifiedTime(configPath).toInstant(); + return configTime.isAfter(directoryTime) ? configTime : directoryTime; + } catch (IOException ignored) { + return Instant.EPOCH; + } + } + + private HytaleInstalledMod installedModFromJar(Path jar) { + String fallbackName = jar.getFileName() == null ? jar.toString() : jar.getFileName().toString(); + String baseName = fallbackName.replaceFirst("(?i)\\.jar$", ""); + try (ZipFile zip = new ZipFile(jar.toFile())) { + ZipEntry manifest = zip.getEntry("manifest.json"); + if (manifest == null) { + return new HytaleInstalledMod(baseName, baseName, "", "", jar.toAbsolutePath().normalize()); + } + try (InputStream input = zip.getInputStream(manifest)) { + JsonNode root = MAPPER.readTree(input); + String group = root.path("Group").asText(""); + String name = root.path("Name").asText(baseName); + String id = group.isBlank() || name.isBlank() ? baseName : group + ":" + name; + return new HytaleInstalledMod( + id, + name.isBlank() ? baseName : name, + root.path("Version").asText(""), + root.path("Description").asText(""), + jar.toAbsolutePath().normalize() + ); + } + } catch (IOException ex) { + return new HytaleInstalledMod(baseName, baseName, "", "", jar.toAbsolutePath().normalize()); + } + } + + private ObjectNode readConfigRoot(Path configPath) { + if (configPath == null || !Files.exists(configPath)) { + ObjectNode root = MAPPER.createObjectNode(); + root.put("Version", 4); + root.set("Mods", MAPPER.createObjectNode()); + return root; + } + try { + JsonNode root = MAPPER.readTree(configPath.toFile()); + if (root instanceof ObjectNode objectNode) { + return objectNode; + } + } catch (IOException ex) { + throw new ModtaleApiException("Could not read Hytale world config " + configPath, ex); + } + ObjectNode replacement = MAPPER.createObjectNode(); + replacement.put("Version", 4); + replacement.set("Mods", MAPPER.createObjectNode()); + return replacement; + } + + private static ObjectNode objectNode(ObjectNode parent, String field) { + JsonNode existing = parent.get(field); + if (existing instanceof ObjectNode objectNode) { + return objectNode; + } + ObjectNode replacement = MAPPER.createObjectNode(); + parent.set(field, replacement); + return replacement; + } + + private static boolean isJar(Path path) { + String name = path.getFileName() == null ? "" : path.getFileName().toString().toLowerCase(Locale.ROOT); + return name.endsWith(".jar"); + } + + public record HytaleWorld( + Path directory, + String name, + Path configPath, + String patchline, + String previewImage, + int enabledMods, + int totalMods, + Instant updatedAt + ) { + public HytaleWorld { + previewImage = previewImage == null ? "" : previewImage.trim(); + } + } + + private record HytaleWorldMetadata(String patchline, String previewImage) { + private HytaleWorldMetadata { + patchline = patchline == null ? "" : patchline.trim(); + previewImage = previewImage == null ? "" : previewImage.trim(); + } + } + + public record HytaleWorldConfig(Path configPath, Map enabledByMod) { + public HytaleWorldConfig { + enabledByMod = enabledByMod == null ? Map.of() : Map.copyOf(enabledByMod); + } + } + + public record HytaleInstalledMod( + String id, + String name, + String version, + String description, + Path file + ) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/install/ArchiveInstaller.java b/launcher/src/main/java/net/modtale/launcher/install/ArchiveInstaller.java new file mode 100644 index 00000000..2805d1b0 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/install/ArchiveInstaller.java @@ -0,0 +1,172 @@ +package net.modtale.launcher.install; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class ArchiveInstaller { + + public List installDownloadedFile(Path downloadedFile, String filename, Path modsDirectory, boolean unpackArchive) + throws IOException { + Files.createDirectories(modsDirectory); + if (unpackArchive) { + return extractInstallableEntries(downloadedFile, modsDirectory); + } + Path destination = uniqueDestination(modsDirectory, safeFilename(filename)); + Files.copy(downloadedFile, destination, StandardCopyOption.REPLACE_EXISTING); + return List.of(destination); + } + + public List installModpackArchive(Path archive, Path modsDirectory) throws IOException { + Files.createDirectories(modsDirectory); + Path stagingDirectory = Files.createTempDirectory("modtale-modpack-"); + try { + Path extractedDirectory = stagingDirectory.resolve("extracted"); + Files.createDirectories(extractedDirectory); + extractArchive(archive, extractedDirectory); + + Path contentRoot = modpackContentRoot(extractedDirectory); + List installed = new ArrayList<>(); + try (Stream files = Files.walk(contentRoot)) { + for (Path source : files + .filter(Files::isRegularFile) + .sorted(Comparator.comparing(Path::toString)) + .toList()) { + Path destination = uniqueDestination(modsDirectory, safeFilename(source.getFileName().toString())); + Files.move(source, destination, StandardCopyOption.REPLACE_EXISTING); + installed.add(destination); + } + } + return installed; + } finally { + deleteRecursively(stagingDirectory); + } + } + + public List extractInstallableEntries(Path archive, Path modsDirectory) throws IOException { + Files.createDirectories(modsDirectory); + List installed = new ArrayList<>(); + try (InputStream input = Files.newInputStream(archive); + ZipInputStream zip = new ZipInputStream(input)) { + ZipEntry entry; + while ((entry = zip.getNextEntry()) != null) { + if (entry.isDirectory() || !isInstallable(entry.getName())) { + continue; + } + Path destination = resolveSafeDestination(modsDirectory, entry.getName()); + Files.createDirectories(destination.getParent()); + Files.copy(zip, destination, StandardCopyOption.REPLACE_EXISTING); + installed.add(destination); + } + } + return installed; + } + + private static void extractArchive(Path archive, Path extractionRoot) throws IOException { + try (InputStream input = Files.newInputStream(archive); + ZipInputStream zip = new ZipInputStream(input)) { + ZipEntry entry; + while ((entry = zip.getNextEntry()) != null) { + Path destination = resolveExtractionDestination(extractionRoot, entry.getName()); + if (entry.isDirectory()) { + Files.createDirectories(destination); + continue; + } + Files.createDirectories(destination.getParent()); + Files.copy(zip, destination, StandardCopyOption.REPLACE_EXISTING); + } + } + } + + private static Path modpackContentRoot(Path extractedDirectory) throws IOException { + try (Stream children = Files.list(extractedDirectory)) { + List entries = children + .filter(path -> !isArchiveMetadataDirectory(path)) + .toList(); + if (entries.size() == 1 && Files.isDirectory(entries.getFirst())) { + return entries.getFirst(); + } + } + return extractedDirectory; + } + + private static boolean isInstallable(String entryName) { + String filename = Path.of(entryName).getFileName().toString(); + String lower = filename.toLowerCase(Locale.ROOT); + return lower.endsWith(".jar") || lower.endsWith(".zip") || lower.endsWith(".hmasset") || lower.endsWith(".hymod"); + } + + private static Path resolveSafeDestination(Path modsDirectory, String entryName) throws IOException { + String filename = safeFilename(Path.of(entryName).getFileName().toString()); + Path destination = uniqueDestination(modsDirectory, filename); + Path normalizedTarget = destination.normalize(); + Path normalizedRoot = modsDirectory.toRealPath().normalize(); + if (!normalizedTarget.toAbsolutePath().normalize().startsWith(normalizedRoot.toAbsolutePath())) { + throw new IOException("Archive entry escapes the target mods directory: " + entryName); + } + return destination; + } + + private static Path resolveExtractionDestination(Path extractionRoot, String entryName) throws IOException { + Path destination = extractionRoot.resolve(entryName).normalize(); + Path normalizedRoot = extractionRoot.toAbsolutePath().normalize(); + if (!destination.toAbsolutePath().normalize().startsWith(normalizedRoot)) { + throw new IOException("Archive entry escapes the extraction directory: " + entryName); + } + return destination; + } + + private static Path uniqueDestination(Path modsDirectory, String filename) { + Path candidate = modsDirectory.resolve(filename); + if (!Files.exists(candidate)) { + return candidate; + } + int extensionStart = filename.lastIndexOf('.'); + String base = extensionStart > 0 ? filename.substring(0, extensionStart) : filename; + String extension = extensionStart > 0 ? filename.substring(extensionStart) : ""; + int counter = 2; + while (true) { + Path next = modsDirectory.resolve(base + "-" + counter + extension); + if (!Files.exists(next)) { + return next; + } + counter++; + } + } + + private static boolean isArchiveMetadataDirectory(Path path) { + return Files.isDirectory(path) && "__MACOSX".equals(path.getFileName().toString()); + } + + private static void deleteRecursively(Path directory) throws IOException { + if (directory == null || Files.notExists(directory)) { + return; + } + try (Stream paths = Files.walk(directory)) { + List cleanup = paths + .sorted(Comparator.reverseOrder()) + .toList(); + for (Path path : cleanup) { + Files.deleteIfExists(path); + } + } + } + + static String safeFilename(String filename) { + String base = filename == null || filename.isBlank() ? "modtale-download.jar" : Path.of(filename).getFileName().toString(); + String sanitized = base.replaceAll("[^A-Za-z0-9._-]+", "-") + .replaceAll("-+", "-") + .replaceAll("-+\\.", ".") + .replaceAll("(^-|-$)", ""); + return sanitized.isBlank() ? "modtale-download.jar" : sanitized; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/install/ModInstaller.java b/launcher/src/main/java/net/modtale/launcher/install/ModInstaller.java new file mode 100644 index 00000000..b84cbe0d --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/install/ModInstaller.java @@ -0,0 +1,392 @@ +package net.modtale.launcher.install; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import net.modtale.launcher.api.ModtaleApiClient.DownloadedFile; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.api.ModtaleApiException; +import net.modtale.launcher.model.install.InstallOptions; +import net.modtale.launcher.model.install.InstallResult; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; +import net.modtale.launcher.model.project.DownloadUrlResponse; +import net.modtale.launcher.model.project.ProjectClassification; +import net.modtale.launcher.model.project.ProjectDependency; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.model.project.VersionDependenciesView; +import net.modtale.launcher.settings.LauncherSettings; +import net.modtale.launcher.settings.SettingsStore; + +public class ModInstaller { + + private final ModtaleApiClient apiClient; + private final SettingsStore settingsStore; + private final ArchiveInstaller archiveInstaller; + + public ModInstaller(ModtaleApiClient apiClient, SettingsStore settingsStore) { + this(apiClient, settingsStore, new ArchiveInstaller()); + } + + ModInstaller(ModtaleApiClient apiClient, SettingsStore settingsStore, ArchiveInstaller archiveInstaller) { + this.apiClient = apiClient; + this.settingsStore = settingsStore; + this.archiveInstaller = archiveInstaller; + } + + public InstallResult installLatest(ProjectDetail project, LauncherSettings settings) { + ProjectVersion version = VersionSelector.latestCompatible(project, settings.getGameVersion()) + .orElseThrow(() -> new ModtaleApiException("No compatible version was found for " + project.title())); + return install(project, version, optionsFrom(settings)); + } + + public InstallResult install(ProjectDetail project, ProjectVersion version, InstallOptions options) { + if (project == null || version == null) { + throw new ModtaleApiException("Select a project and version before installing."); + } + try { + Files.createDirectories(options.modsDirectory()); + } catch (IOException ex) { + throw new ModtaleApiException("Could not create Hytale mods directory " + options.modsDirectory(), ex); + } + + List dependencies = dependencies(project, version, options); + boolean exactDependencySelection = options.hasSelectedDependencies(); + boolean includeOptional = exactDependencySelection || options.includeOptionalDependencies(); + List selectedModtaleDependencies = selectedModtaleDependencies(dependencies, includeOptional); + List selectedExternalDependencies = selectedExternalDependencies(dependencies, includeOptional); + boolean hasDependencySelection = exactDependencySelection + ? !dependencies.isEmpty() + : options.includeDependencies(); + boolean isBundle = hasDependencySelection && !selectedModtaleDependencies.isEmpty(); + boolean isModpack = ProjectClassification.isModpack(project.classification()); + List selectedReferences = selectedDependencyReferences(dependencies, includeOptional); + + List installedFiles = new ArrayList<>(); + List warnings = new ArrayList<>(); + List externalNames = new ArrayList<>(); + + DownloadUrlResponse downloadUrl = isBundle + ? apiClient.getBundleDownloadUrl(project.id(), version.versionNumber(), selectedModtaleDependencies, options.gameVersion()) + : apiClient.getDownloadUrl(project.id(), version.versionNumber(), options.gameVersion()); + + DownloadedFile mainDownload = apiClient.download(downloadUrl.downloadUrl()); + boolean unpackMainDownload = isBundle || looksLikeGeneratedArchive(mainDownload); + try { + if (isModpack || isBundle) { + installedFiles.addAll(archiveInstaller.installModpackArchive(mainDownload.path(), options.modsDirectory())); + } else { + installedFiles.addAll(archiveInstaller.installDownloadedFile( + mainDownload.path(), + mainDownload.filename(), + options.modsDirectory(), + unpackMainDownload + )); + } + } catch (IOException ex) { + throw new ModtaleApiException("Could not install " + project.title() + " into " + options.modsDirectory(), ex); + } finally { + deleteTemp(mainDownload.path()); + } + + for (ProjectDependency dependency : selectedExternalDependencies) { + if (dependency.externalFileUrl() == null || dependency.externalFileUrl().isBlank()) { + warnings.add("External dependency needs manual install: " + displayName(dependency)); + continue; + } + DownloadedFile externalDownload = apiClient.download(dependency.externalFileUrl()); + try { + String filename = dependency.externalFileName() == null || dependency.externalFileName().isBlank() + ? externalDownload.filename() + : dependency.externalFileName(); + installedFiles.addAll(archiveInstaller.installDownloadedFile( + externalDownload.path(), + filename, + options.modsDirectory(), + false + )); + externalNames.add(displayName(dependency)); + } catch (IOException ex) { + warnings.add("External dependency failed: " + displayName(dependency) + " (" + ex.getMessage() + ")"); + } finally { + deleteTemp(externalDownload.path()); + } + } + + InstalledProject installedProject = new InstalledProject( + project.id(), + project.slug(), + project.title(), + project.classification(), + version.versionNumber(), + version.id(), + options.gameVersion(), + Instant.now(), + Instant.now(), + installedFiles.stream().map(Path::toString).toList(), + selectedModtaleDependencies, + externalNames, + InstalledProject.SOURCE_MODTALE, + isModpack ? InstalledProject.INSTALL_MODPACK : isBundle ? InstalledProject.INSTALL_BUNDLE : InstalledProject.INSTALL_DIRECT, + false, + selectedReferences + ); + return new InstallResult(installedProject, installedFiles, warnings); + } + + public InstallResult installAndRecord(ProjectDetail project, LauncherSettings settings) { + ProjectVersion version = VersionSelector.latestCompatible(project, settings.getGameVersion()) + .orElseThrow(() -> new ModtaleApiException("No compatible version was found for " + project.title())); + InstalledProject previous = removePreviousInstall(project.id(), settings); + InstallResult result = install(project, version, optionsFrom(settings)); + return recordInstall(result, settings, previous); + } + + public InstallResult installAndRecord(ProjectDetail project, ProjectVersion version, LauncherSettings settings, String gameVersion) { + InstalledProject previous = removePreviousInstall(project.id(), settings); + InstallResult result = install(project, version, new InstallOptions( + settings.hytaleModsDirectory(), + gameVersion == null || gameVersion.isBlank() ? settings.getGameVersion() : gameVersion, + settings.isIncludeDependencies(), + settings.isIncludeOptionalDependencies() + )); + return recordInstall(result, settings, previous); + } + + public InstallResult installAndRecord( + ProjectDetail project, + ProjectVersion version, + LauncherSettings settings, + String gameVersion, + List selectedDependencies + ) { + InstalledProject previous = removePreviousInstall(project.id(), settings); + List dependencies = selectedDependencies == null ? null : List.copyOf(selectedDependencies); + InstallResult result = install(project, version, new InstallOptions( + settings.hytaleModsDirectory(), + gameVersion == null || gameVersion.isBlank() ? settings.getGameVersion() : gameVersion, + dependencies != null && !dependencies.isEmpty(), + true, + dependencies + )); + return recordInstall(result, settings, previous); + } + + public InstallResult updateAndRecord(ProjectDetail project, ProjectVersion version, LauncherSettings settings) { + InstalledProject previous = existingInstall(project.id(), settings).orElse(null); + removePreviousInstall(project.id(), settings); + InstallResult result = install(project, version, previous == null ? optionsFrom(settings) : optionsFrom(settings, previous)); + return recordInstall(result, settings, previous); + } + + public InstallResult switchVersionAndRecord( + InstalledProject installed, + ProjectDetail project, + ProjectVersion version, + LauncherSettings settings + ) { + return switchVersionAndRecord(installed, project, version, settings, ""); + } + + public InstallResult switchVersionAndRecord( + InstalledProject installed, + ProjectDetail project, + ProjectVersion version, + LauncherSettings settings, + String gameVersion + ) { + if (installed == null) { + return updateAndRecord(project, version, settings); + } + removePreviousInstall(installed.projectId(), settings); + InstallResult result = install(project, version, optionsFrom(settings, installed, gameVersion)); + return recordInstall(result, settings, installed); + } + + public void uninstallAndRecord(InstalledProject installed, LauncherSettings settings) { + if (installed == null || settings == null) { + return; + } + deleteRecordedFiles(installed); + settings.removeInstalledProject(installed.projectId()); + settingsStore.removeInstalledProject(installed.projectId()); + settingsStore.save(settings); + } + + private InstallResult recordInstall(InstallResult result, LauncherSettings settings, InstalledProject previous) { + InstalledProject recorded = mergeInstallMetadata(result.installedProject(), previous); + settings.upsertInstalledProject(recorded); + settingsStore.save(settings); + return new InstallResult(recorded, result.installedFiles(), result.warnings()); + } + + private InstalledProject mergeInstallMetadata(InstalledProject fresh, InstalledProject previous) { + if (previous == null) { + return fresh; + } + boolean unlocked = previous.modpackUnlocked() && (fresh.isModpack() || !fresh.bundledProjects().isEmpty()); + return new InstalledProject( + fresh.projectId(), + fresh.slug(), + fresh.title(), + fresh.classification(), + fresh.installedVersion(), + fresh.installedVersionId(), + fresh.gameVersion(), + previous.installedAt(), + fresh.updatedAt(), + fresh.files(), + fresh.dependencyProjectIds(), + fresh.externalDependencies(), + fresh.source(), + fresh.installType(), + unlocked, + fresh.bundledProjects() + ); + } + + private Optional existingInstall(String projectId, LauncherSettings settings) { + if (projectId == null || settings == null) { + return Optional.empty(); + } + return settings.getInstalledProjects().stream() + .filter(installed -> projectId.equals(installed.projectId())) + .findFirst(); + } + + private InstalledProject removePreviousInstall(String projectId, LauncherSettings settings) { + InstalledProject previous = existingInstall(projectId, settings).orElse(null); + if (previous != null) { + deleteRecordedFiles(previous); + } + return previous; + } + + private static void deleteRecordedFiles(InstalledProject installed) { + installed.files().forEach(file -> { + try { + Files.deleteIfExists(Path.of(file)); + } catch (IOException ignored) { + // Stale files should not block an update; the new install can still succeed. + } + }); + } + + private static InstallOptions optionsFrom(LauncherSettings settings) { + return new InstallOptions( + settings.hytaleModsDirectory(), + settings.getGameVersion(), + settings.isIncludeDependencies(), + settings.isIncludeOptionalDependencies() + ); + } + + private static InstallOptions optionsFrom(LauncherSettings settings, InstalledProject installed) { + return optionsFrom(settings, installed, ""); + } + + private static InstallOptions optionsFrom(LauncherSettings settings, InstalledProject installed, String selectedGameVersion) { + String gameVersion = selectedGameVersion == null || selectedGameVersion.isBlank() + ? installed.gameVersion() + : selectedGameVersion.trim(); + if (gameVersion == null || gameVersion.isBlank()) { + gameVersion = settings.getGameVersion(); + } + if (!installed.bundledProjects().isEmpty()) { + return new InstallOptions( + settings.hytaleModsDirectory(), + gameVersion, + true, + true, + installed.bundledProjects().stream() + .map(InstalledProjectReference::toDependency) + .toList() + ); + } + return new InstallOptions( + settings.hytaleModsDirectory(), + gameVersion, + settings.isIncludeDependencies(), + settings.isIncludeOptionalDependencies() + ); + } + + private List dependencies(ProjectDetail project, ProjectVersion version, InstallOptions options) { + if (options.hasSelectedDependencies()) { + return options.selectedDependencies(); + } + VersionDependenciesView dependenciesView = options.includeDependencies() + ? apiClient.getDependencies(project.id(), version.versionNumber(), options.gameVersion()) + : new VersionDependenciesView(List.of()); + return dependenciesView.dependencies(); + } + + private static List selectedDependencyReferences( + List dependencies, + boolean includeOptional + ) { + return dependencies.stream() + .filter(dependency -> !dependency.isEmbedded()) + .filter(dependency -> includeOptional || !dependency.isOptional()) + .map(InstalledProjectReference::fromDependency) + .toList(); + } + + private static List selectedModtaleDependencies(List dependencies, boolean includeOptional) { + Set ids = new LinkedHashSet<>(); + for (ProjectDependency dependency : dependencies) { + if (dependency.isExternal() || dependency.isEmbedded() || dependency.projectId() == null || dependency.projectId().isBlank()) { + continue; + } + if (dependency.isOptional() && !includeOptional) { + continue; + } + ids.add(dependency.projectId()); + } + return List.copyOf(ids); + } + + private static List selectedExternalDependencies(List dependencies, boolean includeOptional) { + return dependencies.stream() + .filter(ProjectDependency::isExternal) + .filter(dependency -> !dependency.isEmbedded()) + .filter(dependency -> includeOptional || !dependency.isOptional()) + .toList(); + } + + private static boolean looksLikeGeneratedArchive(DownloadedFile file) { + String lowerName = file.filename() == null ? "" : file.filename().toLowerCase(java.util.Locale.ROOT); + String lowerType = file.contentType() == null ? "" : file.contentType().toLowerCase(java.util.Locale.ROOT); + return lowerName.endsWith("-unzip-me.zip") + || lowerName.contains("modpack") + || lowerType.contains("application/zip"); + } + + private static void deleteTemp(Path path) { + try { + Files.deleteIfExists(path); + } catch (IOException ignored) { + // Temporary download cleanup is best-effort. + } + } + + private static String displayName(ProjectDependency dependency) { + if (dependency.projectTitle() != null && !dependency.projectTitle().isBlank()) { + return dependency.projectTitle(); + } + if (dependency.title() != null && !dependency.title().isBlank()) { + return dependency.title(); + } + if (dependency.externalId() != null && !dependency.externalId().isBlank()) { + return dependency.source() + ":" + dependency.externalId(); + } + return dependency.id() == null ? "external dependency" : dependency.id(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/install/UpdateService.java b/launcher/src/main/java/net/modtale/launcher/install/UpdateService.java new file mode 100644 index 00000000..23bf24c0 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/install/UpdateService.java @@ -0,0 +1,75 @@ +package net.modtale.launcher.install; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.UpdateCandidate; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.settings.LauncherSettings; + +public class UpdateService { + + private final ModtaleApiClient apiClient; + + public UpdateService(ModtaleApiClient apiClient) { + this.apiClient = apiClient; + } + + public List checkForUpdates(LauncherSettings settings) { + List updates = new ArrayList<>(); + for (InstalledProject installed : settings.getInstalledProjects()) { + checkForUpdate(settings, installed).ifPresent(updates::add); + } + return updates; + } + + public Optional checkForUpdate(LauncherSettings settings, InstalledProject installed) { + if (installed == null || !isModtaleProject(installed)) { + return Optional.empty(); + } + ProjectDetail project = projectWithVersions(routeKey(installed)); + ProjectVersion newest = VersionSelector.latestCompatible(project, effectiveGameVersion(settings, installed)).orElse(null); + if (newest == null || sameVersion(installed, newest)) { + return Optional.empty(); + } + return Optional.of(new UpdateCandidate(installed, project, newest)); + } + + public ProjectDetail projectWithVersions(String routeKey) { + ProjectDetail project = apiClient.getProject(routeKey); + if (project.versions().isEmpty()) { + project = project.withVersions(apiClient.getProjectVersions(project.routeKey())); + } + return project; + } + + private static String routeKey(InstalledProject installed) { + return installed.slug() != null && !installed.slug().isBlank() ? installed.slug() : installed.projectId(); + } + + private static boolean isModtaleProject(InstalledProject installed) { + String source = installed.source() == null ? "" : installed.source().trim(); + return source.isBlank() || InstalledProject.SOURCE_MODTALE.equalsIgnoreCase(source); + } + + private static String effectiveGameVersion(LauncherSettings settings, InstalledProject installed) { + if (installed.gameVersion() != null && !installed.gameVersion().isBlank()) { + return installed.gameVersion(); + } + return settings.getGameVersion(); + } + + public static boolean sameVersion(InstalledProject installed, ProjectVersion version) { + if (hasText(installed.installedVersionId()) && hasText(version.id())) { + return installed.installedVersionId().equals(version.id()); + } + return hasText(installed.installedVersion()) && installed.installedVersion().equals(version.versionNumber()); + } + + private static boolean hasText(String value) { + return value != null && !value.isBlank(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/install/VersionSelector.java b/launcher/src/main/java/net/modtale/launcher/install/VersionSelector.java new file mode 100644 index 00000000..d6a208c7 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/install/VersionSelector.java @@ -0,0 +1,59 @@ +package net.modtale.launcher.install; + +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectVersion; + +public final class VersionSelector { + + private VersionSelector() { + } + + public static Optional latestCompatible(ProjectDetail project, String gameVersion) { + if (project == null) { + return Optional.empty(); + } + return latestCompatible(project.versions(), gameVersion); + } + + public static Optional latestCompatible(List versions, String gameVersion) { + if (versions == null || versions.isEmpty()) { + return Optional.empty(); + } + return versions.stream() + .filter(version -> version.supportsGameVersion(gameVersion)) + .max(Comparator + .comparingInt(VersionSelector::channelRank) + .thenComparing(VersionSelector::releaseInstant, Comparator.nullsFirst(Comparator.naturalOrder())) + .thenComparing(ProjectVersion::versionNumber, Comparator.nullsFirst(Comparator.naturalOrder()))); + } + + private static int channelRank(ProjectVersion version) { + String channel = version.channel(); + if (channel == null || channel.isBlank() || "RELEASE".equalsIgnoreCase(channel)) { + return 3; + } + if ("BETA".equalsIgnoreCase(channel)) { + return 2; + } + if ("ALPHA".equalsIgnoreCase(channel)) { + return 1; + } + return 0; + } + + private static Instant releaseInstant(ProjectVersion version) { + if (version.releaseDate() == null || version.releaseDate().isBlank()) { + return null; + } + try { + return Instant.parse(version.releaseDate()); + } catch (DateTimeParseException ignored) { + return null; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/install/WorldModListInstaller.java b/launcher/src/main/java/net/modtale/launcher/install/WorldModListInstaller.java new file mode 100644 index 00000000..6ca7f97f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/install/WorldModListInstaller.java @@ -0,0 +1,62 @@ +package net.modtale.launcher.install; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.api.ModtaleApiClient.DownloadedFile; +import net.modtale.launcher.api.ModtaleApiException; +import net.modtale.launcher.model.worldlist.WorldModList; +import net.modtale.launcher.model.worldlist.WorldModListInstallResult; +import net.modtale.launcher.settings.LauncherSettings; + +public final class WorldModListInstaller { + + private final ModtaleApiClient apiClient; + private final ArchiveInstaller archiveInstaller; + + public WorldModListInstaller(ModtaleApiClient apiClient) { + this(apiClient, new ArchiveInstaller()); + } + + WorldModListInstaller(ModtaleApiClient apiClient, ArchiveInstaller archiveInstaller) { + this.apiClient = apiClient; + this.archiveInstaller = archiveInstaller; + } + + public WorldModListInstallResult install(WorldModList list, LauncherSettings settings) { + if (list == null || list.id().isBlank()) { + throw new ModtaleApiException("Select a shared mod list before installing."); + } + if (settings == null) { + throw new ModtaleApiException("Launcher settings are unavailable."); + } + + DownloadedFile download = apiClient.download("/lists/" + encodePathSegment(list.id()) + "/download"); + try { + List installedFiles = archiveInstaller.extractInstallableEntries(download.path(), settings.hytaleModsDirectory()); + if (installedFiles.isEmpty()) { + throw new ModtaleApiException("This shared list did not include any installable files."); + } + return new WorldModListInstallResult(list, installedFiles); + } catch (IOException ex) { + throw new ModtaleApiException("Could not install " + list.title() + " into " + settings.hytaleModsDirectory(), ex); + } finally { + deleteTemp(download.path()); + } + } + + private static String encodePathSegment(String value) { + return java.net.URLEncoder.encode(value == null ? "" : value.trim(), java.nio.charset.StandardCharsets.UTF_8) + .replace("+", "%20"); + } + + private static void deleteTemp(Path path) { + try { + Files.deleteIfExists(path); + } catch (IOException ignored) { + // Temporary download cleanup is best-effort. + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/auth/SignInResponse.java b/launcher/src/main/java/net/modtale/launcher/model/auth/SignInResponse.java new file mode 100644 index 00000000..6de20817 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/auth/SignInResponse.java @@ -0,0 +1,7 @@ +package net.modtale.launcher.model.auth; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record SignInResponse(String status, boolean mfaRequired, String preAuthToken) { +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/install/InstallOptions.java b/launcher/src/main/java/net/modtale/launcher/model/install/InstallOptions.java new file mode 100644 index 00000000..9e48af3e --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/install/InstallOptions.java @@ -0,0 +1,30 @@ +package net.modtale.launcher.model.install; + +import java.nio.file.Path; +import java.util.List; +import net.modtale.launcher.model.project.ProjectDependency; + +public record InstallOptions( + Path modsDirectory, + String gameVersion, + boolean includeDependencies, + boolean includeOptionalDependencies, + List selectedDependencies +) { + public InstallOptions { + selectedDependencies = selectedDependencies == null ? null : List.copyOf(selectedDependencies); + } + + public InstallOptions( + Path modsDirectory, + String gameVersion, + boolean includeDependencies, + boolean includeOptionalDependencies + ) { + this(modsDirectory, gameVersion, includeDependencies, includeOptionalDependencies, null); + } + + public boolean hasSelectedDependencies() { + return selectedDependencies != null; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/install/InstallResult.java b/launcher/src/main/java/net/modtale/launcher/model/install/InstallResult.java new file mode 100644 index 00000000..84e88d3f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/install/InstallResult.java @@ -0,0 +1,11 @@ +package net.modtale.launcher.model.install; + +import java.nio.file.Path; +import java.util.List; + +public record InstallResult(InstalledProject installedProject, List installedFiles, List warnings) { + public InstallResult { + installedFiles = installedFiles == null ? List.of() : List.copyOf(installedFiles); + warnings = warnings == null ? List.of() : List.copyOf(warnings); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/install/InstalledProject.java b/launcher/src/main/java/net/modtale/launcher/model/install/InstalledProject.java new file mode 100644 index 00000000..f41cbf0c --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/install/InstalledProject.java @@ -0,0 +1,110 @@ +package net.modtale.launcher.model.install; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.time.Instant; +import java.util.List; +import net.modtale.launcher.model.project.ProjectClassification; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record InstalledProject( + String projectId, + String slug, + String title, + String classification, + String installedVersion, + String installedVersionId, + String gameVersion, + Instant installedAt, + Instant updatedAt, + List files, + List dependencyProjectIds, + List externalDependencies, + String source, + String installType, + boolean modpackUnlocked, + List bundledProjects +) { + public static final String SOURCE_MODTALE = "MODTALE"; + public static final String SOURCE_LOCAL = "LOCAL"; + public static final String INSTALL_DIRECT = "DIRECT"; + public static final String INSTALL_BUNDLE = "BUNDLE"; + public static final String INSTALL_MODPACK = "MODPACK"; + + public InstalledProject { + projectId = value(projectId); + slug = value(slug); + title = value(title); + classification = value(classification); + installedVersion = value(installedVersion); + installedVersionId = value(installedVersionId); + gameVersion = value(gameVersion); + installedAt = installedAt == null ? Instant.EPOCH : installedAt; + updatedAt = updatedAt == null ? installedAt : updatedAt; + files = files == null ? List.of() : List.copyOf(files); + dependencyProjectIds = dependencyProjectIds == null ? List.of() : List.copyOf(dependencyProjectIds); + externalDependencies = externalDependencies == null ? List.of() : List.copyOf(externalDependencies); + source = value(source, SOURCE_MODTALE); + bundledProjects = bundledProjects == null ? List.of() : List.copyOf(bundledProjects); + installType = value(installType, defaultInstallType(classification, bundledProjects)); + } + + public InstalledProject( + String projectId, + String slug, + String title, + String classification, + String installedVersion, + String installedVersionId, + String gameVersion, + Instant installedAt, + Instant updatedAt, + List files, + List dependencyProjectIds, + List externalDependencies + ) { + this(projectId, slug, title, classification, installedVersion, installedVersionId, gameVersion, + installedAt, updatedAt, files, dependencyProjectIds, externalDependencies, + SOURCE_MODTALE, "", false, List.of()); + } + + public InstalledProject withModpackUnlocked(boolean unlocked) { + return new InstalledProject(projectId, slug, title, classification, installedVersion, installedVersionId, + gameVersion, installedAt, updatedAt, files, dependencyProjectIds, externalDependencies, + source, installType, unlocked, bundledProjects); + } + + public List bundledModtaleProjectIds() { + if (!bundledProjects.isEmpty()) { + return bundledProjects.stream() + .filter(InstalledProjectReference::isModtaleProject) + .map(InstalledProjectReference::projectId) + .filter(id -> id != null && !id.isBlank()) + .distinct() + .toList(); + } + return dependencyProjectIds; + } + + public boolean isModpack() { + return ProjectClassification.isModpack(classification); + } + + private static String defaultInstallType(String classification, List bundledProjects) { + if (ProjectClassification.isModpack(classification)) { + return INSTALL_MODPACK; + } + if (bundledProjects != null && !bundledProjects.isEmpty()) { + return INSTALL_BUNDLE; + } + return INSTALL_DIRECT; + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } + + private static String value(String value, String fallback) { + String normalized = value(value); + return normalized.isBlank() ? fallback : normalized; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/install/InstalledProjectReference.java b/launcher/src/main/java/net/modtale/launcher/model/install/InstalledProjectReference.java new file mode 100644 index 00000000..7d661f03 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/install/InstalledProjectReference.java @@ -0,0 +1,126 @@ +package net.modtale.launcher.model.install; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import net.modtale.launcher.model.project.ProjectDependency; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record InstalledProjectReference( + String id, + String projectId, + String slug, + String title, + String classification, + String versionNumber, + String dependencyType, + String source, + String externalId, + String externalUrl, + String externalFileUrl, + String externalFileName, + String cachedFileUrl, + String icon, + Boolean optional, + Boolean embedded +) { + public InstalledProjectReference { + id = value(id); + projectId = value(projectId); + slug = value(slug); + title = value(title); + classification = value(classification); + versionNumber = value(versionNumber); + dependencyType = value(dependencyType); + source = value(source); + externalId = value(externalId); + externalUrl = value(externalUrl); + externalFileUrl = value(externalFileUrl); + externalFileName = value(externalFileName); + cachedFileUrl = value(cachedFileUrl); + icon = value(icon); + } + + public static InstalledProjectReference fromDependency(ProjectDependency dependency) { + if (dependency == null) { + return empty(); + } + return new InstalledProjectReference( + dependency.id(), + dependency.projectId(), + dependency.slug(), + displayTitle(dependency), + dependency.classification(), + dependency.versionNumber(), + dependency.dependencyType(), + dependency.source(), + dependency.externalId(), + dependency.externalUrl(), + dependency.externalFileUrl(), + dependency.externalFileName(), + dependency.cachedFileUrl(), + dependency.icon(), + dependency.optional(), + dependency.embedded() + ); + } + + public ProjectDependency toDependency() { + return new ProjectDependency( + id, + projectId, + title, + versionNumber, + dependencyType, + source, + externalId, + externalUrl, + externalFileUrl, + externalFileName, + cachedFileUrl, + false, + icon, + title, + classification, + slug, + optional, + embedded + ); + } + + public boolean isModtaleProject() { + return !projectId.isBlank() && (source.isBlank() || "MODTALE".equalsIgnoreCase(source)); + } + + public String routeKey() { + return !slug.isBlank() ? slug : projectId; + } + + public String displayName() { + if (!title.isBlank()) { + return title; + } + if (!externalId.isBlank()) { + return source.isBlank() ? externalId : source + ":" + externalId; + } + return !projectId.isBlank() ? projectId : value(id, "Bundled project"); + } + + private static InstalledProjectReference empty() { + return new InstalledProjectReference("", "", "", "", "", "", "", "", "", "", "", "", "", "", null, null); + } + + private static String displayTitle(ProjectDependency dependency) { + if (dependency.title() != null && !dependency.title().isBlank()) { + return dependency.title(); + } + return dependency.projectTitle(); + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } + + private static String value(String value, String fallback) { + String normalized = value(value); + return normalized.isBlank() ? fallback : normalized; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/install/UpdateCandidate.java b/launcher/src/main/java/net/modtale/launcher/model/install/UpdateCandidate.java new file mode 100644 index 00000000..cf028f2d --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/install/UpdateCandidate.java @@ -0,0 +1,18 @@ +package net.modtale.launcher.model.install; + +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectVersion; + +public record UpdateCandidate(InstalledProject installedProject, ProjectDetail project, ProjectVersion newestVersion) { + public String title() { + return installedProject.title(); + } + + public String currentVersion() { + return installedProject.installedVersion(); + } + + public String newestVersionNumber() { + return newestVersion == null ? "" : newestVersion.versionNumber(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/notification/LauncherNotification.java b/launcher/src/main/java/net/modtale/launcher/model/notification/LauncherNotification.java new file mode 100644 index 00000000..6abe6e00 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/notification/LauncherNotification.java @@ -0,0 +1,57 @@ +package net.modtale.launcher.model.notification; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record LauncherNotification( + String id, + String title, + String message, + String link, + String iconUrl, + boolean read, + String type, + Map metadata, + LocalDateTime createdAt +) { + public LauncherNotification { + metadata = metadata == null ? Map.of() : Map.copyOf(metadata); + } + + public boolean actionable() { + return actionType().isPresent(); + } + + public Optional actionType() { + return ActionType.fromType(type); + } + + public enum ActionType { + TRANSFER_REQUEST("TRANSFER_REQUEST"), + ORG_INVITE("ORG_INVITE"), + CONTRIBUTOR_INVITE("CONTRIBUTOR_INVITE"); + + private final String type; + + ActionType(String type) { + this.type = type; + } + + public String type() { + return type; + } + + static Optional fromType(String type) { + if (type == null || type.isBlank()) { + return Optional.empty(); + } + return Arrays.stream(values()) + .filter(actionType -> actionType.type.equals(type.trim())) + .findFirst(); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/DownloadUrlResponse.java b/launcher/src/main/java/net/modtale/launcher/model/project/DownloadUrlResponse.java new file mode 100644 index 00000000..15d322c8 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/DownloadUrlResponse.java @@ -0,0 +1,7 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record DownloadUrlResponse(String downloadUrl, int expiresIn) { +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/GameVersionCatalog.java b/launcher/src/main/java/net/modtale/launcher/model/project/GameVersionCatalog.java new file mode 100644 index 00000000..5045a0ec --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/GameVersionCatalog.java @@ -0,0 +1,29 @@ +package net.modtale.launcher.model.project; + +import java.util.List; + +public record GameVersionCatalog( + List releaseVersions, + List preReleaseVersions, + List allVersions, + List versions +) { + public GameVersionCatalog { + releaseVersions = releaseVersions == null ? List.of() : List.copyOf(releaseVersions); + preReleaseVersions = preReleaseVersions == null ? List.of() : List.copyOf(preReleaseVersions); + allVersions = allVersions == null ? List.of() : List.copyOf(allVersions); + versions = versions == null ? List.of() : List.copyOf(versions); + } + + public static GameVersionCatalog fromVersions(List versions) { + List safeVersions = versions == null ? List.of() : versions; + return new GameVersionCatalog(safeVersions, List.of(), safeVersions, List.of()); + } + + public record GameVersionEntry( + String version, + boolean preRelease, + String sourceUrl + ) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectClassification.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectClassification.java new file mode 100644 index 00000000..fe27018a --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectClassification.java @@ -0,0 +1,80 @@ +package net.modtale.launcher.model.project; + +import java.util.Arrays; +import java.util.Optional; + +public enum ProjectClassification { + MODPACK("MODPACK", "Modpack", "Modpack", "modpack"), + PLUGIN("PLUGIN", "Plugin", "Plugin", "mod"), + SAVE("SAVE", "World", "World", "world"), + ART("ART", "Art Asset", "Art", "mod"), + DATA("DATA", "Data Asset", "Data", "mod"); + + private final String apiValue; + private final String label; + private final String compactLabel; + private final String routePrefix; + + ProjectClassification(String apiValue, String label, String compactLabel, String routePrefix) { + this.apiValue = apiValue; + this.label = label; + this.compactLabel = compactLabel; + this.routePrefix = routePrefix; + } + + public String apiValue() { + return apiValue; + } + + public String label() { + return label; + } + + public String compactLabel() { + return compactLabel; + } + + public String routePrefix() { + return routePrefix; + } + + public boolean isModpack() { + return this == MODPACK; + } + + public static Optional fromApiValue(String value) { + if (value == null || value.isBlank()) { + return Optional.empty(); + } + String normalized = value.trim(); + return Arrays.stream(values()) + .filter(classification -> classification.apiValue.equalsIgnoreCase(normalized)) + .findFirst(); + } + + public static boolean isModpack(String value) { + return fromApiValue(value).map(ProjectClassification::isModpack).orElse(false); + } + + public static String labelFor(String value) { + return fromApiValue(value) + .map(ProjectClassification::label) + .orElseGet(() -> fallback(value)); + } + + public static String compactLabelFor(String value) { + return fromApiValue(value) + .map(ProjectClassification::compactLabel) + .orElseGet(() -> fallback(value)); + } + + public static String routePrefixFor(String value) { + return fromApiValue(value) + .map(ProjectClassification::routePrefix) + .orElse(PLUGIN.routePrefix); + } + + private static String fallback(String value) { + return value == null || value.isBlank() ? "Project" : value; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectComment.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectComment.java new file mode 100644 index 00000000..fbd1585c --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectComment.java @@ -0,0 +1,96 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectComment( + String id, + @JsonAlias("authorId") String userId, + String user, + Author author, + String content, + String date, + String updatedAt, + Integer upvoteCount, + Integer downvoteCount, + String userVote, + List upvotes, + List downvotes, + Reply developerReply +) { + public ProjectComment { + upvotes = upvotes == null ? List.of() : List.copyOf(upvotes); + downvotes = downvotes == null ? List.of() : List.copyOf(downvotes); + } + + public int score() { + if (upvoteCount != null || downvoteCount != null) { + return Math.max(0, upvoteCount == null ? 0 : upvoteCount) + - Math.max(0, downvoteCount == null ? 0 : downvoteCount); + } + return upvotes.size() - downvotes.size(); + } + + public String userVoteFor(String currentUserId) { + if ("up".equalsIgnoreCase(userVote) || "down".equalsIgnoreCase(userVote)) { + return userVote.toLowerCase(java.util.Locale.ROOT); + } + if (currentUserId != null && upvotes.contains(currentUserId)) { + return "up"; + } + if (currentUserId != null && downvotes.contains(currentUserId)) { + return "down"; + } + return null; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record Reply( + @JsonAlias("authorId") String userId, + String user, + Author author, + String content, + String date, + Integer upvoteCount, + Integer downvoteCount, + String userVote, + List upvotes, + List downvotes + ) { + public Reply { + upvotes = upvotes == null ? List.of() : List.copyOf(upvotes); + downvotes = downvotes == null ? List.of() : List.copyOf(downvotes); + } + + public int score() { + if (upvoteCount != null || downvoteCount != null) { + return Math.max(0, upvoteCount == null ? 0 : upvoteCount) + - Math.max(0, downvoteCount == null ? 0 : downvoteCount); + } + return upvotes.size() - downvotes.size(); + } + + public String userVoteFor(String currentUserId) { + if ("up".equalsIgnoreCase(userVote) || "down".equalsIgnoreCase(userVote)) { + return userVote.toLowerCase(java.util.Locale.ROOT); + } + if (currentUserId != null && upvotes.contains(currentUserId)) { + return "up"; + } + if (currentUserId != null && downvotes.contains(currentUserId)) { + return "down"; + } + return null; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record Author( + String id, + String username, + String avatarUrl + ) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectDependency.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectDependency.java new file mode 100644 index 00000000..6b57f879 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectDependency.java @@ -0,0 +1,74 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectDependency( + String id, + String projectId, + String projectTitle, + String versionNumber, + String dependencyType, + String source, + String externalId, + String externalUrl, + String externalFileUrl, + String externalFileName, + String cachedFileUrl, + boolean hytaleProjectConfirmed, + String icon, + String title, + String classification, + String slug, + @JsonProperty("isOptional") Boolean optional, + @JsonProperty("isEmbedded") Boolean embedded +) { + public ProjectDependency( + String id, + String projectId, + String projectTitle, + String versionNumber, + String dependencyType, + String source, + String externalId, + String externalUrl, + String externalFileUrl, + String externalFileName, + String cachedFileUrl, + boolean hytaleProjectConfirmed + ) { + this(id, projectId, projectTitle, versionNumber, dependencyType, source, externalId, externalUrl, + externalFileUrl, externalFileName, cachedFileUrl, hytaleProjectConfirmed, + null, null, null, null, null, null); + } + + public boolean isOptional() { + return Boolean.TRUE.equals(optional) || DependencyType.OPTIONAL.matches(dependencyType); + } + + public boolean isEmbedded() { + return Boolean.TRUE.equals(embedded) || DependencyType.EMBEDDED.matches(dependencyType); + } + + public boolean isExternal() { + return source != null && !DependencySource.MODTALE.matches(source); + } + + private enum DependencyType { + OPTIONAL, + EMBEDDED; + + boolean matches(String value) { + return value != null && name().equalsIgnoreCase(value.trim()); + } + } + + private enum DependencySource { + MODTALE; + + boolean matches(String value) { + return value != null && name().equalsIgnoreCase(value.trim()); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectDetail.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectDetail.java new file mode 100644 index 00000000..d25b1ad5 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectDetail.java @@ -0,0 +1,67 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectDetail( + String id, + String slug, + String title, + String about, + String description, + String authorId, + String author, + String imageUrl, + String bannerUrl, + String classification, + int downloadCount, + int favoriteCount, + String updatedAt, + String license, + String repositoryUrl, + Map links, + List tags, + List galleryImages, + Map galleryImageCaptions, + Boolean allowComments, + boolean hmWikiEnabled, + String hmWikiSlug, + List versions +) { + public ProjectDetail { + links = links == null ? Map.of() : Map.copyOf(links); + tags = tags == null ? List.of() : List.copyOf(tags); + galleryImages = galleryImages == null ? List.of() : List.copyOf(galleryImages); + galleryImageCaptions = galleryImageCaptions == null ? Map.of() : Map.copyOf(galleryImageCaptions); + versions = versions == null ? List.of() : List.copyOf(versions); + } + + public ProjectDetail( + String id, + String slug, + String title, + String description, + String author, + String classification, + String updatedAt, + String license, + String repositoryUrl, + List tags, + List versions + ) { + this(id, slug, title, null, description, null, author, null, null, classification, 0, 0, updatedAt, + license, repositoryUrl, Map.of(), tags, List.of(), Map.of(), null, false, null, versions); + } + + public String routeKey() { + return slug != null && !slug.isBlank() ? slug : id; + } + + public ProjectDetail withVersions(List nextVersions) { + return new ProjectDetail(id, slug, title, about, description, authorId, author, imageUrl, bannerUrl, + classification, downloadCount, favoriteCount, updatedAt, license, repositoryUrl, links, tags, + galleryImages, galleryImageCaptions, allowComments, hmWikiEnabled, hmWikiSlug, nextVersions); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectGallery.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectGallery.java new file mode 100644 index 00000000..1fbf830b --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectGallery.java @@ -0,0 +1,16 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectGallery( + List galleryImages, + Map galleryImageCaptions +) { + public ProjectGallery { + galleryImages = galleryImages == null ? List.of() : List.copyOf(galleryImages); + galleryImageCaptions = galleryImageCaptions == null ? Map.of() : Map.copyOf(galleryImageCaptions); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectMeta.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectMeta.java new file mode 100644 index 00000000..f79f6456 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectMeta.java @@ -0,0 +1,16 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectMeta( + String title, + String description, + String icon, + String author, + String classification, + int downloads, + String repositoryUrl, + String slug +) { +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectPage.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectPage.java new file mode 100644 index 00000000..f783e135 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectPage.java @@ -0,0 +1,17 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectPage( + List content, + int totalPages, + long totalElements, + int number, + boolean last +) { + public ProjectPage { + content = content == null ? List.of() : List.copyOf(content); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectSummary.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectSummary.java new file mode 100644 index 00000000..154e599d --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectSummary.java @@ -0,0 +1,39 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectSummary( + String id, + String slug, + String title, + String description, + String authorId, + String author, + String imageUrl, + String bannerUrl, + String classification, + int downloadCount, + int favoriteCount, + String updatedAt, + List versions +) { + public ProjectSummary { + versions = versions == null ? List.of() : List.copyOf(versions); + } + + public String routeKey() { + return slug != null && !slug.isBlank() ? slug : id; + } + + public ProjectSummary withFavoriteCount(int nextFavoriteCount) { + return new ProjectSummary(id, slug, title, description, authorId, author, imageUrl, bannerUrl, classification, + downloadCount, Math.max(0, nextFavoriteCount), updatedAt, versions); + } + + @Override + public String toString() { + return title == null || title.isBlank() ? routeKey() : title; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersion.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersion.java new file mode 100644 index 00000000..d36c56c3 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersion.java @@ -0,0 +1,42 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectVersion( + String id, + String versionNumber, + List gameVersions, + String fileUrl, + int downloadCount, + String releaseDate, + String changelog, + List dependencies, + String channel, + List incompatibleProjectIds +) { + public ProjectVersion { + gameVersions = gameVersions == null ? List.of() : List.copyOf(gameVersions); + dependencies = dependencies == null ? List.of() : List.copyOf(dependencies); + incompatibleProjectIds = incompatibleProjectIds == null ? List.of() : List.copyOf(incompatibleProjectIds); + } + + public ProjectVersion( + String id, + String versionNumber, + List gameVersions, + String fileUrl, + int downloadCount, + String releaseDate, + String changelog, + List dependencies, + String channel + ) { + this(id, versionNumber, gameVersions, fileUrl, downloadCount, releaseDate, changelog, dependencies, channel, List.of()); + } + + public boolean supportsGameVersion(String gameVersion) { + return gameVersion == null || gameVersion.isBlank() || gameVersions.contains(gameVersion); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersionChangelog.java b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersionChangelog.java new file mode 100644 index 00000000..27cfc294 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/ProjectVersionChangelog.java @@ -0,0 +1,11 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProjectVersionChangelog( + String id, + String versionNumber, + String changelog +) { +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/project/VersionDependenciesView.java b/launcher/src/main/java/net/modtale/launcher/model/project/VersionDependenciesView.java new file mode 100644 index 00000000..93ccc7f2 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/project/VersionDependenciesView.java @@ -0,0 +1,11 @@ +package net.modtale.launcher.model.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record VersionDependenciesView(List dependencies) { + public VersionDependenciesView { + dependencies = dependencies == null ? List.of() : List.copyOf(dependencies); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/sync/LauncherSettingsSnapshot.java b/launcher/src/main/java/net/modtale/launcher/model/sync/LauncherSettingsSnapshot.java new file mode 100644 index 00000000..110efd94 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/sync/LauncherSettingsSnapshot.java @@ -0,0 +1,366 @@ +package net.modtale.launcher.model.sync; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HexFormat; +import java.util.List; +import java.util.StringJoiner; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; +import net.modtale.launcher.settings.LauncherSettings; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class LauncherSettingsSnapshot { + + private int schemaVersion = 1; + private String settingsHash = ""; + private String updatedAt = ""; + private Preferences preferences = new Preferences(); + private List installedProjects = new ArrayList<>(); + + public static LauncherSettingsSnapshot fromSettings(LauncherSettings settings) { + LauncherSettingsSnapshot snapshot = new LauncherSettingsSnapshot(); + snapshot.setPreferences(Preferences.fromSettings(settings)); + snapshot.setInstalledProjects(settings == null ? List.of() : settings.getInstalledProjects().stream() + .filter(LauncherSettingsSnapshot::isSyncedProject) + .map(InstalledProjectSnapshot::fromInstalledProject) + .toList()); + snapshot.refreshHash(); + return snapshot; + } + + public void applyPreferencesTo(LauncherSettings settings) { + if (settings == null) { + return; + } + Preferences source = preferences == null ? new Preferences() : preferences; + settings.setHytaleModsPath(source.hytaleModsPath); + settings.setHytaleGamePath(source.hytaleGamePath); + settings.setHytaleUserDataPath(source.hytaleUserDataPath); + settings.setHytaleJavaPath(source.hytaleJavaPath); + settings.setHytaleBranch(source.hytaleBranch); + settings.setHytaleBuild(source.hytaleBuild); + settings.setGameVersion(source.gameVersion); + settings.setIncludeDependencies(source.includeDependencies); + settings.setIncludeOptionalDependencies(source.includeOptionalDependencies); + settings.setAutoCheckUpdates(source.autoCheckUpdates); + settings.setLauncherAutoUpdates(source.launcherAutoUpdates); + } + + public boolean hasSyncedContent() { + return !installedProjects().isEmpty() + || (settingsHash != null && !settingsHash.isBlank()) + || (updatedAt != null && !updatedAt.isBlank()); + } + + public String effectiveHash() { + String hash = settingsHash == null ? "" : settingsHash.trim(); + if (!hash.isBlank()) { + return hash; + } + return computeHash(); + } + + public String computeHash() { + return hashPayload(canonicalPayload()); + } + + public String installedProjectsHash() { + return hashPayload(canonicalInstalledProjectsPayload()); + } + + public LauncherSettingsSnapshot preferencesOnly() { + LauncherSettingsSnapshot copy = new LauncherSettingsSnapshot(); + copy.setSchemaVersion(schemaVersion); + copy.setSettingsHash(computeHash()); + copy.setUpdatedAt(updatedAt); + copy.setPreferences(preferences); + copy.setInstalledProjects(List.of()); + return copy; + } + + private static String hashPayload(String payload) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hashed = digest.digest(payload.getBytes(StandardCharsets.UTF_8)); + return HexFormat.of().formatHex(hashed); + } catch (NoSuchAlgorithmException ex) { + throw new IllegalStateException("SHA-256 is not available.", ex); + } + } + + public void refreshHash() { + settingsHash = computeHash(); + } + + private String canonicalPayload() { + Preferences prefs = preferences == null ? new Preferences() : preferences; + StringJoiner payload = new StringJoiner("\n"); + payload.add("schema=" + schemaVersion); + payload.add("modsPath=" + value(prefs.hytaleModsPath)); + payload.add("gamePath=" + value(prefs.hytaleGamePath)); + payload.add("userDataPath=" + value(prefs.hytaleUserDataPath)); + payload.add("javaPath=" + value(prefs.hytaleJavaPath)); + payload.add("branch=" + value(prefs.hytaleBranch)); + payload.add("build=" + Math.max(0, prefs.hytaleBuild)); + payload.add("gameVersion=" + value(prefs.gameVersion)); + payload.add("includeDependencies=" + prefs.includeDependencies); + payload.add("includeOptionalDependencies=" + prefs.includeOptionalDependencies); + payload.add("autoCheckUpdates=" + prefs.autoCheckUpdates); + payload.add("launcherAutoUpdates=" + prefs.launcherAutoUpdates); + installedProjects().stream() + .filter(project -> !value(project.projectId).isBlank()) + .sorted(Comparator + .comparing((InstalledProjectSnapshot project) -> value(project.projectId)) + .thenComparing(project -> value(project.installedVersionId)) + .thenComparing(project -> value(project.installedVersion))) + .forEach(project -> payload.add(project.canonicalPayload())); + return payload.toString(); + } + + private String canonicalInstalledProjectsPayload() { + StringJoiner payload = new StringJoiner("\n"); + installedProjects().stream() + .filter(project -> !value(project.projectId).isBlank()) + .sorted(Comparator + .comparing((InstalledProjectSnapshot project) -> value(project.projectId)) + .thenComparing(project -> value(project.installedVersionId)) + .thenComparing(project -> value(project.installedVersion))) + .forEach(project -> payload.add(project.canonicalPayload())); + return payload.toString(); + } + + public int getSchemaVersion() { + return schemaVersion; + } + + public void setSchemaVersion(int schemaVersion) { + this.schemaVersion = Math.max(1, schemaVersion); + } + + public String getSettingsHash() { + return settingsHash; + } + + public void setSettingsHash(String settingsHash) { + this.settingsHash = settingsHash == null ? "" : settingsHash.trim(); + } + + public String getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt == null ? "" : updatedAt.trim(); + } + + public Preferences getPreferences() { + return preferences; + } + + public void setPreferences(Preferences preferences) { + this.preferences = preferences == null ? new Preferences() : preferences; + } + + public List getInstalledProjects() { + return installedProjects; + } + + public void setInstalledProjects(List installedProjects) { + this.installedProjects = installedProjects == null ? new ArrayList<>() : new ArrayList<>(installedProjects); + } + + public List installedProjects() { + return installedProjects == null ? List.of() : List.copyOf(installedProjects); + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } + + private static boolean isSyncedProject(InstalledProject project) { + if (project == null) { + return false; + } + String source = value(project.source()); + return source.isBlank() || InstalledProject.SOURCE_MODTALE.equalsIgnoreCase(source); + } + + private static String listValue(List values) { + if (values == null || values.isEmpty()) { + return ""; + } + return values.stream() + .filter(value -> value != null && !value.isBlank()) + .map(String::trim) + .distinct() + .sorted() + .reduce((left, right) -> left + "," + right) + .orElse(""); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Preferences { + private String hytaleModsPath = ""; + private String hytaleGamePath = ""; + private String hytaleUserDataPath = ""; + private String hytaleJavaPath = ""; + private String hytaleBranch = "release"; + private int hytaleBuild; + private String gameVersion = ""; + private boolean includeDependencies = true; + private boolean includeOptionalDependencies; + private boolean autoCheckUpdates = true; + private boolean launcherAutoUpdates; + + public static Preferences fromSettings(LauncherSettings settings) { + Preferences preferences = new Preferences(); + if (settings == null) { + return preferences; + } + preferences.setHytaleModsPath(settings.getHytaleModsPath()); + preferences.setHytaleGamePath(settings.getHytaleGamePath()); + preferences.setHytaleUserDataPath(settings.getHytaleUserDataPath()); + preferences.setHytaleJavaPath(settings.getHytaleJavaPath()); + preferences.setHytaleBranch(settings.getHytaleBranch()); + preferences.setHytaleBuild(settings.getHytaleBuild()); + preferences.setGameVersion(settings.getGameVersion()); + preferences.setIncludeDependencies(settings.isIncludeDependencies()); + preferences.setIncludeOptionalDependencies(settings.isIncludeOptionalDependencies()); + preferences.setAutoCheckUpdates(settings.isAutoCheckUpdates()); + preferences.setLauncherAutoUpdates(settings.isLauncherAutoUpdates()); + return preferences; + } + + public String getHytaleModsPath() { return hytaleModsPath; } + public void setHytaleModsPath(String hytaleModsPath) { this.hytaleModsPath = value(hytaleModsPath); } + public String getHytaleGamePath() { return hytaleGamePath; } + public void setHytaleGamePath(String hytaleGamePath) { this.hytaleGamePath = value(hytaleGamePath); } + public String getHytaleUserDataPath() { return hytaleUserDataPath; } + public void setHytaleUserDataPath(String hytaleUserDataPath) { this.hytaleUserDataPath = value(hytaleUserDataPath); } + public String getHytaleJavaPath() { return hytaleJavaPath; } + public void setHytaleJavaPath(String hytaleJavaPath) { this.hytaleJavaPath = value(hytaleJavaPath); } + public String getHytaleBranch() { return hytaleBranch; } + public void setHytaleBranch(String hytaleBranch) { this.hytaleBranch = value(hytaleBranch); } + public int getHytaleBuild() { return hytaleBuild; } + public void setHytaleBuild(int hytaleBuild) { this.hytaleBuild = Math.max(0, hytaleBuild); } + public String getGameVersion() { return gameVersion; } + public void setGameVersion(String gameVersion) { this.gameVersion = value(gameVersion); } + public boolean isIncludeDependencies() { return includeDependencies; } + public void setIncludeDependencies(boolean includeDependencies) { this.includeDependencies = includeDependencies; } + public boolean isIncludeOptionalDependencies() { return includeOptionalDependencies; } + public void setIncludeOptionalDependencies(boolean includeOptionalDependencies) { this.includeOptionalDependencies = includeOptionalDependencies; } + public boolean isAutoCheckUpdates() { return autoCheckUpdates; } + public void setAutoCheckUpdates(boolean autoCheckUpdates) { this.autoCheckUpdates = autoCheckUpdates; } + public boolean isLauncherAutoUpdates() { return launcherAutoUpdates; } + public void setLauncherAutoUpdates(boolean launcherAutoUpdates) { this.launcherAutoUpdates = launcherAutoUpdates; } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class InstalledProjectSnapshot { + private String projectId = ""; + private String slug = ""; + private String title = ""; + private String classification = ""; + private String installedVersion = ""; + private String installedVersionId = ""; + private String gameVersion = ""; + private String source = InstalledProject.SOURCE_MODTALE; + private String installType = InstalledProject.INSTALL_DIRECT; + private boolean modpackUnlocked; + private List dependencyProjectIds = new ArrayList<>(); + private List externalDependencies = new ArrayList<>(); + private List bundledProjects = new ArrayList<>(); + + public static InstalledProjectSnapshot fromInstalledProject(InstalledProject project) { + InstalledProjectSnapshot snapshot = new InstalledProjectSnapshot(); + if (project == null) { + return snapshot; + } + snapshot.setProjectId(project.projectId()); + snapshot.setSlug(project.slug()); + snapshot.setTitle(project.title()); + snapshot.setClassification(project.classification()); + snapshot.setInstalledVersion(project.installedVersion()); + snapshot.setInstalledVersionId(project.installedVersionId()); + snapshot.setGameVersion(project.gameVersion()); + snapshot.setSource(project.source()); + snapshot.setInstallType(project.installType()); + snapshot.setModpackUnlocked(project.modpackUnlocked()); + snapshot.setDependencyProjectIds(project.dependencyProjectIds()); + snapshot.setExternalDependencies(project.externalDependencies()); + snapshot.setBundledProjects(project.bundledProjects()); + return snapshot; + } + + private String canonicalPayload() { + return String.join("|", + "project=" + value(projectId), + "slug=" + value(slug), + "title=" + value(title), + "classification=" + value(classification), + "version=" + value(installedVersion), + "versionId=" + value(installedVersionId), + "gameVersion=" + value(gameVersion), + "source=" + value(source), + "installType=" + value(installType), + "unlocked=" + modpackUnlocked, + "deps=" + listValue(dependencyProjectIds), + "external=" + listValue(externalDependencies), + "bundled=" + bundledValue(bundledProjects)); + } + + public String getProjectId() { return projectId; } + public void setProjectId(String projectId) { this.projectId = value(projectId); } + public String getSlug() { return slug; } + public void setSlug(String slug) { this.slug = value(slug); } + public String getTitle() { return title; } + public void setTitle(String title) { this.title = value(title); } + public String getClassification() { return classification; } + public void setClassification(String classification) { this.classification = value(classification); } + public String getInstalledVersion() { return installedVersion; } + public void setInstalledVersion(String installedVersion) { this.installedVersion = value(installedVersion); } + public String getInstalledVersionId() { return installedVersionId; } + public void setInstalledVersionId(String installedVersionId) { this.installedVersionId = value(installedVersionId); } + public String getGameVersion() { return gameVersion; } + public void setGameVersion(String gameVersion) { this.gameVersion = value(gameVersion); } + public String getSource() { return source; } + public void setSource(String source) { this.source = value(source).isBlank() ? InstalledProject.SOURCE_MODTALE : value(source); } + public String getInstallType() { return installType; } + public void setInstallType(String installType) { this.installType = value(installType).isBlank() ? InstalledProject.INSTALL_DIRECT : value(installType); } + public boolean isModpackUnlocked() { return modpackUnlocked; } + public void setModpackUnlocked(boolean modpackUnlocked) { this.modpackUnlocked = modpackUnlocked; } + public List getDependencyProjectIds() { return dependencyProjectIds; } + public void setDependencyProjectIds(List dependencyProjectIds) { + this.dependencyProjectIds = dependencyProjectIds == null ? new ArrayList<>() : new ArrayList<>(dependencyProjectIds); + } + public List getExternalDependencies() { return externalDependencies; } + public void setExternalDependencies(List externalDependencies) { + this.externalDependencies = externalDependencies == null ? new ArrayList<>() : new ArrayList<>(externalDependencies); + } + public List getBundledProjects() { return bundledProjects; } + public void setBundledProjects(List bundledProjects) { + this.bundledProjects = bundledProjects == null ? new ArrayList<>() : new ArrayList<>(bundledProjects); + } + } + + private static String bundledValue(List projects) { + if (projects == null || projects.isEmpty()) { + return ""; + } + return projects.stream() + .map(project -> String.join(":", + value(project.projectId()), + value(project.slug()), + value(project.versionNumber()), + value(project.source()), + value(project.externalId()))) + .sorted() + .reduce((left, right) -> left + "," + right) + .orElse(""); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/user/CreatorProfile.java b/launcher/src/main/java/net/modtale/launcher/model/user/CreatorProfile.java new file mode 100644 index 00000000..59d30a3f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/user/CreatorProfile.java @@ -0,0 +1,76 @@ +package net.modtale.launcher.model.user; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record CreatorProfile( + @JsonAlias("_id") String id, + String username, + String avatarUrl, + String bannerUrl, + String bio, + String createdAt, + String tier, + List roles, + String accountType, + List badges, + List followerIds, + List followingIds, + List connectedAccounts, + List organizationMembers, + List organizationRoles +) { + public CreatorProfile { + roles = roles == null ? List.of() : List.copyOf(roles); + badges = badges == null ? List.of() : List.copyOf(badges); + followerIds = followerIds == null ? List.of() : List.copyOf(followerIds); + followingIds = followingIds == null ? List.of() : List.copyOf(followingIds); + connectedAccounts = connectedAccounts == null ? List.of() : List.copyOf(connectedAccounts); + organizationMembers = organizationMembers == null ? List.of() : List.copyOf(organizationMembers); + organizationRoles = organizationRoles == null ? List.of() : List.copyOf(organizationRoles); + } + + public boolean organization() { + return "ORGANIZATION".equalsIgnoreCase(accountType); + } + + @Override + public String toString() { + return username == null || username.isBlank() ? id : username; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record ConnectedAccount( + String provider, + String providerId, + String username, + String profileUrl, + Boolean visible + ) { + public boolean isVisible() { + return Boolean.TRUE.equals(visible); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record OrganizationMember( + String userId, + String roleId + ) { + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public record OrganizationRole( + String id, + String name, + String color, + List permissions, + Boolean owner + ) { + public OrganizationRole { + permissions = permissions == null ? List.of() : List.copyOf(permissions); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/user/CurrentUser.java b/launcher/src/main/java/net/modtale/launcher/model/user/CurrentUser.java new file mode 100644 index 00000000..260f540b --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/user/CurrentUser.java @@ -0,0 +1,84 @@ +package net.modtale.launcher.model.user; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record CurrentUser( + String id, + String username, + String avatarUrl, + String email, + Boolean emailVerified, + String tier, + List likedProjectIds, + List followingIds, + NotificationPreferences notificationPreferences +) { + public CurrentUser { + likedProjectIds = likedProjectIds == null ? List.of() : List.copyOf(likedProjectIds); + followingIds = followingIds == null ? List.of() : List.copyOf(followingIds); + notificationPreferences = notificationPreferences == null + ? NotificationPreferences.defaults() + : notificationPreferences; + } + + public boolean likesProject(String projectId) { + return projectId != null && likedProjectIds.contains(projectId); + } + + public boolean followsUser(String userId) { + return userId != null && followingIds.contains(userId); + } + + @Override + public String toString() { + return username == null || username.isBlank() ? id : username; + } + + public record NotificationPreferences( + String projectUpdates, + String creatorUploads, + String newComments, + String newFollowers, + String dependencyUpdates + ) { + public NotificationPreferences { + projectUpdates = level(projectUpdates); + creatorUploads = level(creatorUploads); + newComments = level(newComments); + newFollowers = level(newFollowers); + dependencyUpdates = level(dependencyUpdates); + } + + public static NotificationPreferences defaults() { + String enabled = NotificationLevel.ON.apiValue(); + return new NotificationPreferences(enabled, enabled, enabled, enabled, enabled); + } + + private static String level(String value) { + return NotificationLevel.fromApiValue(value).apiValue(); + } + } + + public enum NotificationLevel { + ON, + OFF; + + public String apiValue() { + return name(); + } + + public static NotificationLevel fromApiValue(String value) { + if (value == null || value.isBlank()) { + return ON; + } + for (NotificationLevel level : values()) { + if (level.name().equalsIgnoreCase(value.trim())) { + return level; + } + } + return ON; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/user/UserSummary.java b/launcher/src/main/java/net/modtale/launcher/model/user/UserSummary.java new file mode 100644 index 00000000..60a648ba --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/user/UserSummary.java @@ -0,0 +1,28 @@ +package net.modtale.launcher.model.user; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record UserSummary( + String id, + String username, + String avatarUrl, + String bannerUrl, + String bio, + String createdAt, + String tier, + List roles, + String accountType, + List badges +) { + public UserSummary { + roles = roles == null ? List.of() : List.copyOf(roles); + badges = badges == null ? List.of() : List.copyOf(badges); + } + + @Override + public String toString() { + return username == null || username.isBlank() ? id : username; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/worldlist/CreateWorldModListRequest.java b/launcher/src/main/java/net/modtale/launcher/model/worldlist/CreateWorldModListRequest.java new file mode 100644 index 00000000..fef2bb99 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/worldlist/CreateWorldModListRequest.java @@ -0,0 +1,47 @@ +package net.modtale.launcher.model.worldlist; + +import java.util.List; + +public record CreateWorldModListRequest( + String title, + String worldName, + String gameVersion, + List mods +) { + public CreateWorldModListRequest { + title = value(title); + worldName = value(worldName); + gameVersion = value(gameVersion); + mods = mods == null ? List.of() : List.copyOf(mods); + } + + public record Item( + String modId, + String projectId, + String slug, + String title, + String versionNumber, + String classification, + String source, + String externalId, + String externalUrl, + String icon + ) { + public Item { + modId = value(modId); + projectId = value(projectId); + slug = value(slug); + title = value(title); + versionNumber = value(versionNumber); + classification = value(classification); + source = value(source); + externalId = value(externalId); + externalUrl = value(externalUrl); + icon = value(icon); + } + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModList.java b/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModList.java new file mode 100644 index 00000000..3a828f8d --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModList.java @@ -0,0 +1,41 @@ +package net.modtale.launcher.model.worldlist; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.time.Instant; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record WorldModList( + String id, + String title, + String worldName, + String gameVersion, + String ownerUsername, + Instant createdAt, + Instant lastViewedAt, + Instant expiresAt, + int viewCount, + int downloadCount, + int modCount, + int downloadableCount, + String shareUrl, + String downloadUrl, + String launcherInstallUrl, + List mods +) { + public WorldModList { + id = value(id); + title = value(title); + worldName = value(worldName); + gameVersion = value(gameVersion); + ownerUsername = value(ownerUsername); + shareUrl = value(shareUrl); + downloadUrl = value(downloadUrl); + launcherInstallUrl = value(launcherInstallUrl); + mods = mods == null ? List.of() : List.copyOf(mods); + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListInstallResult.java b/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListInstallResult.java new file mode 100644 index 00000000..b650a7d4 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListInstallResult.java @@ -0,0 +1,13 @@ +package net.modtale.launcher.model.worldlist; + +import java.nio.file.Path; +import java.util.List; + +public record WorldModListInstallResult( + WorldModList list, + List installedFiles +) { + public WorldModListInstallResult { + installedFiles = installedFiles == null ? List.of() : List.copyOf(installedFiles); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListItem.java b/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListItem.java new file mode 100644 index 00000000..4321b30f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/model/worldlist/WorldModListItem.java @@ -0,0 +1,39 @@ +package net.modtale.launcher.model.worldlist; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record WorldModListItem( + String id, + String modId, + String projectId, + String slug, + String title, + String versionNumber, + String classification, + String source, + String externalId, + String externalUrl, + String icon, + boolean downloadable, + String unavailableReason +) { + public WorldModListItem { + id = value(id); + modId = value(modId); + projectId = value(projectId); + slug = value(slug); + title = value(title); + versionNumber = value(versionNumber); + classification = value(classification); + source = value(source); + externalId = value(externalId); + externalUrl = value(externalUrl); + icon = value(icon); + unavailableReason = value(unavailableReason); + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/protocol/LauncherProtocolRequest.java b/launcher/src/main/java/net/modtale/launcher/protocol/LauncherProtocolRequest.java new file mode 100644 index 00000000..b51be16d --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/protocol/LauncherProtocolRequest.java @@ -0,0 +1,111 @@ +package net.modtale.launcher.protocol; + +import java.net.URI; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javafx.application.Application; + +public record LauncherProtocolRequest(String installListId) { + + private static final LauncherProtocolRequest EMPTY = new LauncherProtocolRequest(""); + + public LauncherProtocolRequest { + installListId = value(installListId); + } + + public boolean hasInstallList() { + return !installListId.isBlank(); + } + + public static LauncherProtocolRequest from(Application.Parameters parameters) { + if (parameters == null) { + return EMPTY; + } + + String namedListId = firstValue(parameters.getNamed(), "listId", "installList", "install-list", "list"); + if (!namedListId.isBlank()) { + return new LauncherProtocolRequest(namedListId); + } + + LauncherProtocolRequest rawRequest = firstProtocolUrl(parameters.getRaw()); + if (rawRequest.hasInstallList()) { + return rawRequest; + } + + return firstProtocolUrl(parameters.getUnnamed()); + } + + private static LauncherProtocolRequest firstProtocolUrl(List values) { + if (values == null) { + return EMPTY; + } + for (String value : values) { + LauncherProtocolRequest request = fromProtocolUrl(value); + if (request.hasInstallList()) { + return request; + } + } + return EMPTY; + } + + private static LauncherProtocolRequest fromProtocolUrl(String value) { + if (value == null || !value.trim().startsWith("modtale:")) { + return EMPTY; + } + try { + URI uri = URI.create(value.trim()); + if (!"modtale".equalsIgnoreCase(uri.getScheme())) { + return EMPTY; + } + String action = value(uri.getHost()); + if (!"install-list".equalsIgnoreCase(action)) { + return EMPTY; + } + Map params = queryParams(uri.getRawQuery()); + return new LauncherProtocolRequest(params.get("listId")); + } catch (IllegalArgumentException ignored) { + return EMPTY; + } + } + + private static Map queryParams(String rawQuery) { + Map params = new LinkedHashMap<>(); + if (rawQuery == null || rawQuery.isBlank()) { + return params; + } + for (String part : rawQuery.split("&")) { + if (part.isBlank()) { + continue; + } + int separator = part.indexOf('='); + String key = separator >= 0 ? part.substring(0, separator) : part; + String rawValue = separator >= 0 ? part.substring(separator + 1) : ""; + params.put(decode(key), decode(rawValue)); + } + return params; + } + + private static String firstValue(Map values, String... keys) { + if (values == null || values.isEmpty()) { + return ""; + } + for (String key : keys) { + String value = values.get(key); + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + private static String decode(String value) { + return URLDecoder.decode(value == null ? "" : value, StandardCharsets.UTF_8); + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/settings/HytalePathDetector.java b/launcher/src/main/java/net/modtale/launcher/settings/HytalePathDetector.java new file mode 100644 index 00000000..d3a53c2c --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/settings/HytalePathDetector.java @@ -0,0 +1,169 @@ +package net.modtale.launcher.settings; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.stream.Stream; + +public final class HytalePathDetector { + + private HytalePathDetector() { + } + + public static Path defaultModsDirectory() { + return detectExistingModsDirectory().orElseGet(() -> defaultUserDataDirectory().resolve("Mods")); + } + + public static Path defaultSavesDirectory() { + return detectExistingSavesDirectory().orElseGet(() -> defaultUserDataDirectory().resolve("Saves")); + } + + public static Path defaultUserDataDirectory() { + return detectExistingUserDataDirectory().orElseGet(() -> userDataCandidates().getFirst()); + } + + public static Path defaultGameDirectory() { + return detectExistingGameDirectory().orElseGet(() -> gameCandidates().getFirst()); + } + + public static Path defaultJavaExecutable() { + return detectExistingJavaExecutable().orElseGet(HytalePathDetector::currentJavaExecutable); + } + + public static Optional detectExistingJavaExecutable() { + return javaExecutableCandidates().stream().filter(Files::isRegularFile).findFirst(); + } + + public static Optional detectExistingGameDirectory() { + return gameCandidates().stream().filter(HytalePathDetector::containsClientExecutable).findFirst(); + } + + public static List candidates() { + return userDataCandidates().stream() + .flatMap(path -> java.util.stream.Stream.of(path.resolve("Mods"), path.resolve("mods"), path.resolve(Path.of("userdata", "mods")))) + .distinct() + .toList(); + } + + public static List userDataCandidates() { + return hytaleDataDirectoryCandidates().stream() + .flatMap(path -> Stream.of(path.resolve("UserData"), path.resolve("userdata"), path)) + .distinct() + .toList(); + } + + public static List gameCandidates() { + List paths = new ArrayList<>(); + hytaleDataDirectoryCandidates().forEach(root -> { + paths.add(root.resolve(Path.of("install", "release", "package", "game", "latest"))); + paths.add(root.resolve(Path.of("install", "pre-release", "package", "game", "latest"))); + paths.add(root.resolve(Path.of("install", "prerelease", "package", "game", "latest"))); + paths.add(root.resolve(Path.of("install", "release", "package", "game"))); + paths.add(root.resolve(Path.of("install", "pre-release", "package", "game"))); + paths.add(root.resolve(Path.of("install", "prerelease", "package", "game"))); + paths.add(root); + }); + + String home = System.getProperty("user.home", "."); + paths.add(Path.of(home, "Hytale", "Game")); + paths.add(Path.of(home, "Hytale")); + paths.add(Path.of(home, ".modtale", "launcher", "hytale")); + return paths.stream().distinct().toList(); + } + + public static List javaExecutableCandidates() { + String executable = javaExecutableName(); + List paths = new ArrayList<>(); + hytaleDataDirectoryCandidates().forEach(root -> { + paths.add(root.resolve(Path.of("install", "release", "package", "jre", "latest", "bin", executable))); + paths.add(root.resolve(Path.of("install", "pre-release", "package", "jre", "latest", "bin", executable))); + paths.add(root.resolve(Path.of("install", "prerelease", "package", "jre", "latest", "bin", executable))); + paths.add(root.resolve(Path.of("jre", "latest", "bin", executable))); + }); + paths.add(currentJavaExecutable()); + return paths.stream().distinct().toList(); + } + + public static boolean isCurrentJavaExecutable(Path path) { + if (path == null) { + return false; + } + return path.toAbsolutePath().normalize().equals(currentJavaExecutable().toAbsolutePath().normalize()); + } + + public static List hytaleDataDirectoryCandidates() { + String home = System.getProperty("user.home", "."); + String os = System.getProperty("os.name", "").toLowerCase(Locale.ROOT); + List paths = new ArrayList<>(); + + if (os.contains("win")) { + addEnvPath(paths, "APPDATA", "Hytale"); + paths.add(Path.of(home, "AppData", "Roaming", "Hytale")); + addEnvPath(paths, "LOCALAPPDATA", "Hytale"); + addEnvPath(paths, "ProgramFiles", "Hypixel Studios", "Hytale Launcher"); + paths.add(Path.of("C:", "Program Files", "Hypixel Studios", "Hytale Launcher")); + } else if (os.contains("mac")) { + paths.add(Path.of(home, "Library", "Application Support", "Hytale")); + paths.add(Path.of("/", "Applications", "Hytale Launcher.app", "Contents", "MacOS")); + } else { + String xdgDataHome = System.getenv("XDG_DATA_HOME"); + if (xdgDataHome != null && !xdgDataHome.isBlank()) { + paths.add(Path.of(xdgDataHome, "Hytale")); + } + paths.add(Path.of(home, ".var", "app", "com.hypixel.HytaleLauncher", "data", "Hytale")); + paths.add(Path.of(home, ".local", "share", "Hytale")); + paths.add(Path.of(home, ".config", "Hytale")); + paths.add(Path.of(home, ".hytale")); + } + + paths.add(Path.of(home, "Hytale")); + return paths.stream().distinct().toList(); + } + + private static Path currentJavaExecutable() { + return Path.of(System.getProperty("java.home", "."), "bin", javaExecutableName()); + } + + private static String javaExecutableName() { + String executable = System.getProperty("os.name", "").toLowerCase(Locale.ROOT).contains("win") + ? "java.exe" + : "java"; + return executable; + } + + private static void addEnvPath(List paths, String variable, String first, String... more) { + String value = System.getenv(variable); + if (value != null && !value.isBlank()) { + paths.add(Path.of(value, first).resolve(Path.of("", more))); + } + } + + public static Optional detectExistingModsDirectory() { + return candidates().stream().filter(Files::isDirectory).findFirst(); + } + + public static Optional detectExistingSavesDirectory() { + return userDataCandidates().stream() + .flatMap(path -> java.util.stream.Stream.of(path.resolve("Saves"), path.resolve("saves"))) + .filter(Files::isDirectory) + .findFirst(); + } + + public static Optional detectExistingUserDataDirectory() { + return userDataCandidates().stream().filter(Files::isDirectory).findFirst(); + } + + public static boolean containsClientExecutable(Path path) { + String os = System.getProperty("os.name", "").toLowerCase(Locale.ROOT); + if (os.contains("mac")) { + return Files.isRegularFile(path.resolve(Path.of("Client", "Hytale.app", "Contents", "MacOS", "HytaleClient"))); + } + if (os.contains("win")) { + return Files.isRegularFile(path.resolve(Path.of("Client", "HytaleClient.exe"))); + } + return Files.isRegularFile(path.resolve(Path.of("Client", "HytaleClient"))); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/settings/InstalledProjectRegistry.java b/launcher/src/main/java/net/modtale/launcher/settings/InstalledProjectRegistry.java new file mode 100644 index 00000000..461cd166 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/settings/InstalledProjectRegistry.java @@ -0,0 +1,111 @@ +package net.modtale.launcher.settings; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import net.modtale.launcher.api.ModtaleApiException; +import net.modtale.launcher.model.install.InstalledProject; + +final class InstalledProjectRegistry { + + private static final String REGISTRY_FILE = "installed-projects.json"; + + private final Path registryPath; + private final ObjectMapper mapper; + + InstalledProjectRegistry(Path launcherDirectory, ObjectMapper mapper) { + Path directory = launcherDirectory == null ? Path.of(".") : launcherDirectory; + this.registryPath = directory.resolve(REGISTRY_FILE); + this.mapper = mapper; + } + + List merge(List projects) { + Map merged = new LinkedHashMap<>(); + for (InstalledProject project : validProjects(projects)) { + merged.put(project.projectId(), project); + } + for (InstalledProject project : load()) { + if (hasAnyRecordedFile(project)) { + merged.putIfAbsent(project.projectId(), project); + } + } + return List.copyOf(merged.values()); + } + + void save(List projects) { + List records = validProjects(projects); + try { + Files.createDirectories(registryPath.getParent()); + mapper.writeValue(registryPath.toFile(), new RegistryFile(records)); + } catch (IOException ex) { + throw new ModtaleApiException("Could not save installed project registry to " + registryPath, ex); + } + } + + void remove(String projectId) { + if (projectId == null || projectId.isBlank()) { + return; + } + List remaining = load().stream() + .filter(project -> !projectId.trim().equals(project.projectId())) + .toList(); + save(remaining); + } + + private List load() { + if (!Files.isRegularFile(registryPath)) { + return List.of(); + } + try { + if (Files.size(registryPath) == 0 || Files.readString(registryPath).isBlank()) { + return List.of(); + } + RegistryFile registry = mapper.readValue(registryPath.toFile(), RegistryFile.class); + return validProjects(registry.installedProjects()); + } catch (IOException ex) { + try { + return validProjects(mapper.readValue(registryPath.toFile(), new TypeReference>() { + })); + } catch (IOException ignored) { + throw new ModtaleApiException("Could not load installed project registry from " + registryPath, ex); + } + } + } + + private static List validProjects(List projects) { + if (projects == null || projects.isEmpty()) { + return List.of(); + } + List valid = new ArrayList<>(); + for (InstalledProject project : projects) { + if (project != null && project.projectId() != null && !project.projectId().isBlank()) { + valid.add(project); + } + } + return valid; + } + + private static boolean hasAnyRecordedFile(InstalledProject project) { + if (project.files().isEmpty()) { + return true; + } + return project.files().stream() + .filter(file -> file != null && !file.isBlank()) + .map(Path::of) + .anyMatch(Files::exists); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private record RegistryFile(List installedProjects) { + private RegistryFile { + installedProjects = installedProjects == null ? List.of() : List.copyOf(installedProjects); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/settings/LauncherConfig.java b/launcher/src/main/java/net/modtale/launcher/settings/LauncherConfig.java new file mode 100644 index 00000000..c0afbc6f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/settings/LauncherConfig.java @@ -0,0 +1,133 @@ +package net.modtale.launcher.settings; + +import java.net.URI; +import java.util.Optional; +import net.modtale.launcher.api.ModtaleApiClient; + +public final class LauncherConfig { + + public static final String API_BASE_URL_PROPERTY = "modtale.apiBaseUrl"; + public static final String API_BASE_URL_ENV = "MODTALE_API_BASE_URL"; + public static final String SITE_BASE_URL_PROPERTY = "modtale.siteBaseUrl"; + public static final String SITE_BASE_URL_ENV = "MODTALE_SITE_BASE_URL"; + public static final String LAUNCHER_UPDATES_REPOSITORY_PROPERTY = "modtale.launcherUpdatesRepository"; + public static final String LAUNCHER_UPDATES_REPOSITORY_ENV = "MODTALE_LAUNCHER_UPDATES_REPOSITORY"; + public static final String DISCORD_CLIENT_ID_PROPERTY = "modtale.discordClientId"; + public static final String DISCORD_CLIENT_ID_ENV = "MODTALE_DISCORD_CLIENT_ID"; + public static final String DISCORD_CLIENT_ID_FALLBACK_ENV = "DISCORD_CLIENT_ID"; + public static final String DEFAULT_LAUNCHER_UPDATES_REPOSITORY = "Modtale/modtale"; + + private LauncherConfig() { + } + + public static String siteBaseUrl() { + return normalizeBaseUrl(firstConfiguredValue(SITE_BASE_URL_PROPERTY, SITE_BASE_URL_ENV), + ModtaleApiClient.DEFAULT_SITE_BASE_URL, + "Modtale website URL"); + } + + public static String apiBaseUrl() { + return normalizeBaseUrl(firstConfiguredValue(API_BASE_URL_PROPERTY, API_BASE_URL_ENV), + ModtaleApiClient.DEFAULT_API_BASE_URL, + "Modtale API URL"); + } + + public static String launcherUpdatesRepository() { + String value = firstConfiguredValue(LAUNCHER_UPDATES_REPOSITORY_PROPERTY, LAUNCHER_UPDATES_REPOSITORY_ENV); + return normalizeLauncherUpdatesRepository(value); + } + + public static Optional discordClientId() { + String value = firstConfiguredValue(DISCORD_CLIENT_ID_PROPERTY, DISCORD_CLIENT_ID_ENV); + if (value == null) { + value = environmentValue(DISCORD_CLIENT_ID_FALLBACK_ENV); + } + return normalizeDiscordClientId(value); + } + + static String normalizeSiteBaseUrl(String rawValue) { + return normalizeBaseUrl(rawValue, ModtaleApiClient.DEFAULT_SITE_BASE_URL, "Modtale website URL"); + } + + static String normalizeApiBaseUrl(String rawValue) { + return normalizeBaseUrl(rawValue, ModtaleApiClient.DEFAULT_API_BASE_URL, "Modtale API URL"); + } + + public static String normalizeLauncherUpdatesRepository(String rawValue) { + String value = rawValue == null || rawValue.isBlank() + ? DEFAULT_LAUNCHER_UPDATES_REPOSITORY + : rawValue.trim(); + if (!value.matches("[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+")) { + throw new IllegalArgumentException("Launcher update repository must use owner/repo format."); + } + return value; + } + + public static Optional normalizeDiscordClientId(String rawValue) { + String value = rawValue == null ? "" : rawValue.trim(); + if (value.isBlank() || "dev".equalsIgnoreCase(value)) { + return Optional.empty(); + } + return value.matches("\\d{8,32}") ? Optional.of(value) : Optional.empty(); + } + + private static String normalizeBaseUrl(String rawValue, String defaultValue, String label) { + String value = rawValue == null || rawValue.isBlank() + ? defaultValue + : rawValue.trim(); + if (!value.contains("://")) { + value = defaultScheme(value) + "://" + value; + } + + URI uri = URI.create(value); + String scheme = uri.getScheme(); + if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { + throw new IllegalArgumentException("The " + label + " must start with http:// or https://."); + } + if (uri.getHost() == null || uri.getHost().isBlank()) { + throw new IllegalArgumentException("Enter a valid " + label + "."); + } + return value.replaceAll("/+$", ""); + } + + private static String defaultScheme(String value) { + String host = value; + int pathIndex = host.indexOf('/'); + if (pathIndex >= 0) { + host = host.substring(0, pathIndex); + } + if (host.startsWith("[") && host.contains("]")) { + host = host.substring(1, host.indexOf(']')); + } else { + int portIndex = host.indexOf(':'); + if (portIndex >= 0) { + host = host.substring(0, portIndex); + } + } + + String normalizedHost = host.toLowerCase(java.util.Locale.ROOT); + if ("localhost".equals(normalizedHost) + || "127.0.0.1".equals(normalizedHost) + || "::1".equals(normalizedHost)) { + return "http"; + } + return "https"; + } + + private static String firstConfiguredValue(String systemPropertyName, String environmentVariableName) { + String systemProperty = System.getProperty(systemPropertyName); + if (systemProperty != null && !systemProperty.isBlank()) { + return systemProperty; + } + + String environmentValue = environmentValue(environmentVariableName); + if (environmentValue != null && !environmentValue.isBlank()) { + return environmentValue; + } + return null; + } + + private static String environmentValue(String environmentVariableName) { + return System.getenv(environmentVariableName); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/settings/LauncherSettings.java b/launcher/src/main/java/net/modtale/launcher/settings/LauncherSettings.java new file mode 100644 index 00000000..0af80858 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/settings/LauncherSettings.java @@ -0,0 +1,534 @@ +package net.modtale.launcher.settings; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import net.modtale.launcher.hytale.HytaleApiClient; +import net.modtale.launcher.hytale.HytaleAuthSession; +import net.modtale.launcher.hytale.HytaleVersion; +import net.modtale.launcher.model.install.InstalledProject; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class LauncherSettings { + + private String lastUsername = ""; + private String hytaleModsPath = HytalePathDetector.defaultModsDirectory().toString(); + private String hytaleGamePath = HytalePathDetector.defaultGameDirectory().toString(); + private String hytaleUserDataPath = HytalePathDetector.defaultUserDataDirectory().toString(); + private String hytaleJavaPath = HytalePathDetector.defaultJavaExecutable().toString(); + private String hytaleBranch = "release"; + private int hytaleBuild; + private long hytalePlaytimeSeconds; + private HytaleAuthSession hytaleAuthSession; + private List hytaleAuthSessions = new ArrayList<>(); + private String activeHytaleAccountId = ""; + private String gameVersion = ""; + private boolean includeDependencies = true; + private boolean includeOptionalDependencies; + private boolean autoCheckUpdates = true; + private boolean launcherAutoUpdates; + private List hytalePatchlineCaches = new ArrayList<>(); + private List hytaleVersionCaches = new ArrayList<>(); + private List installedProjects = new ArrayList<>(); + + public String getLastUsername() { + return lastUsername; + } + + public void setLastUsername(String lastUsername) { + this.lastUsername = lastUsername == null ? "" : lastUsername.trim(); + } + + public String getHytaleModsPath() { + return hytaleModsPath; + } + + public void setHytaleModsPath(String hytaleModsPath) { + this.hytaleModsPath = hytaleModsPath == null ? "" : hytaleModsPath.trim(); + } + + public Path hytaleModsDirectory() { + return Path.of(hytaleModsPath); + } + + public String getHytaleGamePath() { + return hytaleGamePath; + } + + public void setHytaleGamePath(String hytaleGamePath) { + this.hytaleGamePath = hytaleGamePath == null ? "" : hytaleGamePath.trim(); + } + + public Path hytaleGameDirectory() { + return Path.of(hytaleGamePath); + } + + public String getHytaleUserDataPath() { + return hytaleUserDataPath; + } + + public void setHytaleUserDataPath(String hytaleUserDataPath) { + this.hytaleUserDataPath = hytaleUserDataPath == null ? "" : hytaleUserDataPath.trim(); + } + + public Path hytaleUserDataDirectory() { + return Path.of(hytaleUserDataPath); + } + + public String getHytaleJavaPath() { + return hytaleJavaPath; + } + + public void setHytaleJavaPath(String hytaleJavaPath) { + this.hytaleJavaPath = hytaleJavaPath == null || hytaleJavaPath.isBlank() + ? HytalePathDetector.defaultJavaExecutable().toString() + : hytaleJavaPath.trim(); + } + + public Path hytaleJavaExecutable() { + return Path.of(hytaleJavaPath); + } + + public String getHytaleBranch() { + return hytaleBranch; + } + + public void setHytaleBranch(String hytaleBranch) { + this.hytaleBranch = HytaleApiClient.normalizeBranch(hytaleBranch); + } + + public int getHytaleBuild() { + return hytaleBuild; + } + + public void setHytaleBuild(int hytaleBuild) { + this.hytaleBuild = Math.max(0, hytaleBuild); + } + + public long getHytalePlaytimeSeconds() { + return Math.max(0, hytalePlaytimeSeconds); + } + + public void setHytalePlaytimeSeconds(long hytalePlaytimeSeconds) { + this.hytalePlaytimeSeconds = Math.max(0, hytalePlaytimeSeconds); + } + + public void addHytalePlaytimeSeconds(long seconds) { + if (seconds <= 0) { + return; + } + this.hytalePlaytimeSeconds = Math.max(0, this.hytalePlaytimeSeconds + seconds); + } + + public List getHytalePatchlineCaches() { + return hytalePatchlineCaches; + } + + public void setHytalePatchlineCaches(List hytalePatchlineCaches) { + this.hytalePatchlineCaches = hytalePatchlineCaches == null ? new ArrayList<>() : new ArrayList<>(hytalePatchlineCaches); + } + + public List getHytaleVersionCaches() { + return hytaleVersionCaches; + } + + public void setHytaleVersionCaches(List hytaleVersionCaches) { + this.hytaleVersionCaches = hytaleVersionCaches == null ? new ArrayList<>() : new ArrayList<>(hytaleVersionCaches); + } + + public List cachedHytalePatchlines(String accountId, String platform) { + String accountKey = cacheValue(accountId); + String platformKey = cacheValue(platform); + return hytalePatchlineCaches.stream() + .filter(entry -> accountKey.equals(cacheValue(entry.getAccountId())) + && platformKey.equals(cacheValue(entry.getPlatform()))) + .findFirst() + .map(HytalePatchlineCacheEntry::getPatchlines) + .orElse(List.of()); + } + + public List pendingHytalePatchlines(String accountId, String platform) { + String accountKey = cacheValue(accountId); + String platformKey = cacheValue(platform); + return hytalePatchlineCaches.stream() + .filter(entry -> accountKey.equals(cacheValue(entry.getAccountId())) + && platformKey.equals(cacheValue(entry.getPlatform()))) + .findFirst() + .map(HytalePatchlineCacheEntry::getPendingPatchlines) + .orElse(List.of()); + } + + public void cacheHytalePatchlines(String accountId, String platform, List patchlines) { + String accountKey = cacheValue(accountId); + String platformKey = cacheValue(platform); + HytalePatchlineCacheEntry entry = hytalePatchlineCacheEntry(accountKey, platformKey); + entry.setAccountId(accountKey); + entry.setPlatform(platformKey); + entry.setFetchedAt(System.currentTimeMillis()); + entry.setPatchlines(patchlines); + } + + public void cachePendingHytalePatchlines(String accountId, String platform, List pendingPatchlines) { + String accountKey = cacheValue(accountId); + String platformKey = cacheValue(platform); + HytalePatchlineCacheEntry entry = hytalePatchlineCacheEntry(accountKey, platformKey); + entry.setAccountId(accountKey); + entry.setPlatform(platformKey); + entry.setPendingPatchlines(pendingPatchlines); + } + + public List cachedHytaleVersions(String accountId, String platform, String patchline) { + String accountKey = cacheValue(accountId); + String platformKey = cacheValue(platform); + String patchlineKey = HytaleApiClient.normalizeBranch(patchline); + return hytaleVersionCaches.stream() + .filter(entry -> accountKey.equals(cacheValue(entry.getAccountId())) + && platformKey.equals(cacheValue(entry.getPlatform())) + && patchlineKey.equals(HytaleApiClient.normalizeBranch(entry.getPatchline()))) + .findFirst() + .map(HytaleVersionCacheEntry::getVersions) + .orElse(List.of()); + } + + public void cacheHytaleVersions(String accountId, String platform, String patchline, List versions) { + String accountKey = cacheValue(accountId); + String platformKey = cacheValue(platform); + String patchlineKey = HytaleApiClient.normalizeBranch(patchline); + hytaleVersionCaches.removeIf(entry -> accountKey.equals(cacheValue(entry.getAccountId())) + && platformKey.equals(cacheValue(entry.getPlatform())) + && patchlineKey.equals(HytaleApiClient.normalizeBranch(entry.getPatchline()))); + HytaleVersionCacheEntry entry = new HytaleVersionCacheEntry(); + entry.setAccountId(accountKey); + entry.setPlatform(platformKey); + entry.setPatchline(patchlineKey); + entry.setFetchedAt(System.currentTimeMillis()); + entry.setVersions(versions); + hytaleVersionCaches.add(entry); + } + + public HytaleAuthSession getHytaleAuthSession() { + normalizeHytaleAuthSessions(); + if (!activeHytaleAccountId.isBlank()) { + for (HytaleAuthSession session : hytaleAuthSessions) { + if (activeHytaleAccountId.equals(hytaleAccountId(session))) { + return session; + } + } + } + if (!hytaleAuthSessions.isEmpty()) { + HytaleAuthSession session = hytaleAuthSessions.getFirst(); + activeHytaleAccountId = hytaleAccountId(session); + hytaleAuthSession = session; + return session; + } + return hytaleAuthSession; + } + + public void setHytaleAuthSession(HytaleAuthSession hytaleAuthSession) { + this.hytaleAuthSession = hytaleAuthSession; + if (hytaleAuthSession == null) { + activeHytaleAccountId = ""; + return; + } + upsertHytaleAuthSession(hytaleAuthSession); + } + + public List getHytaleAuthSessions() { + normalizeHytaleAuthSessions(); + return List.copyOf(hytaleAuthSessions); + } + + public void setHytaleAuthSessions(List hytaleAuthSessions) { + this.hytaleAuthSessions = hytaleAuthSessions == null ? new ArrayList<>() : new ArrayList<>(hytaleAuthSessions); + normalizeHytaleAuthSessions(); + } + + public String getActiveHytaleAccountId() { + normalizeHytaleAuthSessions(); + return activeHytaleAccountId; + } + + public void setActiveHytaleAccountId(String activeHytaleAccountId) { + this.activeHytaleAccountId = activeHytaleAccountId == null ? "" : activeHytaleAccountId.trim(); + normalizeHytaleAuthSessions(); + } + + public void upsertHytaleAuthSession(HytaleAuthSession session) { + if (session == null) { + return; + } + String accountId = hytaleAccountId(session); + hytaleAuthSessions.removeIf(existing -> hytaleAccountId(existing).equals(accountId)); + hytaleAuthSessions.add(session); + activeHytaleAccountId = accountId; + hytaleAuthSession = session; + } + + public void selectHytaleAccount(String accountId) { + if (accountId == null || accountId.isBlank()) { + return; + } + normalizeHytaleAuthSessions(); + for (HytaleAuthSession session : hytaleAuthSessions) { + if (accountId.equals(hytaleAccountId(session))) { + activeHytaleAccountId = accountId; + hytaleAuthSession = session; + return; + } + } + } + + public void removeActiveHytaleAuthSession() { + normalizeHytaleAuthSessions(); + String accountId = activeHytaleAccountId; + if (accountId.isBlank() && hytaleAuthSession != null) { + accountId = hytaleAccountId(hytaleAuthSession); + } + removeHytaleAuthSession(accountId); + } + + public void removeHytaleAuthSession(String accountId) { + if (accountId == null || accountId.isBlank()) { + return; + } + normalizeHytaleAuthSessions(); + String selectedAccountId = accountId.trim(); + String previousActiveAccountId = activeHytaleAccountId; + hytaleAuthSessions.removeIf(existing -> hytaleAccountId(existing).equals(selectedAccountId)); + hytaleAuthSession = null; + activeHytaleAccountId = ""; + if (!hytaleAuthSessions.isEmpty()) { + HytaleAuthSession next = hytaleAuthSessions.stream() + .filter(session -> hytaleAccountId(session).equals(previousActiveAccountId)) + .findFirst() + .orElse(hytaleAuthSessions.getFirst()); + hytaleAuthSession = next; + activeHytaleAccountId = hytaleAccountId(next); + } + } + + public void normalizeHytaleAuthSessions() { + if (hytaleAuthSessions == null) { + hytaleAuthSessions = new ArrayList<>(); + } + if (hytaleAuthSession != null) { + String legacyId = hytaleAccountId(hytaleAuthSession); + boolean known = hytaleAuthSessions.stream() + .anyMatch(existing -> hytaleAccountId(existing).equals(legacyId)); + if (!known) { + hytaleAuthSessions.add(hytaleAuthSession); + } + } + hytaleAuthSessions.removeIf(session -> session == null || hytaleAccountId(session).isBlank()); + if (hytaleAuthSessions.isEmpty()) { + activeHytaleAccountId = ""; + hytaleAuthSession = null; + return; + } + if (activeHytaleAccountId == null || activeHytaleAccountId.isBlank() + || hytaleAuthSessions.stream().noneMatch(session -> activeHytaleAccountId.equals(hytaleAccountId(session)))) { + activeHytaleAccountId = hytaleAccountId(hytaleAuthSessions.getFirst()); + } + hytaleAuthSession = hytaleAuthSessions.stream() + .filter(session -> activeHytaleAccountId.equals(hytaleAccountId(session))) + .findFirst() + .orElse(hytaleAuthSessions.getFirst()); + } + + public static String hytaleAccountId(HytaleAuthSession session) { + if (session == null) { + return ""; + } + if (session.getAccountOwnerId() != null && !session.getAccountOwnerId().isBlank()) { + return session.getAccountOwnerId().trim(); + } + if (session.getUuid() != null && !session.getUuid().isBlank()) { + return session.getUuid().trim(); + } + return session.getUsername() == null ? "" : session.getUsername().trim(); + } + + public String getGameVersion() { + return gameVersion; + } + + public void setGameVersion(String gameVersion) { + this.gameVersion = gameVersion == null ? "" : gameVersion.trim(); + } + + public boolean isIncludeDependencies() { + return includeDependencies; + } + + public void setIncludeDependencies(boolean includeDependencies) { + this.includeDependencies = includeDependencies; + } + + public boolean isIncludeOptionalDependencies() { + return includeOptionalDependencies; + } + + public void setIncludeOptionalDependencies(boolean includeOptionalDependencies) { + this.includeOptionalDependencies = includeOptionalDependencies; + } + + public boolean isAutoCheckUpdates() { + return autoCheckUpdates; + } + + public void setAutoCheckUpdates(boolean autoCheckUpdates) { + this.autoCheckUpdates = autoCheckUpdates; + } + + public boolean isLauncherAutoUpdates() { + return launcherAutoUpdates; + } + + public void setLauncherAutoUpdates(boolean launcherAutoUpdates) { + this.launcherAutoUpdates = launcherAutoUpdates; + } + + public List getInstalledProjects() { + return installedProjects; + } + + public void setInstalledProjects(List installedProjects) { + this.installedProjects = installedProjects == null + ? new ArrayList<>() + : new ArrayList<>(installedProjects.stream() + .filter(project -> project != null && project.projectId() != null && !project.projectId().isBlank()) + .toList()); + } + + public void upsertInstalledProject(InstalledProject project) { + if (project == null || project.projectId() == null || project.projectId().isBlank()) { + return; + } + installedProjects.removeIf(existing -> existing.projectId().equals(project.projectId())); + installedProjects.add(project); + } + + public void removeInstalledProject(String projectId) { + if (projectId == null || projectId.isBlank()) { + return; + } + installedProjects.removeIf(existing -> existing.projectId().equals(projectId.trim())); + } + + private static String cacheValue(String value) { + return value == null ? "" : value.trim(); + } + + private HytalePatchlineCacheEntry hytalePatchlineCacheEntry(String accountId, String platform) { + String accountKey = cacheValue(accountId); + String platformKey = cacheValue(platform); + for (HytalePatchlineCacheEntry entry : hytalePatchlineCaches) { + if (accountKey.equals(cacheValue(entry.getAccountId())) + && platformKey.equals(cacheValue(entry.getPlatform()))) { + return entry; + } + } + HytalePatchlineCacheEntry entry = new HytalePatchlineCacheEntry(); + hytalePatchlineCaches.add(entry); + return entry; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class HytalePatchlineCacheEntry { + private String accountId = ""; + private String platform = ""; + private long fetchedAt; + private List patchlines = new ArrayList<>(); + private List pendingPatchlines = new ArrayList<>(); + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = cacheValue(accountId); + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = cacheValue(platform); + } + + public long getFetchedAt() { + return fetchedAt; + } + + public void setFetchedAt(long fetchedAt) { + this.fetchedAt = Math.max(0, fetchedAt); + } + + public List getPatchlines() { + return patchlines; + } + + public void setPatchlines(List patchlines) { + this.patchlines = patchlines == null ? new ArrayList<>() : new ArrayList<>(patchlines); + } + + public List getPendingPatchlines() { + return pendingPatchlines; + } + + public void setPendingPatchlines(List pendingPatchlines) { + this.pendingPatchlines = pendingPatchlines == null ? new ArrayList<>() : new ArrayList<>(pendingPatchlines); + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class HytaleVersionCacheEntry { + private String accountId = ""; + private String platform = ""; + private String patchline = "release"; + private long fetchedAt; + private List versions = new ArrayList<>(); + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = cacheValue(accountId); + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = cacheValue(platform); + } + + public String getPatchline() { + return patchline; + } + + public void setPatchline(String patchline) { + this.patchline = HytaleApiClient.normalizeBranch(patchline); + } + + public long getFetchedAt() { + return fetchedAt; + } + + public void setFetchedAt(long fetchedAt) { + this.fetchedAt = Math.max(0, fetchedAt); + } + + public List getVersions() { + return versions; + } + + public void setVersions(List versions) { + this.versions = versions == null ? new ArrayList<>() : new ArrayList<>(versions); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/settings/SettingsStore.java b/launcher/src/main/java/net/modtale/launcher/settings/SettingsStore.java new file mode 100644 index 00000000..2b581626 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/settings/SettingsStore.java @@ -0,0 +1,123 @@ +package net.modtale.launcher.settings; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import net.modtale.launcher.api.ModtaleApiException; + +public class SettingsStore { + + private final Path settingsPath; + private final ObjectMapper mapper; + private final InstalledProjectRegistry installedProjectRegistry; + + public SettingsStore() { + this(defaultSettingsPath()); + } + + public SettingsStore(Path settingsPath) { + this.settingsPath = settingsPath; + this.mapper = new ObjectMapper() + .registerModule(new JavaTimeModule()) + .enable(SerializationFeature.INDENT_OUTPUT) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + this.installedProjectRegistry = new InstalledProjectRegistry(settingsPath.getParent(), mapper); + } + + public LauncherSettings load() { + if (!Files.exists(settingsPath)) { + return saveDefaultSettings(); + } + try { + if (isBlankSettingsFile()) { + return saveDefaultSettings(); + } + LauncherSettings settings = mapper.readValue(settingsPath.toFile(), LauncherSettings.class); + normalize(settings); + settings.setInstalledProjects(installedProjectRegistry.merge(settings.getInstalledProjects())); + return settings; + } catch (IOException ex) { + throw new ModtaleApiException("Could not load launcher settings from " + settingsPath, ex); + } + } + + private LauncherSettings saveDefaultSettings() { + LauncherSettings settings = new LauncherSettings(); + save(settings); + return settings; + } + + private boolean isBlankSettingsFile() throws IOException { + return Files.size(settingsPath) == 0 || Files.readString(settingsPath).isBlank(); + } + + public void save(LauncherSettings settings) { + normalize(settings); + settings.setInstalledProjects(installedProjectRegistry.merge(settings.getInstalledProjects())); + try { + Files.createDirectories(settingsPath.getParent()); + mapper.writeValue(settingsPath.toFile(), settings); + installedProjectRegistry.save(settings.getInstalledProjects()); + } catch (IOException ex) { + throw new ModtaleApiException("Could not save launcher settings to " + settingsPath, ex); + } + } + + public void removeInstalledProject(String projectId) { + installedProjectRegistry.remove(projectId); + } + + public Path settingsPath() { + return settingsPath; + } + + public static Path defaultSettingsPath() { + return defaultLauncherDirectory().resolve("settings.json"); + } + + public static Path defaultSessionPath() { + return defaultLauncherDirectory().resolve("session-cookies.json"); + } + + private static Path defaultLauncherDirectory() { + return Path.of(System.getProperty("user.home", "."), ".modtale", "launcher"); + } + + private static void normalize(LauncherSettings settings) { + if (settings.getHytaleModsPath() == null || settings.getHytaleModsPath().isBlank()) { + settings.setHytaleModsPath(HytalePathDetector.defaultModsDirectory().toString()); + } + if (settings.getHytaleGamePath() == null || settings.getHytaleGamePath().isBlank()) { + settings.setHytaleGamePath(HytalePathDetector.defaultGameDirectory().toString()); + } else if (!HytalePathDetector.containsClientExecutable(settings.hytaleGameDirectory())) { + HytalePathDetector.detectExistingGameDirectory() + .ifPresent(path -> settings.setHytaleGamePath(path.toString())); + } + if (settings.getHytaleUserDataPath() == null || settings.getHytaleUserDataPath().isBlank()) { + settings.setHytaleUserDataPath(HytalePathDetector.defaultUserDataDirectory().toString()); + } + if (settings.getHytaleJavaPath() == null || settings.getHytaleJavaPath().isBlank()) { + settings.setHytaleJavaPath(HytalePathDetector.defaultJavaExecutable().toString()); + } else if (HytalePathDetector.isCurrentJavaExecutable(settings.hytaleJavaExecutable())) { + HytalePathDetector.detectExistingJavaExecutable() + .filter(path -> !HytalePathDetector.isCurrentJavaExecutable(path)) + .ifPresent(path -> settings.setHytaleJavaPath(path.toString())); + } + if (settings.getHytaleBranch() == null || settings.getHytaleBranch().isBlank()) { + settings.setHytaleBranch("release"); + } + if (settings.getInstalledProjects() == null) { + settings.setInstalledProjects(java.util.List.of()); + } + if (settings.getHytalePatchlineCaches() == null) { + settings.setHytalePatchlineCaches(java.util.List.of()); + } + if (settings.getHytaleVersionCaches() == null) { + settings.setHytaleVersionCaches(java.util.List.of()); + } + settings.normalizeHytaleAuthSessions(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/sync/LauncherPreferenceSyncDialog.java b/launcher/src/main/java/net/modtale/launcher/sync/LauncherPreferenceSyncDialog.java new file mode 100644 index 00000000..ea0c3def --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/sync/LauncherPreferenceSyncDialog.java @@ -0,0 +1,132 @@ +package net.modtale.launcher.sync; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.function.Supplier; +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.ui.common.StatusModal; + +final class LauncherPreferenceSyncDialog { + + private static final DateTimeFormatter SAVED_AT_FORMAT = + DateTimeFormatter.ofPattern("MMM d, yyyy 'at' h:mm a"); + + private final int remoteProjects; + private final int localProjects; + private final String updatedAt; + + private LauncherPreferenceSyncDialog( + int remoteProjects, + int localProjects, + String updatedAt + ) { + this.remoteProjects = Math.max(0, remoteProjects); + this.localProjects = Math.max(0, localProjects); + this.updatedAt = updatedAt == null ? "" : updatedAt.trim(); + } + + static boolean showAndWait( + Supplier host, + int remoteProjects, + int localProjects, + String updatedAt + ) { + LauncherPreferenceSyncDialog dialog = new LauncherPreferenceSyncDialog( + remoteProjects, + localProjects, + updatedAt + ); + StatusModal.Result result = StatusModal.builder(host) + .type(StatusModal.Type.INFO) + .title("Different preferences found") + .message("Your Modtale account has launcher preferences that differ from this device.") + .secondaryLabel("Use this device") + .actionLabel("Load from Modtale") + .content(dialog.summaryCard()) + .showAndWait(); + return result == StatusModal.Result.PRIMARY; + } + + private VBox summaryCard() { + VBox summary = new VBox(8); + summary.getStyleClass().add("preference-sync-summary"); + summary.setAlignment(Pos.CENTER); + summary.getChildren().add(summaryLine("Modtale account", + remoteProjects + " installed project" + plural(remoteProjects))); + summary.getChildren().add(summaryLine("This device", + localProjects + " installed project" + plural(localProjects))); + summary.getChildren().add(summaryLine("Last saved", savedAtLabel())); + return summary; + } + + private HBox summaryLine(String labelText, String valueText) { + HBox row = new HBox(10); + row.setAlignment(Pos.CENTER); + Label label = new Label(labelText); + label.getStyleClass().add("preference-sync-summary-label"); + label.setAlignment(Pos.CENTER); + Label value = new Label(valueText); + value.getStyleClass().add("preference-sync-summary-value"); + value.setAlignment(Pos.CENTER); + row.getChildren().addAll(label, value); + return row; + } + + private String savedAtLabel() { + if (updatedAt.isBlank()) { + return "Previously saved"; + } + for (DateParser parser : new DateParser[]{ + this::parseLocalDateTime, + this::parseOffsetDateTime, + this::parseInstant + }) { + String formatted = parser.parse(updatedAt); + if (!formatted.isBlank()) { + return formatted; + } + } + return updatedAt; + } + + private String parseLocalDateTime(String value) { + try { + return SAVED_AT_FORMAT.format(LocalDateTime.parse(value)); + } catch (DateTimeParseException ignored) { + return ""; + } + } + + private String parseOffsetDateTime(String value) { + try { + return SAVED_AT_FORMAT.format(OffsetDateTime.parse(value).toLocalDateTime()); + } catch (DateTimeParseException ignored) { + return ""; + } + } + + private String parseInstant(String value) { + try { + return SAVED_AT_FORMAT.format(LocalDateTime.ofInstant(Instant.parse(value), ZoneId.systemDefault())); + } catch (DateTimeParseException ignored) { + return ""; + } + } + + private static String plural(int count) { + return count == 1 ? "" : "s"; + } + + @FunctionalInterface + private interface DateParser { + String parse(String value); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/sync/LauncherSettingsSyncService.java b/launcher/src/main/java/net/modtale/launcher/sync/LauncherSettingsSyncService.java new file mode 100644 index 00000000..acc2e2e7 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/sync/LauncherSettingsSyncService.java @@ -0,0 +1,335 @@ +package net.modtale.launcher.sync; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; +import javafx.scene.layout.StackPane; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.api.ModtaleApiException; +import net.modtale.launcher.install.ModInstaller; +import net.modtale.launcher.install.VersionSelector; +import net.modtale.launcher.model.install.InstallOptions; +import net.modtale.launcher.model.install.InstallResult; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.model.sync.LauncherSettingsSnapshot; +import net.modtale.launcher.settings.LauncherSettings; +import net.modtale.launcher.settings.SettingsStore; +import net.modtale.launcher.ui.feedback.LauncherFeedback; +import net.modtale.launcher.ui.settings.LauncherSettingsController; + +public final class LauncherSettingsSyncService { + + private final ModtaleApiClient apiClient; + private final SettingsStore settingsStore; + private final LauncherSettingsController settingsController; + private final ModInstaller installer; + private final LauncherFeedback feedback; + private final BooleanSupplier signedIn; + private final Supplier overlayHost; + private final AtomicBoolean checking = new AtomicBoolean(); + private final AtomicBoolean uploading = new AtomicBoolean(); + + private volatile String lastKnownRemoteHash = ""; + private volatile String lastKnownRemoteInstalledProjectsHash = ""; + + public LauncherSettingsSyncService( + ModtaleApiClient apiClient, + SettingsStore settingsStore, + LauncherSettingsController settingsController, + ModInstaller installer, + LauncherFeedback feedback, + BooleanSupplier signedIn, + Supplier overlayHost + ) { + this.apiClient = apiClient; + this.settingsStore = settingsStore; + this.settingsController = settingsController; + this.installer = installer; + this.feedback = feedback; + this.signedIn = signedIn == null ? () -> false : signedIn; + this.overlayHost = overlayHost == null ? () -> null : overlayHost; + } + + public void checkOnSignIn() { + if (!signedIn.getAsBoolean() || !checking.compareAndSet(false, true)) { + return; + } + feedback.runAsync("Checking launcher preferences...", + apiClient::getLauncherSettings, + remote -> { + checking.set(false); + handleRemoteSnapshot(remote); + }, + error -> checking.set(false)); + } + + public void syncAfterLocalChange() { + if (!signedIn.getAsBoolean() || checking.get()) { + return; + } + LauncherSettingsSnapshot local = LauncherSettingsSnapshot.fromSettings(settingsController.settings()); + String localHash = local.computeHash(); + if (localHash.equals(lastKnownRemoteHash)) { + return; + } + if (canUploadPreferencesOnly(local)) { + uploadPreferences(local, false); + } else { + uploadSnapshot(local, false); + } + } + + private void handleRemoteSnapshot(LauncherSettingsSnapshot remote) { + LauncherSettingsSnapshot local = LauncherSettingsSnapshot.fromSettings(settingsController.settings()); + if (remote == null || !remote.hasSyncedContent()) { + uploadSnapshot(local, false); + return; + } + + String localHash = local.computeHash(); + if (hashMatches(remote, localHash)) { + lastKnownRemoteHash = localHash; + lastKnownRemoteInstalledProjectsHash = local.installedProjectsHash(); + return; + } + + lastKnownRemoteHash = remote.effectiveHash(); + lastKnownRemoteInstalledProjectsHash = remote.installedProjectsHash(); + if (promptLoadRemote(remote, local)) { + restoreSnapshot(remote); + } else { + uploadSnapshot(local, true); + } + } + + private boolean promptLoadRemote(LauncherSettingsSnapshot remote, LauncherSettingsSnapshot local) { + return LauncherPreferenceSyncDialog.showAndWait( + overlayHost, + remote.installedProjects().size(), + local.installedProjects().size(), + remote.getUpdatedAt() + ); + } + + private void restoreSnapshot(LauncherSettingsSnapshot snapshot) { + feedback.runAsync("Loading launcher preferences from Modtale...", + () -> restore(snapshot), + result -> { + LauncherSettingsSnapshot local = LauncherSettingsSnapshot.fromSettings(settingsController.settings()); + lastKnownRemoteHash = local.computeHash(); + lastKnownRemoteInstalledProjectsHash = local.installedProjectsHash(); + settingsController.reloadFromStore(); + feedback.log("Loaded launcher preferences from Modtale."); + feedback.showToast("Preferences loaded", result.message()); + }); + } + + private RestoreResult restore(LauncherSettingsSnapshot snapshot) { + LauncherSettings settings = settingsController.settings(); + List previousInstalls = new ArrayList<>(settings.getInstalledProjects()); + Set remoteProjectIds = remoteProjectIds(snapshot); + List preservedLocalInstalls = previousInstalls.stream() + .filter(project -> !remoteProjectIds.contains(project.projectId())) + .toList(); + deleteRecordedFiles(previousInstalls.stream() + .filter(project -> remoteProjectIds.contains(project.projectId())) + .toList()); + remoteProjectIds.forEach(settingsStore::removeInstalledProject); + + snapshot.applyPreferencesTo(settings); + settings.setInstalledProjects(preservedLocalInstalls); + settingsStore.save(settings); + + int installed = 0; + List warnings = new ArrayList<>(); + for (LauncherSettingsSnapshot.InstalledProjectSnapshot projectSnapshot : snapshot.installedProjects()) { + if (projectSnapshot.getProjectId() == null || projectSnapshot.getProjectId().isBlank()) { + continue; + } + try { + ProjectDetail project = apiClient.getProject(projectSnapshot.getProjectId()); + ProjectVersion version = resolveVersion(project, projectSnapshot, settings); + InstallResult result = installer.install(project, version, installOptions(settings, projectSnapshot)); + settings.upsertInstalledProject(result.installedProject().withModpackUnlocked(projectSnapshot.isModpackUnlocked())); + settingsStore.save(settings); + installed++; + warnings.addAll(result.warnings()); + } catch (RuntimeException ex) { + warnings.add(projectSnapshot.getProjectId() + ": " + ex.getMessage()); + } + } + + if (!warnings.isEmpty()) { + feedback.log("Launcher preference restore warnings: " + String.join(" ", warnings)); + } + return new RestoreResult("Restored " + installed + " installed project" + plural(installed) + + preservedMessage(preservedLocalInstalls.size()) + " and saved preferences."); + } + + private Set remoteProjectIds(LauncherSettingsSnapshot snapshot) { + Set ids = new LinkedHashSet<>(); + for (LauncherSettingsSnapshot.InstalledProjectSnapshot installed : snapshot.installedProjects()) { + if (installed.getProjectId() != null && !installed.getProjectId().isBlank()) { + ids.add(installed.getProjectId().trim()); + } + } + return ids; + } + + private String preservedMessage(int preserved) { + if (preserved <= 0) { + return ""; + } + return " and kept " + preserved + " local install" + plural(preserved); + } + + private ProjectVersion resolveVersion( + ProjectDetail project, + LauncherSettingsSnapshot.InstalledProjectSnapshot installed, + LauncherSettings settings + ) { + if (project == null) { + throw new ModtaleApiException("Project is no longer available."); + } + if (project.versions().isEmpty()) { + project = project.withVersions(apiClient.getProjectVersions(project.routeKey())); + } + if (installed.getInstalledVersionId() != null && !installed.getInstalledVersionId().isBlank()) { + for (ProjectVersion version : project.versions()) { + if (installed.getInstalledVersionId().equals(version.id())) { + return version; + } + } + } + if (installed.getInstalledVersion() != null && !installed.getInstalledVersion().isBlank()) { + for (ProjectVersion version : project.versions()) { + if (installed.getInstalledVersion().equals(version.versionNumber())) { + return version; + } + } + } + String projectTitle = project.title(); + return VersionSelector.latestCompatible(project, effectiveGameVersion(settings, installed)) + .orElseThrow(() -> new ModtaleApiException("No compatible version was found for " + projectTitle)); + } + + private InstallOptions installOptions( + LauncherSettings settings, + LauncherSettingsSnapshot.InstalledProjectSnapshot installed + ) { + if (installed.getBundledProjects() != null && !installed.getBundledProjects().isEmpty()) { + return new InstallOptions( + settings.hytaleModsDirectory(), + effectiveGameVersion(settings, installed), + true, + true, + installed.getBundledProjects().stream() + .map(net.modtale.launcher.model.install.InstalledProjectReference::toDependency) + .toList() + ); + } + return new InstallOptions( + settings.hytaleModsDirectory(), + effectiveGameVersion(settings, installed), + settings.isIncludeDependencies(), + settings.isIncludeOptionalDependencies() + ); + } + + private String effectiveGameVersion( + LauncherSettings settings, + LauncherSettingsSnapshot.InstalledProjectSnapshot installed + ) { + if (installed.getGameVersion() != null && !installed.getGameVersion().isBlank()) { + return installed.getGameVersion(); + } + return settings.getGameVersion(); + } + + private void deleteRecordedFiles(List installedProjects) { + for (InstalledProject installed : installedProjects) { + if (installed == null || installed.files() == null) { + continue; + } + for (String file : installed.files()) { + if (file == null || file.isBlank()) { + continue; + } + try { + Files.deleteIfExists(Path.of(file)); + } catch (IOException ignored) { + // A stale file should not block restoring the account snapshot. + } + } + } + } + + private void uploadSnapshot(LauncherSettingsSnapshot snapshot, boolean announce) { + uploadSnapshot(snapshot, announce, false); + } + + private void uploadPreferences(LauncherSettingsSnapshot snapshot, boolean announce) { + uploadSnapshot(snapshot, announce, true); + } + + private void uploadSnapshot(LauncherSettingsSnapshot snapshot, boolean announce, boolean preferencesOnly) { + if (!signedIn.getAsBoolean()) { + return; + } + snapshot.refreshHash(); + String snapshotHash = snapshot.computeHash(); + if (snapshotHash.equals(lastKnownRemoteHash)) { + return; + } + if (!uploading.compareAndSet(false, true)) { + return; + } + feedback.runAsync("Saving launcher preferences to Modtale...", + () -> preferencesOnly + ? apiClient.updateLauncherSettingsPreferences(snapshot) + : apiClient.updateLauncherSettings(snapshot), + saved -> { + uploading.set(false); + lastKnownRemoteHash = saved == null || hashMatches(saved, snapshotHash) + ? snapshotHash + : saved.effectiveHash(); + lastKnownRemoteInstalledProjectsHash = saved == null || hashMatches(saved, snapshotHash) + ? snapshot.installedProjectsHash() + : saved.installedProjectsHash(); + if (announce) { + feedback.log("Saved this device's launcher preferences to Modtale."); + feedback.showToast("Preferences saved", "This device is now the account snapshot."); + } + }, + error -> uploading.set(false)); + } + + private boolean canUploadPreferencesOnly(LauncherSettingsSnapshot snapshot) { + String installedProjectsHash = snapshot.installedProjectsHash(); + return !lastKnownRemoteInstalledProjectsHash.isBlank() + && installedProjectsHash.equals(lastKnownRemoteInstalledProjectsHash); + } + + private boolean hashMatches(LauncherSettingsSnapshot remote, String localHash) { + if (localHash == null || localHash.isBlank()) { + return false; + } + return localHash.equals(remote.effectiveHash()) || localHash.equals(remote.computeHash()); + } + + private static String plural(int count) { + return count == 1 ? "" : "s"; + } + + private record RestoreResult(String message) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountController.java b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountController.java new file mode 100644 index 00000000..5ea35e73 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountController.java @@ -0,0 +1,301 @@ +package net.modtale.launcher.ui.account; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; +import javafx.application.Platform; +import javafx.scene.control.Label; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.api.ModtaleApiException; +import net.modtale.launcher.model.auth.SignInResponse; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.sync.LauncherSettingsSyncService; +import net.modtale.launcher.ui.feedback.LauncherFeedback; +import net.modtale.launcher.ui.settings.LauncherSettingsController; + +public final class LauncherAccountController { + + private final ModtaleApiClient apiClient; + private final LauncherSettingsController settingsController; + private final Label accountStatus = new Label("Signed out"); + + private LauncherFeedback feedback; + private Runnable onAutoCheckUpdates = () -> { + }; + private Runnable onSignedIn = () -> { + }; + private Runnable onSignedOut = () -> { + }; + private final List> currentUserListeners = new CopyOnWriteArrayList<>(); + private volatile CurrentUser currentUser; + private LauncherSettingsSyncService settingsSyncService; + + public LauncherAccountController( + ModtaleApiClient apiClient, + LauncherSettingsController settingsController + ) { + this.apiClient = apiClient; + this.settingsController = settingsController; + } + + public void attachFeedback(LauncherFeedback feedback) { + this.feedback = feedback; + } + + public void setOnAutoCheckUpdates(Runnable onAutoCheckUpdates) { + this.onAutoCheckUpdates = onAutoCheckUpdates == null ? () -> { + } : onAutoCheckUpdates; + } + + public void setOnSignedIn(Runnable onSignedIn) { + this.onSignedIn = onSignedIn == null ? () -> { + } : onSignedIn; + } + + public void setOnSignedOut(Runnable onSignedOut) { + this.onSignedOut = onSignedOut == null ? () -> { + } : onSignedOut; + } + + public void setSettingsSyncService(LauncherSettingsSyncService settingsSyncService) { + this.settingsSyncService = settingsSyncService; + } + + public Label statusLabel() { + return accountStatus; + } + + public void addCurrentUserListener(Consumer listener) { + if (listener == null) { + return; + } + currentUserListeners.add(listener); + Platform.runLater(() -> listener.accept(currentUser)); + } + + public boolean isSignedIn() { + return currentUser != null; + } + + public CurrentUser currentUser() { + return currentUser; + } + + public String displayName() { + return currentUser == null ? "Signed out" : currentUser.toString(); + } + + public boolean isProjectLiked(String projectId) { + return currentUser != null && currentUser.likesProject(projectId); + } + + public void syncLocalSettings() { + if (settingsSyncService != null) { + settingsSyncService.syncAfterLocalChange(); + } + } + + public String idleStatus() { + return currentUser == null ? "Signed out" : ""; + } + + public CurrentUser ensureSignedIn() { + if (currentUser != null) { + return currentUser; + } + throw new ModtaleApiException("Sign in with Modtale before continuing."); + } + + public void setCurrentUser(CurrentUser user) { + currentUser = user; + Platform.runLater(this::refreshStatus); + if (user != null) { + Platform.runLater(onSignedIn); + } + } + + public void restoreSession() { + if (!apiClient.hasStoredSession()) { + Platform.runLater(onSignedOut); + return; + } + + feedback.runAsync("Checking Modtale session...", + apiClient::currentUser, + user -> completeSignIn(user, true), + error -> { + currentUser = null; + apiClient.clearStoredSession(); + refreshStatus(); + onSignedOut.run(); + feedback.log("Please sign in with Modtale to continue."); + }); + } + + public void signIn() { + signInWithBrowser(); + } + + public void signIn(String username, char[] password, Consumer onResult) { + feedback.runAsync("Signing in with Modtale...", + () -> signInLocally(username, password), + result -> { + if (result.mfaRequired()) { + if (onResult != null) { + onResult.accept(result); + } + feedback.log("Two-factor authentication is required for this account."); + return; + } + completeSignIn(result.user(), true); + feedback.log("Signed in as " + result.user() + ". Downloads and updates will use your Modtale session."); + feedback.showToast("Signed in", "You're connected as " + result.user() + "."); + if (onResult != null) { + onResult.accept(result); + } + }, + error -> { + currentUser = null; + refreshStatus(); + onSignedOut.run(); + if (onResult != null) { + onResult.accept(SignInResult.failed(error.getMessage())); + } + }); + } + + public void validateMfa(String preAuthToken, String code, Consumer onResult) { + feedback.runAsync("Verifying two-factor code...", + () -> completeMfaSignIn(preAuthToken, code), + result -> { + completeSignIn(result.user(), true); + feedback.log("Signed in as " + result.user() + ". Downloads and updates will use your Modtale session."); + feedback.showToast("Signed in", "You're connected as " + result.user() + "."); + if (onResult != null) { + onResult.accept(result); + } + }, + error -> { + if (onResult != null) { + onResult.accept(SignInResult.failed(error.getMessage())); + } + }); + } + + public void signInWithBrowser() { + feedback.runAsync("Opening Modtale sign-in in your browser...", + () -> new LauncherAuthFlow(apiClient).authenticate(), + user -> { + completeSignIn(user, true); + feedback.log("Signed in as " + user + ". Downloads and updates will use your Modtale session."); + feedback.showToast("Signed in", "You're connected as " + user + "."); + }, + error -> { + currentUser = null; + refreshStatus(); + onSignedOut.run(); + }); + } + + public void signInWithOAuthProvider(String provider, String label, Consumer onResult) { + String providerLabel = label == null || label.isBlank() ? "OAuth" : label; + feedback.runAsync("Opening " + providerLabel + " sign-in...", + () -> new LauncherAuthFlow(apiClient).authenticateWithOAuthProvider(provider), + user -> { + completeSignIn(user, true); + feedback.log("Signed in as " + user + " with " + providerLabel + "."); + feedback.showToast("Signed in", "You're connected as " + user + "."); + if (onResult != null) { + onResult.accept(SignInResult.signedIn(user)); + } + }, + error -> { + currentUser = null; + refreshStatus(); + onSignedOut.run(); + if (onResult != null) { + onResult.accept(SignInResult.failed(error.getMessage())); + } + }); + } + + public void signOut() { + feedback.runAsync("Signing out...", () -> { + apiClient.logout(); + return null; + }, ignored -> { + currentUser = null; + refreshStatus(); + feedback.log("Signed out."); + onSignedOut.run(); + }, error -> { + currentUser = null; + apiClient.clearStoredSession(); + refreshStatus(); + onSignedOut.run(); + feedback.log("Local Modtale session cleared."); + }); + } + + private void completeSignIn(CurrentUser user, boolean autoCheckUpdates) { + currentUser = user; + refreshStatus(); + onSignedIn.run(); + if (settingsSyncService != null) { + settingsSyncService.checkOnSignIn(); + } + if (autoCheckUpdates + && settingsController.settings().isAutoCheckUpdates() + && !settingsController.settings().getInstalledProjects().isEmpty()) { + onAutoCheckUpdates.run(); + } + } + + private SignInResult signInLocally(String username, char[] password) { + try { + SignInResponse response = apiClient.signIn(username, password); + if (response != null && response.mfaRequired()) { + return SignInResult.mfa(response.preAuthToken()); + } + return SignInResult.signedIn(apiClient.currentUser()); + } finally { + if (password != null) { + Arrays.fill(password, '\0'); + } + } + } + + private SignInResult completeMfaSignIn(String preAuthToken, String code) { + apiClient.validateMfa(preAuthToken, code); + return SignInResult.signedIn(apiClient.currentUser()); + } + + private void refreshStatus() { + accountStatus.setText(currentUser == null ? "Signed out" : "Signed in as " + currentUser); + currentUserListeners.forEach(listener -> listener.accept(currentUser)); + } + + public record SignInResult(CurrentUser user, boolean mfaRequired, String preAuthToken, String errorMessage) { + + public static SignInResult signedIn(CurrentUser user) { + return new SignInResult(user, false, null, null); + } + + public static SignInResult mfa(String preAuthToken) { + return new SignInResult(null, true, preAuthToken, null); + } + + public static SignInResult failed(String errorMessage) { + return new SignInResult(null, false, null, errorMessage); + } + + public boolean success() { + return user != null; + } + + public boolean failed() { + return errorMessage != null && !errorMessage.isBlank(); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountMenu.java b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountMenu.java new file mode 100644 index 00000000..e647cad2 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAccountMenu.java @@ -0,0 +1,325 @@ +package net.modtale.launcher.ui.account; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; + +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.event.EventTarget; +import javafx.geometry.Bounds; +import javafx.geometry.Insets; +import javafx.geometry.Point2D; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import javafx.stage.Screen; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherOverlaySupport; +import net.modtale.launcher.ui.common.LauncherView; + +public final class LauncherAccountMenu { + + private static final double PROFILE_MENU_ESTIMATED_WIDTH = 256; + private static final double PROFILE_MENU_SCREEN_MARGIN = 8; + private static final double PROFILE_MENU_TOP_OFFSET = 8; + private static final double PROFILE_AVATAR_SIZE = 38; + + private final LauncherAccountController accountController; + private final CachedImageLoader accountImageLoader; + private final Supplier sceneLayer; + private final Consumer showView; + private final Supplier currentView; + private final Runnable showFollowing; + private final Runnable beforeShow; + + private Button menuButton; + private VBox dropdownPanel; + private Label eyebrowLabel; + private Label accountNameLabel; + private VBox actionGroup; + private Region separator; + private VBox dangerGroup; + + public LauncherAccountMenu( + LauncherAccountController accountController, + CachedImageLoader accountImageLoader, + Supplier sceneLayer, + Consumer showView, + Supplier currentView, + Runnable showFollowing, + Runnable beforeShow + ) { + this.accountController = accountController; + this.accountImageLoader = accountImageLoader; + this.sceneLayer = sceneLayer; + this.showView = showView; + this.currentView = currentView; + this.showFollowing = showFollowing; + this.beforeShow = beforeShow; + } + + public Button button() { + if (menuButton == null) { + menuButton = buildButton(); + } + return menuButton; + } + + public VBox panel() { + button(); + return dropdownPanel; + } + + public void hide() { + if (dropdownPanel != null) { + dropdownPanel.setVisible(false); + } + updateSelected(); + } + + public void updateSelected() { + if (menuButton == null) { + return; + } + LauncherView view = currentView.get(); + boolean utilityView = view == LauncherView.UPDATES + || view == LauncherView.NOTIFICATIONS + || view == LauncherView.SETTINGS; + boolean menuShowing = dropdownPanel != null && dropdownPanel.isVisible(); + pseudo(menuButton, "selected", menuShowing || utilityView); + } + + public void hideOnOutsidePress(EventTarget target) { + if (dropdownPanel == null || !dropdownPanel.isVisible()) { + return; + } + if (!LauncherOverlaySupport.eventTargetInside(target, dropdownPanel) + && !LauncherOverlaySupport.eventTargetInside(target, menuButton)) { + hide(); + } + } + + private Button buildButton() { + Label avatarInitial = new Label(initialFor(accountController.displayName())); + ImageView avatarImage = new ImageView(); + avatarImage.getStyleClass().add("avatar-image"); + avatarImage.setFitWidth(PROFILE_AVATAR_SIZE); + avatarImage.setFitHeight(PROFILE_AVATAR_SIZE); + avatarImage.setSmooth(true); + avatarImage.setMouseTransparent(true); + avatarImage.setClip(roundAvatarClip(PROFILE_AVATAR_SIZE)); + avatarImage.setVisible(false); + avatarImage.imageProperty().addListener((observable, oldImage, newImage) -> + avatarImage.setVisible(newImage != null)); + + StackPane avatar = new StackPane(avatarInitial, avatarImage); + avatar.getStyleClass().add("avatar"); + + Button button = new Button(null, avatar); + button.getStyleClass().add("profile-menu-button"); + button.setMnemonicParsing(false); + + dropdownPanel = buildPanel(); + accountController.addCurrentUserListener(user -> { + String displayName = accountController.displayName(); + avatarInitial.setText(initialFor(displayName)); + if (accountNameLabel != null) { + accountNameLabel.setText(displayName); + } + refreshMenuActions(user); + refreshAccountAvatar(user, avatarImage); + }); + button.setOnAction(event -> toggle()); + return button; + } + + private VBox buildPanel() { + eyebrowLabel = new Label("MODTALE ACCOUNT"); + eyebrowLabel.getStyleClass().add("profile-menu-eyebrow"); + accountNameLabel = new Label(accountController.displayName()); + accountNameLabel.getStyleClass().add("profile-menu-name"); + VBox summary = new VBox(4, eyebrowLabel, accountNameLabel); + summary.getStyleClass().add("profile-menu-summary"); + summary.setMaxWidth(Double.MAX_VALUE); + VBox.setMargin(summary, new Insets(0, 8, 8, 8)); + + VBox menuPanel = new VBox(); + menuPanel.getStyleClass().add("profile-dropdown-panel"); + menuPanel.setMinWidth(PROFILE_MENU_ESTIMATED_WIDTH); + menuPanel.setPrefWidth(PROFILE_MENU_ESTIMATED_WIDTH); + menuPanel.setMaxWidth(PROFILE_MENU_ESTIMATED_WIDTH); + menuPanel.setVisible(false); + menuPanel.setManaged(false); + + actionGroup = new VBox(2); + actionGroup.getStyleClass().add("profile-dropdown-action-group"); + VBox.setMargin(actionGroup, new Insets(0, 8, 0, 8)); + + separator = new Region(); + separator.getStyleClass().add("profile-dropdown-separator"); + VBox.setMargin(separator, new Insets(8, 16, 8, 16)); + + dangerGroup = new VBox(); + dangerGroup.getStyleClass().add("profile-dropdown-action-group"); + VBox.setMargin(dangerGroup, new Insets(0, 8, 0, 8)); + + menuPanel.getChildren().addAll(summary, actionGroup, separator, dangerGroup); + refreshMenuActions(accountController.currentUser()); + return menuPanel; + } + + private void refreshMenuActions(CurrentUser user) { + if (eyebrowLabel != null) { + eyebrowLabel.setText("MODTALE ACCOUNT"); + } + if (accountNameLabel != null) { + accountNameLabel.setText(accountController.displayName()); + } + if (actionGroup == null || dangerGroup == null || separator == null) { + return; + } + boolean signedIn = user != null; + actionGroup.getChildren().setAll( + dropdownItem("Library", LauncherIcons.Glyph.LAYERS, () -> showView.accept(LauncherView.LIBRARY), false), + signedIn + ? dropdownItem("Updates", LauncherIcons.Glyph.DOWNLOAD, () -> showView.accept(LauncherView.UPDATES), false) + : dropdownItem("Sign In", LauncherIcons.Glyph.USER, accountController::signIn, false), + signedIn + ? dropdownItem("Notifications", LauncherIcons.Glyph.BELL, () -> showView.accept(LauncherView.NOTIFICATIONS), false) + : dropdownItem("Settings", LauncherIcons.Glyph.SLIDERS, () -> showView.accept(LauncherView.SETTINGS), false) + ); + if (signedIn) { + actionGroup.getChildren().add(dropdownItem("Following", LauncherIcons.Glyph.USER, showFollowing, false)); + actionGroup.getChildren().add(dropdownItem("Settings", LauncherIcons.Glyph.SLIDERS, () -> showView.accept(LauncherView.SETTINGS), false)); + dangerGroup.getChildren().setAll(dropdownItem( + "Sign Out", + LauncherIcons.Glyph.LOG_OUT, + accountController::signOut, + true + )); + } else { + dangerGroup.getChildren().clear(); + } + separator.setVisible(signedIn); + separator.setManaged(signedIn); + dangerGroup.setVisible(signedIn); + dangerGroup.setManaged(signedIn); + } + + private Button dropdownItem( + String label, + LauncherIcons.Glyph icon, + Runnable action, + boolean danger + ) { + Button item = new Button(label); + item.getStyleClass().add("profile-dropdown-item"); + if (danger) { + item.getStyleClass().add("danger"); + } + item.setGraphic(LauncherIcons.icon(icon, 16)); + item.setAlignment(Pos.CENTER_LEFT); + item.setMaxWidth(Double.MAX_VALUE); + item.setOnAction(event -> { + hide(); + if (action != null) { + action.run(); + } + }); + return item; + } + + private void toggle() { + if (dropdownPanel.isVisible()) { + hide(); + return; + } + show(); + } + + private void show() { + StackPane layer = sceneLayer.get(); + if (layer == null || dropdownPanel == null || menuButton == null) { + return; + } + if (beforeShow != null) { + beforeShow.run(); + } + dropdownPanel.applyCss(); + dropdownPanel.autosize(); + position(); + dropdownPanel.setVisible(true); + dropdownPanel.toFront(); + updateSelected(); + Platform.runLater(this::position); + } + + private void position() { + StackPane layer = sceneLayer.get(); + if (layer == null || dropdownPanel == null || menuButton == null) { + return; + } + Bounds anchorBounds = menuButton.localToScene(menuButton.getBoundsInLocal()); + if (anchorBounds == null) { + return; + } + double centerX = anchorBounds.getMinX() + (anchorBounds.getWidth() / 2.0); + double centerY = anchorBounds.getMinY() + (anchorBounds.getHeight() / 2.0); + Point2D avatarBottomRight = layer.sceneToLocal( + centerX + (PROFILE_AVATAR_SIZE / 2.0), + centerY + (PROFILE_AVATAR_SIZE / 2.0) + ); + double width = dropdownPanel.getLayoutBounds().getWidth() > 0 + ? dropdownPanel.getLayoutBounds().getWidth() + : PROFILE_MENU_ESTIMATED_WIDTH; + double maxX = Math.max(PROFILE_MENU_SCREEN_MARGIN, + layer.getWidth() - width - PROFILE_MENU_SCREEN_MARGIN); + double x = LauncherOverlaySupport.clamp( + avatarBottomRight.getX() - width, + PROFILE_MENU_SCREEN_MARGIN, + maxX + ); + double y = avatarBottomRight.getY() + PROFILE_MENU_TOP_OFFSET; + dropdownPanel.relocate(x, y); + } + + private void refreshAccountAvatar(CurrentUser user, ImageView avatarImage) { + String avatarUrl = user == null ? null : user.avatarUrl(); + if (avatarUrl == null || avatarUrl.isBlank()) { + accountImageLoader.clear(avatarImage); + return; + } + double requestedSize = requestedAvatarImageSize(); + accountImageLoader.loadInto(avatarImage, avatarUrl, requestedSize, requestedSize); + } + + private static Rectangle roundAvatarClip(double size) { + Rectangle clip = new Rectangle(size, size); + clip.setArcWidth(size); + clip.setArcHeight(size); + return clip; + } + + private static double requestedAvatarImageSize() { + double scale = Screen.getScreens().stream() + .mapToDouble(screen -> Math.max(screen.getOutputScaleX(), screen.getOutputScaleY())) + .max() + .orElse(1); + return Math.ceil(PROFILE_AVATAR_SIZE * Math.max(1, Math.min(3, scale))); + } + + private static String initialFor(String name) { + if (name == null || name.isBlank() || "Signed out".equals(name)) { + return "M"; + } + return name.trim().substring(0, 1).toUpperCase(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthFlow.java b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthFlow.java new file mode 100644 index 00000000..f094d22f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthFlow.java @@ -0,0 +1,214 @@ +package net.modtale.launcher.ui.account; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpServer; +import java.awt.Desktop; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.time.Duration; +import java.util.Base64; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.settings.LauncherConfig; + +public final class LauncherAuthFlow { + + private static final Duration AUTH_TIMEOUT = Duration.ofMinutes(5); + private static final String APP_NAME = "Modtale Launcher"; + private static final SecureRandom RANDOM = new SecureRandom(); + + private final ModtaleApiClient apiClient; + private final String siteBaseUrl; + + public LauncherAuthFlow(ModtaleApiClient apiClient) { + this.apiClient = apiClient; + this.siteBaseUrl = LauncherConfig.siteBaseUrl(); + } + + public CurrentUser authenticate() { + return authenticate(this::buildAuthUri); + } + + public CurrentUser authenticateWithOAuthProvider(String provider) { + return authenticate((callbackUri, state) -> buildOAuthAuthUri(provider, callbackUri, state)); + } + + private CurrentUser authenticate(AuthUriFactory authUriFactory) { + HttpServer callbackServer = null; + CompletableFuture codeFuture = new CompletableFuture<>(); + try { + String state = randomState(); + callbackServer = HttpServer.create(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0), 0); + callbackServer.createContext("/callback", exchange -> handleCallback(exchange, codeFuture, state)); + callbackServer.setExecutor(null); + callbackServer.start(); + + URI callbackUri = URI.create("http://127.0.0.1:" + callbackServer.getAddress().getPort() + "/callback"); + openBrowser(authUriFactory.build(callbackUri, state)); + + String code = codeFuture.get(AUTH_TIMEOUT.toSeconds(), TimeUnit.SECONDS); + apiClient.exchangeLauncherCode(code); + return apiClient.currentUser(); + } catch (TimeoutException ex) { + throw new RuntimeException("Launcher sign-in timed out. Please try again.", ex); + } catch (CancellationException ex) { + throw ex; + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Launcher sign-in was interrupted.", ex); + } catch (Exception ex) { + if (ex instanceof RuntimeException runtimeException) { + throw runtimeException; + } + throw new RuntimeException(ex.getMessage(), ex); + } finally { + if (callbackServer != null) { + callbackServer.stop(0); + } + } + } + + private URI buildAuthUri(URI callbackUri, String state) { + String base = siteBaseUrl.replaceAll("/+$", ""); + String query = "redirect_uri=" + encode(callbackUri.toString()) + + "&state=" + encode(state) + + "&app_name=" + encode(APP_NAME); + return URI.create(base + "/launcher/auth?" + query); + } + + private URI buildOAuthAuthUri(String provider, URI callbackUri, String state) { + String normalizedProvider = provider == null ? "" : provider.trim().toLowerCase(java.util.Locale.ROOT); + if (!normalizedProvider.matches("[a-z0-9_-]+")) { + throw new RuntimeException("That OAuth provider is not valid."); + } + String base = apiClient.apiBaseUri().toString().replaceAll("/+$", ""); + String query = "redirect_uri=" + encode(callbackUri.toString()) + + "&state=" + encode(state) + + "&app_name=" + encode(APP_NAME); + return URI.create(base + "/auth/launcher/oauth/" + encodePath(normalizedProvider) + "?" + query); + } + + private void handleCallback(HttpExchange exchange, CompletableFuture codeFuture, String expectedState) throws IOException { + Map params = parseQuery(exchange.getRequestURI().getRawQuery()); + String responseTitle = "Launcher sign-in complete"; + String responseMessage = "You can return to Modtale Launcher."; + + String returnedState = params.get("state"); + String code = params.get("code"); + String error = params.get("error"); + if (error != null && !error.isBlank()) { + codeFuture.completeExceptionally(new RuntimeException("Launcher sign-in failed: " + error)); + responseTitle = "Launcher sign-in failed"; + responseMessage = "Return to Modtale Launcher and try again."; + } else if (!expectedState.equals(returnedState)) { + codeFuture.completeExceptionally(new RuntimeException("Launcher sign-in returned an unexpected state.")); + responseTitle = "Launcher sign-in failed"; + responseMessage = "Return to Modtale Launcher and try again."; + } else if (code == null || code.isBlank()) { + codeFuture.completeExceptionally(new RuntimeException("Launcher sign-in did not return an authorization code.")); + responseTitle = "Launcher sign-in failed"; + responseMessage = "Return to Modtale Launcher and try again."; + } else { + codeFuture.complete(code); + } + + byte[] body = callbackPage(responseTitle, responseMessage).getBytes(StandardCharsets.UTF_8); + exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8"); + exchange.sendResponseHeaders(200, body.length); + try (OutputStream output = exchange.getResponseBody()) { + output.write(body); + } + } + + private static void openBrowser(URI uri) { + if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + throw new RuntimeException("Desktop browser integration is not available. Could not open Modtale sign-in."); + } + try { + Desktop.getDesktop().browse(uri); + } catch (IOException ex) { + throw new RuntimeException("Could not open Modtale sign-in in your browser.", ex); + } + } + + private static String callbackPage(String title, String message) { + return """ + + + + + + %s + + + +

    %s

    %s

    + + """.formatted(escapeHtml(title), escapeHtml(title), escapeHtml(message)); + } + + private static Map parseQuery(String rawQuery) { + Map params = new LinkedHashMap<>(); + if (rawQuery == null || rawQuery.isBlank()) { + return params; + } + for (String pair : rawQuery.split("&")) { + int separator = pair.indexOf('='); + String key = separator >= 0 ? pair.substring(0, separator) : pair; + String value = separator >= 0 ? pair.substring(separator + 1) : ""; + params.put(decode(key), decode(value)); + } + return params; + } + + private static String randomState() { + byte[] bytes = new byte[32]; + RANDOM.nextBytes(bytes); + return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); + } + + private static String encode(String value) { + return URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8); + } + + private static String encodePath(String value) { + return encode(value).replace("+", "%20"); + } + + private static String decode(String value) { + return URLDecoder.decode(value == null ? "" : value, StandardCharsets.UTF_8); + } + + private static String escapeHtml(String value) { + return value == null ? "" : value + .replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """) + .replace("'", "'"); + } + + @FunctionalInterface + private interface AuthUriFactory { + URI build(URI callbackUri, String state); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthGate.java b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthGate.java new file mode 100644 index 00000000..99583fcf --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherAuthGate.java @@ -0,0 +1,317 @@ +package net.modtale.launcher.ui.account; + +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.secondaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.setVisibleManaged; +import static net.modtale.launcher.ui.common.LauncherUi.styleInput; + +import java.util.List; +import java.util.Objects; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.PasswordField; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import net.modtale.launcher.ui.common.LauncherIcons; + +public final class LauncherAuthGate { + + private static final List OAUTH_PROVIDERS = List.of( + new OAuthProvider("GitHub", "github", LauncherIcons.BrandGlyph.GITHUB), + new OAuthProvider("Discord", "discord", LauncherIcons.BrandGlyph.DISCORD), + new OAuthProvider("Google", "google", LauncherIcons.BrandGlyph.GOOGLE) + ); + + private final LauncherAccountController accountController; + + private Node view; + private Label statusLabel; + private Button signInButton; + private Button browserSignInButton; + private TextField usernameField; + private PasswordField passwordField; + private TextField mfaCodeField; + private VBox credentialsPane; + private VBox mfaPane; + private String preAuthToken; + + public LauncherAuthGate(LauncherAccountController accountController) { + this.accountController = accountController; + } + + public Node view() { + if (view == null) { + view = buildView(); + } + return view; + } + + public void show(String status, boolean allowSignIn) { + if (statusLabel != null) { + statusLabel.setText(status == null || status.isBlank() ? "Sign in with Modtale to continue." : status); + } + if (credentialsPane != null) { + credentialsPane.setDisable(!allowSignIn); + } + if (mfaPane != null) { + mfaPane.setDisable(!allowSignIn); + } + if (signInButton != null) { + signInButton.setDisable(!allowSignIn); + } + if (browserSignInButton != null) { + browserSignInButton.setDisable(!allowSignIn); + } + if (usernameField != null) { + usernameField.setDisable(!allowSignIn); + } + if (passwordField != null) { + passwordField.setDisable(!allowSignIn); + } + if (mfaCodeField != null) { + mfaCodeField.setDisable(!allowSignIn); + } + } + + private Node buildView() { + VBox gate = new VBox(18); + gate.getStyleClass().add("auth-gate"); + gate.setAlignment(Pos.CENTER); + + ImageView logo = new ImageView(new Image(Objects.requireNonNull(getClass() + .getResource("/net/modtale/launcher/ui/nativefx/assets/logo_light.png")).toExternalForm(), true)); + logo.setFitHeight(42); + logo.setPreserveRatio(true); + + Label title = new Label("Sign in with Modtale"); + title.getStyleClass().add("auth-title"); + + statusLabel = new Label("Checking for an existing Modtale session..."); + statusLabel.getStyleClass().add("auth-status"); + statusLabel.setWrapText(true); + statusLabel.setMaxWidth(360); + statusLabel.setAlignment(Pos.CENTER); + statusLabel.setTextAlignment(javafx.scene.text.TextAlignment.CENTER); + + credentialsPane = credentialsPane(); + mfaPane = mfaPane(); + setVisibleManaged(mfaPane, false); + + VBox card = new VBox(16, logo, title, credentialsPane, mfaPane, statusLabel); + card.getStyleClass().add("auth-card"); + card.setAlignment(Pos.CENTER); + gate.getChildren().add(card); + return gate; + } + + private VBox credentialsPane() { + usernameField = new TextField(); + usernameField.setPromptText("Email or username"); + + passwordField = new PasswordField(); + passwordField.setPromptText("Password"); + styleInput(usernameField, passwordField); + usernameField.setMaxWidth(Double.MAX_VALUE); + passwordField.setMaxWidth(Double.MAX_VALUE); + usernameField.setOnAction(event -> passwordField.requestFocus()); + passwordField.setOnAction(event -> submitCredentials()); + + signInButton = primaryButton("Sign In"); + signInButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.USER, 16)); + signInButton.setMaxWidth(Double.MAX_VALUE); + signInButton.setOnAction(event -> submitCredentials()); + + browserSignInButton = secondaryButton("Use browser sign-in"); + browserSignInButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.GLOBE, 16)); + browserSignInButton.setMaxWidth(Double.MAX_VALUE); + browserSignInButton.setOnAction(event -> { + show("Opening Modtale sign-in in your browser...", false); + accountController.signInWithBrowser(); + }); + + VBox fields = new VBox(10, usernameField, passwordField); + fields.setMaxWidth(Double.MAX_VALUE); + + VBox pane = new VBox(12, oauthPane(), separator(), fields, signInButton, browserSignInButton); + pane.getStyleClass().add("auth-form"); + pane.setAlignment(Pos.CENTER); + pane.setMaxWidth(360); + return pane; + } + + private Node oauthPane() { + VBox providers = new VBox(10); + providers.getStyleClass().add("auth-oauth-list"); + for (int index = 0; index < OAUTH_PROVIDERS.size(); index += 2) { + HBox row = new HBox(10); + row.getStyleClass().add("auth-oauth-row"); + row.getChildren().add(oauthButton(OAUTH_PROVIDERS.get(index))); + if (index + 1 < OAUTH_PROVIDERS.size()) { + row.getChildren().add(oauthButton(OAUTH_PROVIDERS.get(index + 1))); + } + providers.getChildren().add(row); + } + return providers; + } + + private Button oauthButton(OAuthProvider provider) { + Button button = secondaryButton(provider.label()); + button.getStyleClass().add("auth-oauth-button"); + button.setGraphic(LauncherIcons.brandIcon(provider.icon(), 16)); + button.setMaxWidth(Double.MAX_VALUE); + button.setOnAction(event -> submitOAuth(provider)); + HBox.setHgrow(button, Priority.ALWAYS); + return button; + } + + private Node separator() { + Label label = new Label("or use email"); + label.getStyleClass().add("auth-separator-label"); + label.getStyleClass().add("auth-separator"); + label.setAlignment(Pos.CENTER); + label.setMaxWidth(Double.MAX_VALUE); + return label; + } + + private VBox mfaPane() { + Label title = new Label("Enter your two-factor code"); + title.getStyleClass().add("auth-step-title"); + + mfaCodeField = new TextField(); + mfaCodeField.setPromptText("000000"); + mfaCodeField.getStyleClass().addAll("input", "auth-mfa-input"); + mfaCodeField.setMaxWidth(Double.MAX_VALUE); + mfaCodeField.textProperty().addListener((observable, previous, current) -> { + String digits = current == null ? "" : current.replaceAll("\\D", ""); + if (digits.length() > 6) { + digits = digits.substring(0, 6); + } + if (!digits.equals(current)) { + mfaCodeField.setText(digits); + } + }); + mfaCodeField.setOnAction(event -> submitMfa()); + + Button verify = primaryButton("Verify"); + verify.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 16)); + verify.setMaxWidth(Double.MAX_VALUE); + verify.setOnAction(event -> submitMfa()); + + Button back = secondaryButton("Back"); + back.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_LEFT, 16)); + back.setMaxWidth(Double.MAX_VALUE); + back.setOnAction(event -> showCredentials("Sign in with Modtale to continue.", true)); + + HBox actions = new HBox(10, back, verify); + actions.setAlignment(Pos.CENTER); + HBox.setHgrow(back, Priority.ALWAYS); + HBox.setHgrow(verify, Priority.ALWAYS); + + VBox pane = new VBox(12, title, mfaCodeField, actions); + pane.getStyleClass().add("auth-form"); + pane.setAlignment(Pos.CENTER); + pane.setMaxWidth(360); + VBox.setMargin(title, new Insets(0, 0, 2, 0)); + return pane; + } + + private void submitCredentials() { + String username = usernameField == null ? "" : usernameField.getText().trim(); + String password = passwordField == null ? "" : passwordField.getText(); + if (username.isBlank()) { + show("Enter your email or username.", true); + usernameField.requestFocus(); + return; + } + if (password.isBlank()) { + show("Enter your password.", true); + passwordField.requestFocus(); + return; + } + + show("Signing in with Modtale...", false); + accountController.signIn(username, password.toCharArray(), result -> { + if (result.mfaRequired()) { + preAuthToken = result.preAuthToken(); + if (passwordField != null) { + passwordField.clear(); + } + showMfa(); + return; + } + if (result.failed()) { + showCredentials(result.errorMessage(), true); + } else if (result.success() && passwordField != null) { + passwordField.clear(); + } + }); + } + + private void submitOAuth(OAuthProvider provider) { + show("Opening " + provider.label() + " sign-in...", false); + accountController.signInWithOAuthProvider(provider.id(), provider.label(), result -> { + if (result.failed()) { + showCredentials(result.errorMessage(), true); + } + }); + } + + private void submitMfa() { + String code = mfaCodeField == null ? "" : mfaCodeField.getText().trim(); + if (preAuthToken == null || preAuthToken.isBlank()) { + showCredentials("Your two-factor login session expired. Sign in again.", true); + return; + } + if (!code.matches("\\d{6}")) { + show("Enter the 6-digit code from your authenticator app.", true); + mfaCodeField.requestFocus(); + return; + } + + show("Verifying two-factor code...", false); + accountController.validateMfa(preAuthToken, code, result -> { + if (result.failed()) { + show(result.errorMessage(), true); + if (mfaCodeField != null) { + mfaCodeField.selectAll(); + mfaCodeField.requestFocus(); + } + } else { + preAuthToken = null; + if (mfaCodeField != null) { + mfaCodeField.clear(); + } + } + }); + } + + private void showMfa() { + setVisibleManaged(credentialsPane, false); + setVisibleManaged(mfaPane, true); + if (mfaCodeField != null) { + mfaCodeField.clear(); + mfaCodeField.requestFocus(); + } + show("Enter the 6-digit code from your authenticator app.", true); + } + + private void showCredentials(String status, boolean allowSignIn) { + preAuthToken = null; + setVisibleManaged(mfaPane, false); + setVisibleManaged(credentialsPane, true); + show(status, allowSignIn); + if (usernameField != null) { + usernameField.requestFocus(); + } + } + + private record OAuthProvider(String label, String id, LauncherIcons.BrandGlyph icon) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherHytaleAuthGate.java b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherHytaleAuthGate.java new file mode 100644 index 00000000..78bc0bff --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/account/LauncherHytaleAuthGate.java @@ -0,0 +1,111 @@ +package net.modtale.launcher.ui.account; + +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; + +import java.util.Objects; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.VBox; +import net.modtale.launcher.hytale.HytaleAuthService; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.feedback.LauncherFeedback; +import net.modtale.launcher.ui.settings.LauncherSettingsController; + +public final class LauncherHytaleAuthGate { + + private final HytaleAuthService hytaleAuthService; + private final LauncherSettingsController settingsController; + private final LauncherFeedback feedback; + private final Runnable onLinked; + + private Node view; + private Label statusLabel; + private Button signInButton; + + public LauncherHytaleAuthGate( + HytaleAuthService hytaleAuthService, + LauncherSettingsController settingsController, + LauncherFeedback feedback, + Runnable onLinked + ) { + this.hytaleAuthService = hytaleAuthService; + this.settingsController = settingsController; + this.feedback = feedback; + this.onLinked = onLinked == null ? () -> { + } : onLinked; + } + + public Node view() { + if (view == null) { + view = buildView(); + } + return view; + } + + public void show(String status, boolean allowSignIn) { + if (statusLabel != null) { + statusLabel.setText(status == null || status.isBlank() + ? "Sign in with Hytale to use Modtale Launcher." + : status); + } + if (signInButton != null) { + signInButton.setDisable(!allowSignIn); + } + } + + private Node buildView() { + VBox gate = new VBox(18); + gate.getStyleClass().add("auth-gate"); + gate.setAlignment(Pos.CENTER); + + ImageView logo = new ImageView(new Image(Objects.requireNonNull(getClass() + .getResource("/net/modtale/launcher/ui/nativefx/assets/logo_light.png")).toExternalForm(), true)); + logo.setFitHeight(42); + logo.setPreserveRatio(true); + + Label title = new Label("Link a Hytale account"); + title.getStyleClass().add("auth-title"); + + statusLabel = new Label("Sign in with Hytale to use Modtale Launcher."); + statusLabel.getStyleClass().add("auth-status"); + statusLabel.setWrapText(true); + statusLabel.setMaxWidth(360); + statusLabel.setAlignment(Pos.CENTER); + statusLabel.setTextAlignment(javafx.scene.text.TextAlignment.CENTER); + + signInButton = primaryButton("Sign In With Hytale"); + signInButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.USER, 16)); + signInButton.setMaxWidth(Double.MAX_VALUE); + signInButton.setOnAction(event -> signInHytale()); + + Label note = new Label("Modtale sign-in is optional for local play, but Hytale launch uses official Hytale authentication."); + note.getStyleClass().add("auth-status"); + note.setWrapText(true); + note.setMaxWidth(360); + note.setAlignment(Pos.CENTER); + note.setTextAlignment(javafx.scene.text.TextAlignment.CENTER); + + VBox card = new VBox(16, logo, title, statusLabel, signInButton, note); + card.getStyleClass().add("auth-card"); + card.setAlignment(Pos.CENTER); + gate.getChildren().add(card); + return gate; + } + + private void signInHytale() { + settingsController.saveFromFields(false); + show("Opening Hytale sign-in in your browser...", false); + feedback.runAsync("Opening Hytale sign-in in your browser...", () -> + hytaleAuthService.loginAndSave(settingsController.settings()), session -> { + settingsController.reloadFromStore(); + feedback.log("Signed in with Hytale as " + session + "."); + feedback.showToast("Hytale ready", "Signed in as " + session + "."); + show("Signed in with Hytale.", true); + onLinked.run(); + }, error -> show("Hytale sign-in failed. Try again when Hytale authentication is available.", true)); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherFollowingController.java b/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherFollowingController.java new file mode 100644 index 00000000..0c9743e9 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherFollowingController.java @@ -0,0 +1,278 @@ +package net.modtale.launcher.ui.activity; + +import static net.modtale.launcher.ui.common.LauncherUi.setVisibleManaged; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.model.user.UserSummary; +import net.modtale.launcher.ui.account.LauncherAccountController; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherExternalLinks; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.feedback.LauncherFeedback; + +public final class LauncherFollowingController { + + private static final double AVATAR_SIZE = 40; + + private final ModtaleApiClient apiClient; + private final LauncherAccountController accountController; + private final LauncherFeedback feedback; + private final CachedImageLoader imageLoader; + private final StackPane modalLayer = new StackPane(); + private final VBox userList = new VBox(2); + private final Label summary = new Label("No creators loaded"); + + private boolean modalBuilt; + private boolean loading; + private List users = List.of(); + + public LauncherFollowingController( + ModtaleApiClient apiClient, + LauncherAccountController accountController, + LauncherFeedback feedback, + CachedImageLoader imageLoader + ) { + this.apiClient = apiClient; + this.accountController = accountController; + this.feedback = feedback; + this.imageLoader = imageLoader; + accountController.addCurrentUserListener(user -> { + if (user == null) { + users = List.of(); + loading = false; + hideModal(); + renderUsers(); + } + }); + } + + public Node modal() { + if (!modalBuilt) { + buildModal(); + } + return modalLayer; + } + + public void showModal() { + modal(); + setVisibleManaged(modalLayer, true); + modalLayer.toFront(); + refresh(); + } + + public void hideModal() { + setVisibleManaged(modalLayer, false); + } + + public void refresh() { + CurrentUser user = accountController.currentUser(); + if (user == null || user.id() == null || user.id().isBlank()) { + loading = false; + users = List.of(); + renderUsers(); + return; + } + loading = true; + renderUsers(); + feedback.runAsync("Loading following...", + () -> apiClient.getFollowing(user.id()), + loaded -> { + loading = false; + users = List.copyOf(loaded); + renderUsers(); + feedback.log("Loaded " + users.size() + " followed creators."); + }, + error -> { + loading = false; + renderUsers(); + }); + } + + private void buildModal() { + modalBuilt = true; + modalLayer.getStyleClass().add("following-modal-layer"); + setVisibleManaged(modalLayer, false); + + Region scrim = new Region(); + scrim.getStyleClass().add("following-modal-scrim"); + scrim.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + scrim.setOnMouseClicked(event -> hideModal()); + + Label title = new Label("Following"); + title.getStyleClass().add("following-modal-title"); + title.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.USER, 18)); + title.setGraphicTextGap(8); + + Region headerSpacer = new Region(); + HBox.setHgrow(headerSpacer, Priority.ALWAYS); + + Button close = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.X, 16)); + close.getStyleClass().addAll("icon-btn", "following-modal-close"); + close.setMnemonicParsing(false); + close.setAccessibleText("Close following"); + close.setTooltip(new Tooltip("Close")); + close.setOnAction(event -> hideModal()); + + HBox header = new HBox(10, title, headerSpacer, close); + header.getStyleClass().add("following-modal-header"); + header.setAlignment(Pos.CENTER_LEFT); + + summary.getStyleClass().add("following-modal-summary"); + userList.getStyleClass().add("following-modal-list"); + + ScrollPane scrollPane = new ScrollPane(userList); + scrollPane.getStyleClass().add("following-modal-scroll"); + scrollPane.setFitToWidth(true); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setMaxHeight(460); + VBox.setVgrow(scrollPane, Priority.ALWAYS); + + VBox card = new VBox(0, header, summary, scrollPane); + card.getStyleClass().add("following-modal-card"); + card.setMaxWidth(460); + card.setMaxHeight(620); + StackPane.setAlignment(card, Pos.CENTER); + StackPane.setMargin(card, new Insets(24)); + + modalLayer.getChildren().setAll(scrim, card); + renderUsers(); + } + + private void renderUsers() { + if (!modalBuilt) { + return; + } + userList.getChildren().clear(); + if (loading) { + setVisibleManaged(summary, true); + summary.setText("Loading followed creators..."); + Label loadingLabel = new Label("Loading..."); + loadingLabel.getStyleClass().add("following-loading"); + StackPane loadingPane = new StackPane(loadingLabel); + loadingPane.getStyleClass().add("following-loading-pane"); + userList.getChildren().add(loadingPane); + return; + } + if (users.isEmpty()) { + setVisibleManaged(summary, false); + userList.getChildren().add(followingEmptyState()); + return; + } + setVisibleManaged(summary, true); + summary.setText(users.size() + " followed creator" + (users.size() == 1 ? "" : "s")); + for (UserSummary user : users) { + userList.getChildren().add(userRow(user)); + } + } + + private VBox followingEmptyState() { + VBox empty = new VBox(8); + empty.getStyleClass().add("following-empty-state"); + empty.setAlignment(Pos.CENTER); + + Label title = new Label("Not following anyone"); + title.getStyleClass().add("following-empty-title"); + Label subtitle = new Label("Follow creators on Modtale to see them here."); + subtitle.getStyleClass().add("following-empty-subtitle"); + + empty.getChildren().addAll(title, subtitle); + return empty; + } + + private Node userRow(UserSummary user) { + HBox row = new HBox(12); + row.getStyleClass().add("following-row"); + row.setAlignment(Pos.CENTER_LEFT); + + StackPane avatar = avatar(user); + Label name = new Label(value(user.username(), "Unknown creator")); + name.getStyleClass().add("following-name"); + VBox copy = new VBox(3, name); + String role = primaryRole(user.roles()); + if (!role.isBlank()) { + Label roleLabel = new Label(role); + roleLabel.getStyleClass().add("following-role"); + copy.getChildren().add(roleLabel); + } + HBox.setHgrow(copy, Priority.ALWAYS); + + Button open = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.EXTERNAL_LINK, 15)); + open.getStyleClass().addAll("icon-btn", "following-open-button"); + open.setAccessibleText("Open creator profile"); + open.setTooltip(new Tooltip("Open creator profile")); + open.addEventHandler(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + open.setOnAction(event -> { + hideModal(); + LauncherExternalLinks.open(creatorPath(user), feedback::showToast); + }); + + row.setOnMouseClicked(event -> { + hideModal(); + LauncherExternalLinks.open(creatorPath(user), feedback::showToast); + }); + row.getChildren().addAll(avatar, copy, open); + return row; + } + + private StackPane avatar(UserSummary user) { + Label initial = new Label(initialFor(user.username())); + ImageView image = new ImageView(); + image.getStyleClass().add("following-avatar-image"); + image.setFitWidth(AVATAR_SIZE); + image.setFitHeight(AVATAR_SIZE); + image.setSmooth(true); + Rectangle clip = new Rectangle(AVATAR_SIZE, AVATAR_SIZE); + clip.setArcWidth(AVATAR_SIZE); + clip.setArcHeight(AVATAR_SIZE); + image.setClip(clip); + imageLoader.loadInto(image, user.avatarUrl(), AVATAR_SIZE, AVATAR_SIZE); + StackPane avatar = new StackPane(initial, image); + avatar.getStyleClass().add("following-avatar"); + return avatar; + } + + private static String creatorPath(UserSummary user) { + String handle = user.username() == null || user.username().isBlank() + ? user.id() + : user.username(); + return "/creator/" + encodePath(handle); + } + + private static String encodePath(String value) { + return URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8).replace("+", "%20"); + } + + private static String primaryRole(List roles) { + if (roles == null || roles.isEmpty() || "USER".equals(roles.getFirst())) { + return ""; + } + return roles.getFirst(); + } + + private static String initialFor(String name) { + if (name == null || name.isBlank()) { + return "M"; + } + return name.trim().substring(0, 1).toUpperCase(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsController.java b/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsController.java new file mode 100644 index 00000000..9b2eb6a4 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsController.java @@ -0,0 +1,423 @@ +package net.modtale.launcher.ui.activity; + +import static net.modtale.launcher.ui.common.LauncherUi.dangerButton; +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; +import static net.modtale.launcher.ui.common.LauncherUi.secondaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.model.notification.LauncherNotification; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.ui.account.LauncherAccountController; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherExternalLinks; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherView; +import net.modtale.launcher.ui.feedback.LauncherFeedback; + +public final class LauncherNotificationsController { + + private static final DateTimeFormatter NOTIFICATION_DATE = DateTimeFormatter.ofPattern("MMM d, yyyy"); + private static final double NOTIFICATION_ICON_SIZE = 40; + + private final ModtaleApiClient apiClient; + private final LauncherAccountController accountController; + private final LauncherFeedback feedback; + private final CachedImageLoader imageLoader; + private final VBox notificationList = new VBox(0); + private final Label notificationSummary = new Label("No notifications loaded"); + private final ToggleControl projectUpdates = new ToggleControl( + "Favorite Project Updates", + "Notify me when projects I've favorited release new versions." + ); + private final ToggleControl creatorUploads = new ToggleControl( + "New Creator Uploads", + "Notify me when creators I follow upload new projects." + ); + private final ToggleControl newComments = new ToggleControl( + "New Comments", + "Get notified when someone comments on your project." + ); + private final ToggleControl newFollowers = new ToggleControl( + "New Followers", + "Notify me when someone starts following me." + ); + private final ToggleControl dependencyUpdates = new ToggleControl( + "Dependency Updates", + "Alert me when a project I depend on releases a new version." + ); + + private Node view; + private List notifications = List.of(); + + public LauncherNotificationsController( + ModtaleApiClient apiClient, + LauncherAccountController accountController, + LauncherFeedback feedback, + CachedImageLoader imageLoader + ) { + this.apiClient = apiClient; + this.accountController = accountController; + this.feedback = feedback; + this.imageLoader = imageLoader; + accountController.addCurrentUserListener(this::applyPreferences); + } + + public Node view() { + if (view == null) { + view = buildView(); + applyPreferences(accountController.currentUser()); + renderNotifications(); + } + return view; + } + + public void refresh() { + applyPreferences(accountController.currentUser()); + loadNotifications(); + } + + private Node buildView() { + VBox root = new VBox(24); + root.setUserData(LauncherView.NOTIFICATIONS); + root.getStyleClass().addAll("view", "account-view"); + + VBox preferences = new VBox(0); + preferences.getStyleClass().add("account-card"); + preferences.getChildren().addAll( + projectUpdates.node(), + creatorUploads.node(), + newComments.node(), + newFollowers.node(), + dependencyUpdates.node() + ); + + Button save = primaryButton("Save Changes"); + save.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.SAVE, 14)); + save.setOnAction(event -> savePreferences(save)); + HBox saveRow = new HBox(save); + saveRow.setAlignment(Pos.CENTER_RIGHT); + + VBox recent = new VBox(0); + recent.getStyleClass().add("account-card"); + Button refresh = iconAction(LauncherIcons.Glyph.REFRESH_CW, "Refresh"); + refresh.setOnAction(event -> loadNotifications()); + Button markAll = secondaryButton("Mark All Read"); + markAll.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 13)); + markAll.setOnAction(event -> markAllRead(markAll)); + Button clear = secondaryButton("Clear All"); + clear.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.TRASH, 13)); + clear.setOnAction(event -> clearAll(clear)); + HBox recentActions = new HBox(8, refresh, markAll, clear); + recentActions.setAlignment(Pos.CENTER_RIGHT); + HBox recentHeader = sectionHeader("Notifications", "Recent account activity and requests.", recentActions); + notificationSummary.getStyleClass().add("account-section-meta"); + VBox.setMargin(notificationSummary, new Insets(0, 18, 12, 18)); + recent.getChildren().addAll(recentHeader, notificationSummary, notificationList); + + root.getChildren().addAll(preferences, saveRow, recent); + return root; + } + + private HBox sectionHeader(String title, String subtitle, Node actions) { + Label heading = new Label(title); + heading.getStyleClass().add("account-section-title"); + Label sub = new Label(subtitle); + sub.getStyleClass().add("account-section-subtitle"); + VBox copy = new VBox(3, heading, sub); + HBox header = new HBox(12, copy); + header.getStyleClass().add("account-section-header"); + header.setAlignment(Pos.CENTER_LEFT); + HBox.setHgrow(copy, Priority.ALWAYS); + if (actions != null) { + header.getChildren().add(actions); + } + return header; + } + + private void loadNotifications() { + feedback.runAsync("Loading notifications...", + apiClient::getNotifications, + loaded -> { + notifications = List.copyOf(loaded); + renderNotifications(); + feedback.log("Loaded " + notifications.size() + " notifications."); + }); + } + + private void savePreferences(Button save) { + save.setDisable(true); + CurrentUser.NotificationPreferences preferences = new CurrentUser.NotificationPreferences( + projectUpdates.value(), + creatorUploads.value(), + newComments.value(), + newFollowers.value(), + dependencyUpdates.value() + ); + feedback.runAsync("Saving notification preferences...", () -> { + apiClient.updateNotificationPreferences(preferences); + return apiClient.currentUser(); + }, user -> { + save.setDisable(false); + accountController.setCurrentUser(user); + feedback.showToast("Saved", "Notification preferences were updated."); + }, error -> save.setDisable(false)); + } + + private void clearAll(Button clear) { + clear.setDisable(true); + feedback.runAsync("Clearing notifications...", () -> { + apiClient.clearNotifications(); + return List.of(); + }, ignored -> { + clear.setDisable(false); + notifications = List.of(); + renderNotifications(); + feedback.showToast("Notifications cleared", "Your notification list is empty."); + }, error -> clear.setDisable(false)); + } + + private void markAllRead(Button markAll) { + markAll.setDisable(true); + feedback.runAsync("Marking notifications as read...", () -> { + apiClient.markAllNotificationsRead(); + return apiClient.getNotifications(); + }, loaded -> { + markAll.setDisable(false); + notifications = List.copyOf(loaded); + renderNotifications(); + }, error -> markAll.setDisable(false)); + } + + private void dismiss(LauncherNotification notification) { + feedback.runAsync("Dismissing notification...", () -> { + apiClient.deleteNotification(notification.id()); + return notification.id(); + }, id -> { + notifications = notifications.stream() + .filter(item -> !id.equals(item.id())) + .toList(); + renderNotifications(); + }); + } + + private void toggleRead(LauncherNotification notification) { + boolean nextRead = !notification.read(); + feedback.runAsync(nextRead ? "Marking notification as read..." : "Marking notification as unread...", () -> { + apiClient.markNotificationRead(notification.id(), nextRead); + return apiClient.getNotifications(); + }, loaded -> { + notifications = List.copyOf(loaded); + renderNotifications(); + }); + } + + private void resolveAction(LauncherNotification notification, boolean accept) { + feedback.runAsync((accept ? "Accepting" : "Declining") + " notification request...", () -> { + apiClient.resolveNotificationAction(notification, accept); + apiClient.deleteNotification(notification.id()); + return apiClient.getNotifications(); + }, loaded -> { + notifications = List.copyOf(loaded); + renderNotifications(); + feedback.showToast(accept ? "Accepted" : "Declined", "Notification request updated."); + }); + } + + private void renderNotifications() { + notificationList.getChildren().clear(); + int unread = (int) notifications.stream().filter(item -> !item.read()).count(); + if (notifications.isEmpty()) { + notificationSummary.setText(""); + notificationSummary.setVisible(false); + notificationSummary.setManaged(false); + return; + } + notificationSummary.setText(notifications.size() + " total - " + unread + " unread"); + notificationSummary.setVisible(true); + notificationSummary.setManaged(true); + for (LauncherNotification notification : notifications) { + notificationList.getChildren().add(notificationRow(notification)); + } + } + + private Node notificationRow(LauncherNotification notification) { + HBox row = new HBox(12); + row.getStyleClass().add("notification-row"); + row.setAlignment(Pos.TOP_LEFT); + pseudo(row, "unread", !notification.read()); + + StackPane icon = notificationIcon(notification.iconUrl()); + VBox copy = new VBox(4); + HBox titleLine = new HBox(6); + titleLine.setAlignment(Pos.CENTER_LEFT); + Label title = new Label(value(notification.title(), "Notification")); + title.getStyleClass().add("notification-title"); + title.setMaxWidth(Double.MAX_VALUE); + titleLine.getChildren().add(title); + if (!notification.read()) { + Region unreadDot = new Region(); + unreadDot.getStyleClass().add("notification-unread-dot"); + titleLine.getChildren().add(unreadDot); + } + + Label message = new Label(value(notification.message(), "")); + message.getStyleClass().add("notification-message"); + message.setWrapText(true); + Label date = new Label(formatDate(notification.createdAt())); + date.getStyleClass().add("notification-date"); + copy.getChildren().addAll(titleLine, message); + if (notification.actionable()) { + HBox decisions = new HBox(8); + decisions.getStyleClass().add("notification-decisions"); + Button accept = primaryButton("Accept"); + accept.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 13)); + accept.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + accept.setOnAction(event -> resolveAction(notification, true)); + Button decline = dangerButton("Decline"); + decline.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.X, 13)); + decline.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + decline.setOnAction(event -> resolveAction(notification, false)); + decisions.getChildren().addAll(accept, decline); + copy.getChildren().add(decisions); + } else { + copy.getChildren().add(date); + } + HBox.setHgrow(copy, Priority.ALWAYS); + + VBox actions = new VBox(6); + actions.getStyleClass().add("notification-row-actions"); + actions.setAlignment(Pos.TOP_RIGHT); + Button open = iconAction(LauncherIcons.Glyph.EXTERNAL_LINK, "Open"); + open.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + open.setOnAction(event -> LauncherExternalLinks.open(notification.link(), feedback::showToast)); + Button dismiss = iconAction(LauncherIcons.Glyph.X, "Dismiss"); + dismiss.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + dismiss.setOnAction(event -> dismiss(notification)); + Button read = iconAction(LauncherIcons.Glyph.CIRCLE, notification.read() ? "Mark unread" : "Mark read"); + read.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + pseudo(read, "selected", !notification.read()); + read.setOnAction(event -> toggleRead(notification)); + actions.getChildren().addAll(open, dismiss, read); + + row.getChildren().addAll(icon, copy, actions); + return row; + } + + private StackPane notificationIcon(String iconUrl) { + ImageView image = new ImageView(); + image.getStyleClass().add("notification-image"); + image.setFitWidth(NOTIFICATION_ICON_SIZE); + image.setFitHeight(NOTIFICATION_ICON_SIZE); + image.setSmooth(true); + Rectangle clip = new Rectangle(NOTIFICATION_ICON_SIZE, NOTIFICATION_ICON_SIZE); + clip.setArcWidth(8); + clip.setArcHeight(8); + image.setClip(clip); + imageLoader.loadInto(image, iconUrl, NOTIFICATION_ICON_SIZE, NOTIFICATION_ICON_SIZE); + StackPane icon = new StackPane(LauncherIcons.icon(LauncherIcons.Glyph.BELL, 18), image); + icon.getStyleClass().add("notification-image-shell"); + return icon; + } + + private Button iconAction(LauncherIcons.Glyph glyph, String tooltipText) { + Button button = new Button(null, LauncherIcons.icon(glyph, 14)); + button.getStyleClass().addAll("icon-btn", "notification-icon-button"); + button.setMnemonicParsing(false); + button.setAccessibleText(tooltipText); + button.setTooltip(new Tooltip(tooltipText)); + return button; + } + + private void applyPreferences(CurrentUser user) { + CurrentUser.NotificationPreferences prefs = user == null + ? CurrentUser.NotificationPreferences.defaults() + : user.notificationPreferences(); + projectUpdates.setValue(prefs.projectUpdates()); + creatorUploads.setValue(prefs.creatorUploads()); + newComments.setValue(prefs.newComments()); + newFollowers.setValue(prefs.newFollowers()); + dependencyUpdates.setValue(prefs.dependencyUpdates()); + } + + private static String formatDate(LocalDateTime createdAt) { + return createdAt == null ? "" : NOTIFICATION_DATE.format(createdAt); + } + + private static final class ToggleControl { + private final String label; + private final String description; + private final Button off = new Button("Off"); + private final Button on = new Button("On"); + private CurrentUser.NotificationLevel value = CurrentUser.NotificationLevel.ON; + private Node node; + + private ToggleControl(String label, String description) { + this.label = label; + this.description = description; + } + + Node node() { + if (node == null) { + Label title = new Label(label); + title.getStyleClass().add("notification-toggle-title"); + Label desc = new Label(description); + desc.getStyleClass().add("notification-toggle-description"); + desc.setWrapText(true); + VBox copy = new VBox(4, title, desc); + HBox.setHgrow(copy, Priority.ALWAYS); + + off.getStyleClass().add("notification-toggle-segment"); + on.getStyleClass().add("notification-toggle-segment"); + off.setOnAction(event -> setValue(CurrentUser.NotificationLevel.OFF)); + on.setOnAction(event -> setValue(CurrentUser.NotificationLevel.ON)); + HBox segments = new HBox(0, off, on); + segments.getStyleClass().add("notification-toggle-control"); + segments.setAlignment(Pos.CENTER_RIGHT); + + HBox row = new HBox(18, copy, segments); + row.getStyleClass().add("notification-toggle-row"); + row.setAlignment(Pos.CENTER_LEFT); + node = row; + refresh(); + } + return node; + } + + String value() { + return value.apiValue(); + } + + void setValue(String nextValue) { + setValue(CurrentUser.NotificationLevel.fromApiValue(nextValue)); + } + + void setValue(CurrentUser.NotificationLevel nextValue) { + value = nextValue == null ? CurrentUser.NotificationLevel.ON : nextValue; + refresh(); + } + + private void refresh() { + pseudo(off, "selected", value == CurrentUser.NotificationLevel.OFF); + pseudo(on, "selected", value == CurrentUser.NotificationLevel.ON); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsMenu.java b/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsMenu.java new file mode 100644 index 00000000..a1e457ae --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/activity/LauncherNotificationsMenu.java @@ -0,0 +1,445 @@ +package net.modtale.launcher.ui.activity; + +import static net.modtale.launcher.ui.common.LauncherUi.dangerButton; +import static net.modtale.launcher.ui.common.LauncherUi.emptyState; +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.event.EventTarget; +import javafx.geometry.Bounds; +import javafx.geometry.Point2D; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.model.notification.LauncherNotification; +import net.modtale.launcher.ui.account.LauncherAccountController; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherExternalLinks; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherOverlaySupport; +import net.modtale.launcher.ui.feedback.LauncherFeedback; + +public final class LauncherNotificationsMenu { + + private static final DateTimeFormatter NOTIFICATION_DATE = DateTimeFormatter.ofPattern("MMM d, yyyy"); + private static final double NOTIFICATION_ICON_SIZE = 40; + private static final double MENU_ESTIMATED_WIDTH = 384; + private static final double MENU_TOP_OFFSET = 8; + private static final double SCREEN_MARGIN = 8; + + private final ModtaleApiClient apiClient; + private final LauncherAccountController accountController; + private final LauncherFeedback feedback; + private final CachedImageLoader imageLoader; + private final VBox notificationList = new VBox(0); + + private Supplier sceneLayer = () -> null; + private Runnable beforeShow; + + private Button menuButton; + private Button clearButton; + private VBox dropdownPanel; + private Region unreadDot; + private List notifications = List.of(); + private boolean loading; + + public LauncherNotificationsMenu( + ModtaleApiClient apiClient, + LauncherAccountController accountController, + LauncherFeedback feedback, + CachedImageLoader imageLoader + ) { + this.apiClient = apiClient; + this.accountController = accountController; + this.feedback = feedback; + this.imageLoader = imageLoader; + accountController.addCurrentUserListener(user -> { + if (user == null) { + notifications = List.of(); + loading = false; + hide(); + renderNotifications(); + } + }); + } + + public void attachOverlay(Supplier sceneLayer, Runnable beforeShow) { + this.sceneLayer = sceneLayer == null ? () -> null : sceneLayer; + this.beforeShow = beforeShow; + } + + public Button button() { + if (menuButton == null) { + menuButton = buildButton(); + } + return menuButton; + } + + public VBox panel() { + button(); + return dropdownPanel; + } + + public void hide() { + if (dropdownPanel != null) { + dropdownPanel.setVisible(false); + } + if (menuButton != null) { + pseudo(menuButton, "selected", false); + } + } + + public void hideOnOutsidePress(EventTarget target) { + if (dropdownPanel == null || !dropdownPanel.isVisible()) { + return; + } + if (!LauncherOverlaySupport.eventTargetInside(target, dropdownPanel) + && !LauncherOverlaySupport.eventTargetInside(target, menuButton)) { + hide(); + } + } + + private Button buildButton() { + unreadDot = new Region(); + unreadDot.getStyleClass().add("notification-menu-unread-dot"); + unreadDot.setVisible(false); + unreadDot.setManaged(false); + + StackPane graphic = new StackPane(LauncherIcons.icon(LauncherIcons.Glyph.BELL, 18), unreadDot); + graphic.getStyleClass().add("notification-menu-button-graphic"); + StackPane.setAlignment(unreadDot, Pos.TOP_RIGHT); + + Button button = new Button(null, graphic); + button.getStyleClass().add("notification-menu-button"); + button.setMnemonicParsing(false); + button.setAccessibleText("Notifications"); + button.setTooltip(new Tooltip("Notifications")); + button.setOnAction(event -> toggle()); + + dropdownPanel = buildPanel(); + renderNotifications(); + return button; + } + + private VBox buildPanel() { + Label title = new Label("Notifications"); + title.getStyleClass().add("notification-menu-title"); + HBox.setHgrow(title, Priority.ALWAYS); + + Button refresh = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.REFRESH_CW, 13)); + refresh.getStyleClass().addAll("icon-btn", "notification-menu-header-button"); + refresh.setMnemonicParsing(false); + refresh.setAccessibleText("Refresh notifications"); + refresh.setTooltip(new Tooltip("Refresh")); + refresh.setOnAction(event -> refresh(false)); + + clearButton = new Button("Clear All", LauncherIcons.icon(LauncherIcons.Glyph.TRASH, 12)); + clearButton.getStyleClass().add("notification-menu-clear"); + clearButton.setOnAction(event -> clearAll()); + + HBox header = new HBox(8, title, refresh, clearButton); + header.getStyleClass().add("notification-menu-header"); + header.setAlignment(Pos.CENTER_LEFT); + + notificationList.getStyleClass().add("notification-menu-list"); + ScrollPane scroll = new ScrollPane(notificationList); + scroll.getStyleClass().add("notification-menu-scroll"); + scroll.setFitToWidth(true); + scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scroll.setMaxHeight(520); + VBox.setVgrow(scroll, Priority.ALWAYS); + + VBox menuPanel = new VBox(0, header, scroll); + menuPanel.getStyleClass().add("notification-dropdown-panel"); + menuPanel.setMinWidth(MENU_ESTIMATED_WIDTH); + menuPanel.setPrefWidth(MENU_ESTIMATED_WIDTH); + menuPanel.setMaxWidth(MENU_ESTIMATED_WIDTH); + menuPanel.setVisible(false); + menuPanel.setManaged(false); + return menuPanel; + } + + private void toggle() { + if (dropdownPanel.isVisible()) { + hide(); + return; + } + show(); + } + + private void show() { + StackPane layer = sceneLayer.get(); + if (layer == null || dropdownPanel == null || menuButton == null) { + return; + } + if (beforeShow != null) { + beforeShow.run(); + } + dropdownPanel.applyCss(); + dropdownPanel.autosize(); + position(); + dropdownPanel.setVisible(true); + dropdownPanel.toFront(); + pseudo(menuButton, "selected", true); + refresh(true); + Platform.runLater(this::position); + } + + private void position() { + StackPane layer = sceneLayer.get(); + if (layer == null || dropdownPanel == null || menuButton == null) { + return; + } + Bounds anchorBounds = menuButton.localToScene(menuButton.getBoundsInLocal()); + if (anchorBounds == null) { + return; + } + Point2D anchorBottomRight = layer.sceneToLocal(anchorBounds.getMaxX(), anchorBounds.getMaxY()); + double width = dropdownPanel.getLayoutBounds().getWidth() > 0 + ? dropdownPanel.getLayoutBounds().getWidth() + : MENU_ESTIMATED_WIDTH; + double maxX = Math.max(SCREEN_MARGIN, layer.getWidth() - width - SCREEN_MARGIN); + double x = LauncherOverlaySupport.clamp(anchorBottomRight.getX() - width, SCREEN_MARGIN, maxX); + double y = anchorBottomRight.getY() + MENU_TOP_OFFSET; + dropdownPanel.relocate(x, y); + } + + private void refresh(boolean markReadOnLoad) { + if (accountController.currentUser() == null) { + notifications = List.of(); + loading = false; + renderNotifications(); + return; + } + loading = true; + renderNotifications(); + feedback.runAsync("Loading notifications...", + apiClient::getNotifications, + loaded -> { + loading = false; + notifications = List.copyOf(loaded); + renderNotifications(); + if (markReadOnLoad && unreadCount() > 0) { + markAllReadFromMenu(); + } + }, + error -> { + loading = false; + renderNotifications(); + }); + } + + private void clearAll() { + if (clearButton != null) { + clearButton.setDisable(true); + } + feedback.runAsync("Clearing notifications...", () -> { + apiClient.clearNotifications(); + return List.of(); + }, ignored -> { + if (clearButton != null) { + clearButton.setDisable(false); + } + notifications = List.of(); + renderNotifications(); + feedback.showToast("Notifications cleared", "Your notification list is empty."); + }, error -> { + if (clearButton != null) { + clearButton.setDisable(false); + } + }); + } + + private void dismiss(LauncherNotification notification) { + feedback.runAsync("Dismissing notification...", () -> { + apiClient.deleteNotification(notification.id()); + return notification.id(); + }, id -> { + notifications = notifications.stream() + .filter(item -> !id.equals(item.id())) + .toList(); + renderNotifications(); + }); + } + + private void toggleRead(LauncherNotification notification) { + boolean nextRead = !notification.read(); + feedback.runAsync(nextRead ? "Marking notification as read..." : "Marking notification as unread...", () -> { + apiClient.markNotificationRead(notification.id(), nextRead); + return apiClient.getNotifications(); + }, loaded -> { + notifications = List.copyOf(loaded); + renderNotifications(); + }); + } + + private void markAllReadFromMenu() { + feedback.runAsync("Marking notifications as read...", () -> { + apiClient.markAllNotificationsRead(); + return apiClient.getNotifications(); + }, loaded -> { + notifications = List.copyOf(loaded); + renderNotifications(); + }); + } + + private void resolveAction(LauncherNotification notification, boolean accept) { + feedback.runAsync((accept ? "Accepting" : "Declining") + " notification request...", () -> { + apiClient.resolveNotificationAction(notification, accept); + apiClient.deleteNotification(notification.id()); + return apiClient.getNotifications(); + }, loaded -> { + notifications = List.copyOf(loaded); + renderNotifications(); + feedback.showToast(accept ? "Accepted" : "Declined", "Notification request updated."); + }); + } + + private void renderNotifications() { + if (notificationList == null) { + return; + } + notificationList.getChildren().clear(); + int unread = unreadCount(); + if (unreadDot != null) { + unreadDot.setVisible(unread > 0); + unreadDot.setManaged(unread > 0); + } + if (clearButton != null) { + clearButton.setVisible(!notifications.isEmpty()); + clearButton.setManaged(!notifications.isEmpty()); + } + if (loading) { + Label loadingLabel = new Label("Loading..."); + loadingLabel.getStyleClass().add("notification-menu-loading"); + StackPane loadingPane = new StackPane(loadingLabel); + loadingPane.getStyleClass().add("notification-menu-loading-pane"); + notificationList.getChildren().add(loadingPane); + return; + } + if (notifications.isEmpty()) { + VBox empty = emptyState("No notifications", "New activity and requests will appear here."); + empty.getStyleClass().add("notification-menu-empty"); + notificationList.getChildren().add(empty); + return; + } + for (LauncherNotification notification : notifications) { + notificationList.getChildren().add(notificationRow(notification)); + } + } + + private Node notificationRow(LauncherNotification notification) { + HBox row = new HBox(12); + row.getStyleClass().addAll("notification-row", "notification-menu-row"); + row.setAlignment(Pos.TOP_LEFT); + pseudo(row, "unread", !notification.read()); + row.setOnMouseClicked(event -> { + hide(); + LauncherExternalLinks.open(notification.link(), feedback::showToast); + }); + + StackPane icon = notificationIcon(notification.iconUrl()); + VBox copy = new VBox(4); + HBox titleLine = new HBox(6); + titleLine.setAlignment(Pos.CENTER_LEFT); + Label title = new Label(value(notification.title(), "Notification")); + title.getStyleClass().add("notification-title"); + title.setMaxWidth(Double.MAX_VALUE); + titleLine.getChildren().add(title); + if (!notification.read()) { + Region rowUnreadDot = new Region(); + rowUnreadDot.getStyleClass().add("notification-unread-dot"); + titleLine.getChildren().add(rowUnreadDot); + } + + Label message = new Label(value(notification.message(), "")); + message.getStyleClass().add("notification-message"); + message.setWrapText(true); + Label date = new Label(formatDate(notification.createdAt())); + date.getStyleClass().add("notification-date"); + copy.getChildren().addAll(titleLine, message); + if (notification.actionable()) { + HBox decisions = new HBox(8); + decisions.getStyleClass().add("notification-decisions"); + Button accept = primaryButton("Accept"); + accept.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 13)); + accept.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + accept.setOnAction(event -> resolveAction(notification, true)); + Button decline = dangerButton("Decline"); + decline.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.X, 13)); + decline.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + decline.setOnAction(event -> resolveAction(notification, false)); + decisions.getChildren().addAll(accept, decline); + copy.getChildren().add(decisions); + } else { + copy.getChildren().add(date); + } + HBox.setHgrow(copy, Priority.ALWAYS); + + VBox actions = new VBox(6); + actions.getStyleClass().add("notification-row-actions"); + actions.setAlignment(Pos.TOP_RIGHT); + Button dismiss = iconAction(LauncherIcons.Glyph.X, "Dismiss"); + dismiss.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + dismiss.setOnAction(event -> dismiss(notification)); + Button read = iconAction(LauncherIcons.Glyph.CIRCLE, notification.read() ? "Mark unread" : "Mark read"); + read.addEventFilter(MouseEvent.MOUSE_CLICKED, MouseEvent::consume); + pseudo(read, "selected", !notification.read()); + read.setOnAction(event -> toggleRead(notification)); + actions.getChildren().addAll(dismiss, read); + + row.getChildren().addAll(icon, copy, actions); + return row; + } + + private StackPane notificationIcon(String iconUrl) { + ImageView image = new ImageView(); + image.getStyleClass().add("notification-image"); + image.setFitWidth(NOTIFICATION_ICON_SIZE); + image.setFitHeight(NOTIFICATION_ICON_SIZE); + image.setSmooth(true); + Rectangle clip = new Rectangle(NOTIFICATION_ICON_SIZE, NOTIFICATION_ICON_SIZE); + clip.setArcWidth(8); + clip.setArcHeight(8); + image.setClip(clip); + imageLoader.loadInto(image, iconUrl, NOTIFICATION_ICON_SIZE, NOTIFICATION_ICON_SIZE); + StackPane icon = new StackPane(LauncherIcons.icon(LauncherIcons.Glyph.BELL, 18), image); + icon.getStyleClass().add("notification-image-shell"); + return icon; + } + + private Button iconAction(LauncherIcons.Glyph glyph, String tooltipText) { + Button button = new Button(null, LauncherIcons.icon(glyph, 14)); + button.getStyleClass().addAll("icon-btn", "notification-icon-button"); + button.setMnemonicParsing(false); + button.setAccessibleText(tooltipText); + button.setTooltip(new Tooltip(tooltipText)); + return button; + } + + private int unreadCount() { + return (int) notifications.stream().filter(item -> !item.read()).count(); + } + + private static String formatDate(LocalDateTime createdAt) { + return createdAt == null ? "" : NOTIFICATION_DATE.format(createdAt); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/ProjectBrowseController.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/ProjectBrowseController.java new file mode 100644 index 00000000..6c925f17 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/ProjectBrowseController.java @@ -0,0 +1,1040 @@ +package net.modtale.launcher.ui.browse; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; +import static net.modtale.launcher.ui.common.LauncherUi.secondaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.setVisibleManaged; +import static net.modtale.launcher.ui.common.LauncherUi.styleCombo; +import static net.modtale.launcher.ui.common.LauncherUi.styleInput; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.BiConsumer; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.PauseTransition; +import javafx.animation.Timeline; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.collections.FXCollections; +import javafx.event.EventTarget; +import javafx.geometry.Bounds; +import javafx.geometry.Point2D; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.control.Tooltip; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.util.Duration; +import javafx.util.StringConverter; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.api.ProjectSearchQuery; +import net.modtale.launcher.model.project.GameVersionCatalog; +import net.modtale.launcher.model.project.ProjectPage; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.ui.browse.card.ProjectCardFactory; +import net.modtale.launcher.ui.browse.controls.BrowseOptions; +import net.modtale.launcher.ui.browse.controls.ProjectBrowseCategories; +import net.modtale.launcher.ui.browse.controls.ProjectBrowseDownloadTimeframeSelector; +import net.modtale.launcher.ui.browse.controls.ProjectBrowseFilterOptions; +import net.modtale.launcher.ui.browse.controls.ProjectBrowseSort; +import net.modtale.launcher.ui.browse.controls.ProjectBrowseTags; +import net.modtale.launcher.ui.browse.controls.ProjectBrowseViewStyleSelector; +import net.modtale.launcher.ui.browse.render.ProjectBrowserRenderer; +import net.modtale.launcher.ui.browse.search.ProjectBrowseSearchState; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherScrollSupport; +import net.modtale.launcher.ui.common.LauncherView; + +public final class ProjectBrowseController { + + private static final double RESULTS_INDICATOR_WIDTH = 126; + private static final double RESULTS_INDICATOR_SHOW_BUFFER = 10; + private static final Duration PAGINATION_SCROLL_DURATION = Duration.millis(420); + private static final Interpolator PAGINATION_SCROLL_EASE = Interpolator.SPLINE(0.16, 1.0, 0.30, 1.0); + + private final ModtaleApiClient apiClient; + private final Executor executor; + private final Runnable applySettings; + private final Consumer status; + private final Supplier idleStatus; + private final Consumer log; + private final BiConsumer toast; + private final Runnable showDiscover; + private final Supplier currentView; + private final BooleanSupplier modtaleApiAvailable; + private final TextField searchField = new TextField(); + private final ComboBox sortCombo = new ComboBox<>(); + private final ComboBox pageSizeCombo = new ComboBox<>(); + private final StackPane projectResults = new StackPane(); + private final Label resultsIndicator = new Label("0 Results"); + private final FlowPane paginationNav = new FlowPane(24, 12); + private final HBox paginationPageShell = new HBox(4); + private final HBox paginationPageButtons = new HBox(4); + private final HBox paginationJumpShell = new HBox(12); + private final TextField jumpPageField = new TextField(); + private final PauseTransition searchDebounce = new PauseTransition(Duration.millis(450)); + private final ChangeListener layoutResizeListener = (observable, oldValue, newValue) -> + scheduleLayoutRefresh(oldValue, newValue); + private final ProjectBrowserRenderer renderer; + private final ProjectBrowseCategories categories; + private final ProjectBrowseTags tags; + private final ProjectBrowseViewStyleSelector viewStyles; + private final ProjectBrowseFilterOptions filterOptions; + private final ProjectBrowseDownloadTimeframeSelector downloadTimeframes; + private final ProjectBrowseSearchState searchState = new ProjectBrowseSearchState(); + private final VBox sortDropdown = new VBox(); + private final Map sortOptionButtons = new LinkedHashMap<>(); + private final Map sortOptionChecks = new LinkedHashMap<>(); + + private Button tagToggleButton; + private Button filterToggleButton; + private Button sortButton; + private Label sortButtonLabel; + private Timeline paginationScrollTimeline; + private Button previousPageButton; + private Button nextPageButton; + private Button jumpPageButton; + private StackPane browseRoot; + private Node view; + private List currentProjects = List.of(); + private boolean suppressSearch; + private boolean layoutRefreshScheduled; + private int currentPage; + private int totalPageCount; + private long totalResultCount; + private BrowseOptions.BrowseViewOption activeBrowseView = BrowseOptions.BrowseViewOption.defaultOption(); + + public ProjectBrowseController( + ModtaleApiClient apiClient, + Executor executor, + ProjectCardFactory projectCardFactory, + StackPane viewDeck, + Supplier contentBody, + LauncherScrollSupport scrollSupport, + Runnable applySettings, + Consumer status, + Supplier idleStatus, + Consumer log, + BiConsumer toast, + Runnable showDiscover, + Supplier currentView, + BooleanSupplier modtaleApiAvailable, + Function favoriteResolver, + Supplier gameVersion, + Consumer onInstall, + Consumer onOpenPage, + Consumer onOpenCreator, + Consumer onToggleFavorite + ) { + this.apiClient = apiClient; + this.executor = executor; + this.applySettings = applySettings; + this.status = status; + this.idleStatus = idleStatus; + this.log = log; + this.toast = toast; + this.showDiscover = showDiscover; + this.currentView = currentView; + this.modtaleApiAvailable = modtaleApiAvailable == null ? () -> true : modtaleApiAvailable; + this.renderer = new ProjectBrowserRenderer(projectResults, viewDeck, contentBody, projectCardFactory, + favoriteResolver, gameVersion, onInstall, onOpenPage, onOpenCreator, onToggleFavorite); + this.categories = new ProjectBrowseCategories(scrollSupport, this::searchProjects); + this.tags = new ProjectBrowseTags(this::searchProjects, this::refreshBrowseControls); + this.viewStyles = new ProjectBrowseViewStyleSelector(this::searchProjects); + this.filterOptions = new ProjectBrowseFilterOptions( + this::searchProjects, + this::refreshBrowseControls, + tags::clear + ); + this.downloadTimeframes = new ProjectBrowseDownloadTimeframeSelector( + filterOptions::selectDateRange, + filterOptions::selectedDateRange + ); + configureInputs(); + } + + public TextField searchField() { + return searchField; + } + + public Node view() { + if (view == null) { + view = buildView(); + } + return view; + } + + public BrowseOptions.BrowseViewOption activeBrowseView() { + return activeBrowseView; + } + + public String title() { + if (!tags.isEmpty()) { + return tags.title(); + } + BrowseOptions.BrowseViewOption viewOption = BrowseOptions.browseView(activeBrowseView); + if (viewOption.isDefault()) { + String sortTitle = selectedSort().title(); + if (!sortTitle.isBlank()) { + return sortTitle; + } + BrowseOptions.ClassificationOption selectedClassification = categories.selectedClassification(); + return selectedClassification.isDefault() + ? "All Projects" + : "All " + selectedClassification.label(); + } + return viewOption.label(); + } + + public String subtitle() { + BrowseOptions.BrowseViewOption viewOption = BrowseOptions.browseView(activeBrowseView); + if (!viewOption.isDefault()) { + return "Browse " + viewOption.label().toLowerCase(Locale.ROOT) + " with the same filters as the web catalog."; + } + return "Browse the Modtale catalog and install compatible Hytale projects."; + } + + public void selectBrowseView(BrowseOptions.BrowseViewOption browseView) { + BrowseOptions.BrowseViewOption selected = BrowseOptions.browseView(browseView); + activeBrowseView = selected; + withSuppressedSearch(() -> sortCombo.setValue(selected.defaultSort())); + refreshBrowseControls(); + showDiscover.run(); + searchProjects(); + } + + public void selectClassification(BrowseOptions.ClassificationOption classification) { + activeBrowseView = BrowseOptions.BrowseViewOption.defaultOption(); + withSuppressedSearch(() -> sortCombo.setValue(ProjectBrowseSort.defaultSort())); + refreshBrowseControls(); + showDiscover.run(); + categories.selectClassification(classification); + } + + public void selectDefaultBrowsePage() { + withSuppressedSearch(() -> { + activeBrowseView = BrowseOptions.BrowseViewOption.defaultOption(); + searchField.clear(); + sortCombo.setValue(ProjectBrowseSort.defaultSort()); + filterOptions.reset(false); + tags.popover().setVisible(false); + filterOptions.popover().setVisible(false); + }); + searchDebounce.stop(); + refreshBrowseControls(); + showDiscover.run(); + categories.selectClassification(BrowseOptions.ClassificationOption.defaultOption()); + } + + public void refreshControls() { + categories.refresh(); + tags.refresh(); + viewStyles.refresh(); + refreshBrowseControls(); + } + + public void loadGameVersionFilters() { + if (!modtaleApiAvailable.getAsBoolean()) { + return; + } + CompletableFuture.supplyAsync(this::loadGameVersionCatalog, executor) + .whenComplete((catalog, error) -> Platform.runLater(() -> { + if (error != null || catalog == null) { + return; + } + filterOptions.replaceGameVersionCatalog(catalog); + })); + } + + public void searchProjects() { + currentPage = 0; + requestProjects(); + } + + public void resetSearchQuery() { + if (searchField.getText().isEmpty()) { + return; + } + withSuppressedSearch(searchField::clear); + searchDebounce.stop(); + searchProjects(); + } + + private void requestProjects() { + if (suppressSearch) { + return; + } + if (!modtaleApiAvailable.getAsBoolean()) { + status.accept(idleStatus.get()); + log.accept("Sign in with Modtale to browse projects."); + toast.accept("Modtale sign-in required", "Sign in with Modtale to browse projects."); + return; + } + applySettings.run(); + ProjectSearchQuery query = searchQuery(); + long requestId = searchState.start(query); + if (requestId == ProjectBrowseSearchState.DUPLICATE_SEARCH) { + return; + } + + updateResultsIndicator(totalResultCount, true); + status.accept("Searching Modtale projects..."); + log.accept("Searching Modtale projects..."); + CompletableFuture.supplyAsync(() -> apiClient.searchProjects(query), executor) + .whenComplete((page, error) -> Platform.runLater(() -> { + if (!searchState.acceptCompletion(query, requestId)) { + return; + } + status.accept(idleStatus.get()); + if (error != null) { + Throwable cause = error.getCause() == null ? error : error.getCause(); + updateResultsIndicator(totalResultCount, false); + updatePaginationControls(); + log.accept("Error: " + cause.getMessage()); + toast.accept("Search failed", cause.getMessage()); + return; + } + finishSearch(page, query); + })); + } + + public void renderProjects() { + renderer.render(currentProjects, viewStyles.style(), selectedPageSize()); + } + + public void applyFavoriteDelta(String projectId, int delta) { + if (delta == 0) { + return; + } + currentProjects = currentProjects.stream() + .map(item -> item.id().equals(projectId) + ? item.withFavoriteCount(item.favoriteCount() + delta) + : item) + .toList(); + } + + private Node buildView() { + VBox content = new VBox(16); + content.getStyleClass().add("browse-content"); + content.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + + VBox filters = new VBox(10); + filters.getStyleClass().add("browse-filter-shell"); + + HBox browseControls = new HBox(12); + browseControls.getStyleClass().add("browse-filter-row"); + browseControls.setAlignment(Pos.CENTER_LEFT); + + HBox controlRow = new HBox(8); + controlRow.getStyleClass().add("browse-control-group"); + controlRow.setAlignment(Pos.CENTER_RIGHT); + controlRow.setMinWidth(Region.USE_PREF_SIZE); + tagToggleButton = popoverToggle("Tags", LauncherIcons.Glyph.TAG, tags.popover()); + filterToggleButton = popoverToggle("Filters", LauncherIcons.Glyph.FILTER, filterOptions.popover()); + sortButton = sortControl(); + controlRow.getChildren().addAll( + pageSizeCombo, + viewStyles.view(), + tagToggleButton, + filterToggleButton, + downloadTimeframes.view(), + sortButton + ); + resultsIndicator.getStyleClass().add("browse-results-indicator"); + resultsIndicator.setAlignment(Pos.CENTER_LEFT); + resultsIndicator.setMinWidth(RESULTS_INDICATOR_WIDTH); + resultsIndicator.setPrefWidth(RESULTS_INDICATOR_WIDTH); + resultsIndicator.setMaxWidth(RESULTS_INDICATOR_WIDTH); + resultsIndicator.setMouseTransparent(true); + resultsIndicator.setAccessibleText("Browse results status"); + Node categoryPills = categories.view(); + HBox.setHgrow(categoryPills, Priority.NEVER); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + browseControls.getChildren().addAll(categoryPills, resultsIndicator, spacer, controlRow); + configureResultsIndicatorVisibility(browseControls, controlRow); + + filters.getChildren().add(browseControls); + + projectResults.getStyleClass().add("project-results"); + projectResults.setMaxWidth(Double.MAX_VALUE); + projectResults.setAlignment(Pos.TOP_LEFT); + VBox.setVgrow(projectResults, Priority.ALWAYS); + configurePagination(); + content.getChildren().addAll(filters, projectResults, paginationNav); + + configureSortDropdown(); + StackPane root = new StackPane(content, tags.popover(), filterOptions.popover(), sortDropdown); + browseRoot = root; + root.setUserData(LauncherView.DISCOVER); + root.getStyleClass().addAll("view", "browse-view"); + root.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + root.addEventFilter(MouseEvent.MOUSE_PRESSED, this::hideFilterDropdownsOnOutsidePress); + return root; + } + + private GameVersionCatalog loadGameVersionCatalog() { + try { + return apiClient.getGameVersionCatalog(); + } catch (RuntimeException ex) { + return GameVersionCatalog.fromVersions(apiClient.getGameVersions()); + } + } + + private void configureInputs() { + sortCombo.setItems(FXCollections.observableArrayList(ProjectBrowseSort.DOWNLOADS, ProjectBrowseSort.FAVORITES)); + sortCombo.setValue(ProjectBrowseSort.defaultSort()); + sortCombo.setConverter(new StringConverter<>() { + @Override + public String toString(ProjectBrowseSort value) { + return value == null ? ProjectBrowseSort.defaultSort().label() : value.label(); + } + + @Override + public ProjectBrowseSort fromString(String value) { + return ProjectBrowseSort.fromLabel(value); + } + }); + sortCombo.setOnAction(event -> { + refreshBrowseControls(); + if (!suppressSearch) { + activeBrowseView = selectedSort().browseView(); + showDiscover.run(); + } + searchProjects(); + }); + sortCombo.valueProperty().addListener((observable, oldValue, newValue) -> refreshSortDropdown()); + pageSizeCombo.setItems(FXCollections.observableArrayList(BrowseOptions.BROWSE_ITEMS_PER_PAGE_OPTIONS)); + pageSizeCombo.setValue(BrowseOptions.DEFAULT_ITEMS_PER_PAGE); + pageSizeCombo.setConverter(new StringConverter<>() { + @Override + public String toString(Integer value) { + return Integer.toString(BrowseOptions.itemsPerPage(value)); + } + + @Override + public Integer fromString(String value) { + if (value == null || value.isBlank()) { + return BrowseOptions.DEFAULT_ITEMS_PER_PAGE; + } + try { + return BrowseOptions.itemsPerPage(Integer.parseInt(value.trim())); + } catch (NumberFormatException ignored) { + return BrowseOptions.DEFAULT_ITEMS_PER_PAGE; + } + } + }); + pageSizeCombo.setOnAction(event -> { + tags.popover().setVisible(false); + filterOptions.popover().setVisible(false); + hideSortDropdown(); + searchProjects(); + }); + pageSizeCombo.setTooltip(new Tooltip("Results per page")); + pageSizeCombo.setAccessibleText("Results per page"); + styleCombo(pageSizeCombo); + pageSizeCombo.setMinWidth(68); + pageSizeCombo.setPrefWidth(68); + pageSizeCombo.setMaxWidth(68); + pageSizeCombo.getStyleClass().add("page-size-select"); + searchDebounce.setOnFinished(event -> searchProjects()); + searchField.textProperty().addListener((observable, oldValue, newValue) -> searchDebounce.playFromStart()); + projectResults.widthProperty().addListener(layoutResizeListener); + projectResults.heightProperty().addListener(layoutResizeListener); + projectResults.sceneProperty().addListener((observable, oldScene, newScene) -> + observeSceneResizes(oldScene, newScene)); + styleInput(searchField); + refreshBrowseControls(); + } + + private void configurePagination() { + paginationNav.getStyleClass().add("pagination-nav"); + paginationNav.setAlignment(Pos.CENTER); + paginationNav.setMaxWidth(Double.MAX_VALUE); + + paginationPageShell.getStyleClass().add("pagination-page-shell"); + paginationPageShell.setAlignment(Pos.CENTER); + previousPageButton = paginationIconButton(LauncherIcons.Glyph.CHEVRON_LEFT, "Previous Page"); + nextPageButton = paginationIconButton(LauncherIcons.Glyph.CHEVRON_RIGHT, "Next Page"); + paginationPageShell.getChildren().setAll(previousPageButton, paginationPageButtons, nextPageButton); + + paginationPageButtons.getStyleClass().add("pagination-page-buttons"); + paginationPageButtons.setAlignment(Pos.CENTER); + + paginationJumpShell.getStyleClass().add("pagination-jump-shell"); + paginationJumpShell.setAlignment(Pos.CENTER); + Label jumpLabel = new Label("JUMP"); + jumpLabel.getStyleClass().add("pagination-jump-label"); + jumpPageField.setPromptText("#"); + jumpPageField.getStyleClass().add("pagination-jump-input"); + jumpPageField.setOnAction(event -> submitJumpPage()); + jumpPageField.textProperty().addListener((observable, oldValue, newValue) -> updateJumpPageState()); + jumpPageButton = paginationIconButton(LauncherIcons.Glyph.CORNER_DOWN_LEFT, "Go"); + jumpPageButton.getStyleClass().add("pagination-jump-button"); + jumpPageButton.setOnAction(event -> submitJumpPage()); + paginationJumpShell.getChildren().setAll(jumpLabel, jumpPageField, jumpPageButton); + + paginationNav.getChildren().setAll(paginationPageShell, paginationJumpShell); + updatePaginationControls(); + } + + private Button paginationIconButton(LauncherIcons.Glyph glyph, String accessibleText) { + Button button = new Button(); + button.getStyleClass().addAll("pagination-button", "pagination-icon-button"); + button.setGraphic(LauncherIcons.icon(glyph, 16)); + button.setAccessibleText(accessibleText); + button.setMinSize(36, 36); + button.setPrefSize(36, 36); + button.setMaxSize(36, 36); + return button; + } + + private Button sortControl() { + Button button = new Button(); + button.getStyleClass().add("sort-button"); + sortButtonLabel = new Label(selectedSort().label()); + sortButtonLabel.getStyleClass().add("sort-button-label"); + sortButtonLabel.setAlignment(Pos.CENTER); + Node chevron = LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_DOWN, 14); + chevron.getStyleClass().add("sort-button-chevron"); + HBox content = new HBox(6, sortButtonLabel, chevron); + content.getStyleClass().add("sort-button-content"); + content.setAlignment(Pos.CENTER); + button.setGraphic(content); + button.setOnAction(event -> toggleSortDropdown()); + refreshSortDropdown(); + return button; + } + + private void configureSortDropdown() { + sortDropdown.getStyleClass().add("sort-dropdown-panel"); + sortDropdown.setMinWidth(192); + sortDropdown.setPrefWidth(192); + sortDropdown.setMaxWidth(192); + sortDropdown.setVisible(false); + sortDropdown.setManaged(false); + sortDropdown.getChildren().setAll( + sortDropdownItem(ProjectBrowseSort.DOWNLOADS), + sortDropdownItem(ProjectBrowseSort.FAVORITES) + ); + refreshSortDropdown(); + } + + private Button sortDropdownItem(ProjectBrowseSort sort) { + Button item = new Button(); + item.getStyleClass().add("sort-dropdown-item"); + Label label = new Label(sort.label()); + label.getStyleClass().add("sort-dropdown-item-label"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Node check = LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 15); + check.getStyleClass().add("sort-dropdown-check"); + HBox content = new HBox(8, label, spacer, check); + content.setAlignment(Pos.CENTER_LEFT); + item.setGraphic(content); + item.setMaxWidth(Double.MAX_VALUE); + item.setOnAction(event -> selectSort(sort)); + sortOptionButtons.put(sort, item); + sortOptionChecks.put(sort, check); + return item; + } + + private void toggleSortDropdown() { + if (sortDropdown.isVisible()) { + hideSortDropdown(); + return; + } + tags.popover().setVisible(false); + filterOptions.popover().setVisible(false); + sortDropdown.setVisible(true); + sortDropdown.toFront(); + positionFilterDropdown(sortButton, sortDropdown, true); + Platform.runLater(() -> positionFilterDropdown(sortButton, sortDropdown, true)); + refreshSortDropdown(); + } + + private void hideSortDropdown() { + sortDropdown.setVisible(false); + refreshSortDropdown(); + } + + private void selectSort(ProjectBrowseSort sort) { + hideSortDropdown(); + sortCombo.setValue(sort); + refreshSortDropdown(); + } + + private void refreshSortDropdown() { + ProjectBrowseSort selected = selectedSort(); + if (sortButtonLabel != null) { + sortButtonLabel.setText(selected.label()); + } + if (sortButton != null) { + pseudo(sortButton, "selected", sortDropdown.isVisible()); + } + sortOptionButtons.forEach((sort, button) -> pseudo(button, "selected", sort == selected)); + sortOptionChecks.forEach((sort, check) -> check.setVisible(sort == selected)); + } + + private Button popoverToggle(String label, LauncherIcons.Glyph icon, VBox popover) { + Button button = secondaryButton(label); + button.getStyleClass().add("toolbar-pill"); + button.setGraphic(LauncherIcons.icon(icon, 15)); + double width = "Filters".equals(label) ? 92 : 80; + button.setMinWidth(width); + button.setOnAction(event -> { + boolean nextVisible = !popover.isVisible(); + tags.popover().setVisible(false); + filterOptions.popover().setVisible(false); + hideSortDropdown(); + popover.setVisible(nextVisible); + if (nextVisible) { + positionFilterDropdown(button, popover, "Filters".equals(label)); + popover.toFront(); + Platform.runLater(() -> positionFilterDropdown(button, popover, "Filters".equals(label))); + } + updateBrowseControlBadges(); + }); + popover.visibleProperty().addListener((observable, oldValue, visible) -> { + if (visible) { + positionFilterDropdown(button, popover, "Filters".equals(label)); + popover.toFront(); + } + updateBrowseControlBadges(); + scheduleLayoutRefresh(null, null); + }); + return button; + } + + private void positionFilterDropdown(Button anchor, VBox popover, boolean rightAligned) { + if (browseRoot == null || anchor == null || popover == null || anchor.getScene() == null) { + return; + } + popover.applyCss(); + popover.autosize(); + Bounds anchorBounds = anchor.localToScene(anchor.getBoundsInLocal()); + if (anchorBounds == null) { + return; + } + Point2D anchorMin = browseRoot.sceneToLocal(anchorBounds.getMinX(), anchorBounds.getMinY()); + Point2D anchorMax = browseRoot.sceneToLocal(anchorBounds.getMaxX(), anchorBounds.getMaxY()); + double width = popover.getLayoutBounds().getWidth() > 0 ? popover.getLayoutBounds().getWidth() : popover.prefWidth(-1); + double maxX = Math.max(8, browseRoot.getWidth() - width - 8); + double x = rightAligned ? anchorMax.getX() - width : anchorMin.getX(); + double y = anchorMax.getY() + 8; + popover.relocate(clamp(x, 8, maxX), y); + } + + private void hideFilterDropdownsOnOutsidePress(MouseEvent event) { + boolean tagsVisible = tags.popover().isVisible(); + boolean filtersVisible = filterOptions.popover().isVisible(); + boolean sortVisible = sortDropdown.isVisible(); + if (!tagsVisible && !filtersVisible && !sortVisible) { + return; + } + EventTarget target = event.getTarget(); + if (tagsVisible + && !eventTargetInside(target, tags.popover()) + && !eventTargetInside(target, tagToggleButton)) { + tags.popover().setVisible(false); + } + if (filtersVisible + && !eventTargetInside(target, filterOptions.popover()) + && !eventTargetInside(target, filterToggleButton)) { + filterOptions.popover().setVisible(false); + } + if (sortVisible + && !eventTargetInside(target, sortDropdown) + && !eventTargetInside(target, sortButton)) { + hideSortDropdown(); + } + } + + private static boolean eventTargetInside(EventTarget target, Node root) { + if (!(target instanceof Node node) || root == null) { + return false; + } + for (Node current = node; current != null; current = current.getParent()) { + if (current == root) { + return true; + } + } + return false; + } + + private static double clamp(double value, double min, double max) { + if (max < min) { + return min; + } + return Math.max(min, Math.min(value, max)); + } + + private void updateBrowseControlBadges() { + if (tagToggleButton != null) { + tagToggleButton.setText(tags.isEmpty() ? "Tags" : "Tags " + tags.selectedCount()); + pseudo(tagToggleButton, "selected", !tags.isEmpty() || tags.popover().isVisible()); + } + if (filterToggleButton != null) { + int count = filterOptions.activeFilterCount(); + filterToggleButton.setText(count == 0 ? "Filters" : "Filters " + count); + pseudo(filterToggleButton, "selected", count > 0 || filterOptions.popover().isVisible()); + } + } + + private void refreshBrowseControls() { + boolean downloadSort = isDownloadSort(); + filterOptions.setDownloadSort(downloadSort); + downloadTimeframes.setVisible(downloadSort); + downloadTimeframes.refresh(); + updateBrowseControlBadges(); + refreshSortDropdown(); + } + + private boolean isDownloadSort() { + return selectedSort() == ProjectBrowseSort.DOWNLOADS; + } + + private ProjectSearchQuery searchQuery() { + BrowseOptions.BrowseViewOption browseViewOption = BrowseOptions.browseView(activeBrowseView); + return new ProjectSearchQuery( + searchField.getText(), + categories.selectedClassification().apiValue(), + filterOptions.selectedGameVersion(), + selectedSort().apiValue(), + currentPage, + selectedPageSize(), + tags.selectedQuery(), + filterOptions.selectedMinimumDownloads(), + filterOptions.selectedMinimumFavorites(), + browseViewOption.category(), + filterOptions.selectedDateRange(), + filterOptions.selectedOpenSource() + ); + } + + private ProjectBrowseSort selectedSort() { + return sortCombo.getValue() == null ? ProjectBrowseSort.defaultSort() : sortCombo.getValue(); + } + + private void withSuppressedSearch(Runnable work) { + boolean previous = suppressSearch; + suppressSearch = true; + try { + work.run(); + } finally { + suppressSearch = previous; + } + } + + private int selectedPageSize() { + return BrowseOptions.itemsPerPage(pageSizeCombo.getValue()); + } + + private void finishSearch(ProjectPage page, ProjectSearchQuery query) { + if (page == null) { + return; + } + int nextTotalPages = Math.max(0, page.totalPages()); + if (nextTotalPages > 0 && query.page() >= nextTotalPages) { + totalPageCount = nextTotalPages; + currentPage = nextTotalPages - 1; + updatePaginationControls(); + requestProjects(); + return; + } + + searchState.recordCompleted(query); + totalPageCount = nextTotalPages; + currentPage = totalPageCount == 0 + ? 0 + : (int) clamp(query.page(), 0, totalPageCount - 1); + currentProjects = page.content(); + totalResultCount = Math.max(0, page.totalElements()); + updateResultsIndicator(totalResultCount, false); + updatePaginationControls(); + renderProjects(); + log.accept("Found " + page.content().size() + " projects."); + ProjectSearchQuery nextQuery = searchQuery(); + if (!nextQuery.equals(query) && searchState.shouldSearchForLayout(nextQuery, currentProjects)) { + requestProjects(); + } + } + + private void renderProjectsForLayoutChange() { + if (currentProjects.isEmpty()) { + return; + } + renderProjects(); + ProjectSearchQuery nextQuery = searchQuery(); + if (searchState.shouldSearchForLayout(nextQuery, currentProjects)) { + requestProjects(); + } + } + + private void updatePaginationControls() { + boolean showPagination = totalPageCount > 1; + setVisibleManaged(paginationNav, showPagination); + if (!showPagination || previousPageButton == null || nextPageButton == null || jumpPageButton == null) { + return; + } + + previousPageButton.setDisable(currentPage <= 0); + previousPageButton.setOnAction(event -> goToPage(currentPage - 1)); + nextPageButton.setDisable(currentPage >= totalPageCount - 1); + nextPageButton.setOnAction(event -> goToPage(currentPage + 1)); + + paginationPageButtons.getChildren().clear(); + for (PageToken token : pageTokens(currentPage, totalPageCount)) { + if (token.ellipsis()) { + Label dots = new Label("..."); + dots.getStyleClass().add("pagination-dots"); + paginationPageButtons.getChildren().add(dots); + continue; + } + + int targetPage = token.page(); + Button button = new Button(Integer.toString(targetPage + 1)); + button.getStyleClass().add("pagination-button"); + button.setMinSize(36, 36); + button.setPrefSize(36, 36); + button.setMaxSize(36, 36); + button.setAccessibleText("Page " + (targetPage + 1)); + button.setOnAction(event -> goToPage(targetPage)); + pseudo(button, "selected", targetPage == currentPage); + paginationPageButtons.getChildren().add(button); + } + updateJumpPageState(); + } + + private void updateJumpPageState() { + if (jumpPageButton == null) { + return; + } + jumpPageButton.setDisable(jumpPageField.getText() == null || jumpPageField.getText().isBlank()); + } + + private void submitJumpPage() { + String rawPage = jumpPageField.getText(); + jumpPageField.clear(); + if (rawPage == null || rawPage.isBlank()) { + return; + } + try { + int targetPage = Integer.parseInt(rawPage.trim()) - 1; + goToPage(targetPage); + } catch (NumberFormatException ignored) { + // Invalid jump values are intentionally treated like the web form: clear and stay put. + } + } + + private void goToPage(int page) { + if (page < 0 || page >= totalPageCount || page == currentPage) { + return; + } + currentPage = page; + requestProjects(); + animateBrowseToTop(); + } + + private void animateBrowseToTop() { + ScrollPane scrollPane = enclosingScrollPane(); + if (scrollPane != null) { + animateBrowseToTop(scrollPane); + } + Platform.runLater(() -> { + ScrollPane nextScrollPane = enclosingScrollPane(); + if (nextScrollPane != null && Math.abs(nextScrollPane.getVvalue() - nextScrollPane.getVmin()) > 0.001) { + animateBrowseToTop(nextScrollPane); + } + }); + } + + private void animateBrowseToTop(ScrollPane scrollPane) { + if (paginationScrollTimeline != null) { + paginationScrollTimeline.stop(); + } + + double start = scrollPane.getVvalue(); + double end = scrollPane.getVmin(); + if (Math.abs(start - end) <= 0.001) { + scrollPane.setVvalue(end); + return; + } + + Timeline timeline = new Timeline( + new KeyFrame(Duration.ZERO, new KeyValue(scrollPane.vvalueProperty(), start)), + new KeyFrame(PAGINATION_SCROLL_DURATION, + new KeyValue(scrollPane.vvalueProperty(), end, PAGINATION_SCROLL_EASE)) + ); + paginationScrollTimeline = timeline; + timeline.setOnFinished(event -> { + scrollPane.setVvalue(end); + if (paginationScrollTimeline == timeline) { + paginationScrollTimeline = null; + } + }); + timeline.play(); + } + + private ScrollPane enclosingScrollPane() { + for (Node current = browseRoot; current != null; current = current.getParent()) { + if (current instanceof ScrollPane scrollPane) { + return scrollPane; + } + } + return null; + } + + private static List pageTokens(int currentPage, int totalPages) { + int total = Math.max(0, totalPages); + int current = Math.max(0, currentPage) + 1; + int delta = 2; + Set range = new LinkedHashSet<>(); + if (total >= 1) { + range.add(1); + } + for (int i = current - delta; i <= current + delta; i++) { + if (i < total && i > 1) { + range.add(i); + } + } + if (total > 1) { + range.add(total); + } + + List sorted = new ArrayList<>(range); + sorted.sort(Integer::compareTo); + List tokens = new ArrayList<>(); + Integer previous = null; + for (Integer page : sorted) { + if (previous != null) { + if (page - previous == 2) { + tokens.add(PageToken.page(previous)); + } else if (page - previous != 1) { + tokens.add(PageToken.gap()); + } + } + tokens.add(PageToken.page(page - 1)); + previous = page; + } + return tokens; + } + + private void configureResultsIndicatorVisibility(HBox browseControls, HBox controlRow) { + ChangeListener sizeListener = (observable, oldValue, newValue) -> + scheduleResultsIndicatorVisibilityUpdate(browseControls, controlRow); + browseControls.widthProperty().addListener(sizeListener); + controlRow.widthProperty().addListener(sizeListener); + categories.contentWidthProperty().addListener(sizeListener); + categories.overflowingProperty().addListener((observable, oldValue, newValue) -> + scheduleResultsIndicatorVisibilityUpdate(browseControls, controlRow)); + browseControls.sceneProperty().addListener((observable, oldScene, newScene) -> + scheduleResultsIndicatorVisibilityUpdate(browseControls, controlRow)); + scheduleResultsIndicatorVisibilityUpdate(browseControls, controlRow); + } + + private void scheduleResultsIndicatorVisibilityUpdate(HBox browseControls, HBox controlRow) { + Platform.runLater(() -> updateResultsIndicatorVisibility(browseControls, controlRow)); + } + + private void updateResultsIndicatorVisibility(HBox browseControls, HBox controlRow) { + double rowWidth = browseControls.getWidth(); + double categoryWidth = categories.contentWidth(); + if (!Double.isFinite(rowWidth) || rowWidth <= 0 + || !Double.isFinite(categoryWidth) || categoryWidth <= 0) { + return; + } + + double controlsWidth = measuredOrPref(controlRow.getWidth(), controlRow.prefWidth(-1)); + double availableCategoryWidthWithIndicator = rowWidth + - controlsWidth + - RESULTS_INDICATOR_WIDTH + - browseControls.getSpacing() * 3; + boolean canShowIndicator = availableCategoryWidthWithIndicator + >= categoryWidth + RESULTS_INDICATOR_SHOW_BUFFER; + setVisibleManaged(resultsIndicator, canShowIndicator); + } + + private double measuredOrPref(double measured, double pref) { + if (Double.isFinite(measured) && measured > 0) { + return measured; + } + return Double.isFinite(pref) && pref > 0 ? pref : 0; + } + + private void updateResultsIndicator(long totalItems, boolean searching) { + long safeTotal = Math.max(0, totalItems); + resultsIndicator.setText(searching + ? "SEARCHING..." + : String.format(Locale.US, "%,d %s", safeTotal, safeTotal == 1 ? "RESULT" : "RESULTS")); + pseudo(resultsIndicator, "searching", searching); + } + + private void observeSceneResizes(Scene oldScene, Scene newScene) { + if (oldScene != null) { + oldScene.widthProperty().removeListener(layoutResizeListener); + oldScene.heightProperty().removeListener(layoutResizeListener); + } + if (newScene != null) { + newScene.widthProperty().addListener(layoutResizeListener); + newScene.heightProperty().addListener(layoutResizeListener); + } + } + + private void scheduleLayoutRefresh(Number oldValue, Number newValue) { + if (oldValue == null || newValue == null + || Math.abs(newValue.doubleValue() - oldValue.doubleValue()) > 0.5) { + scheduleLayoutRefresh(); + } + } + + private void scheduleLayoutRefresh() { + if (layoutRefreshScheduled) { + return; + } + layoutRefreshScheduled = true; + Platform.runLater(() -> { + layoutRefreshScheduled = false; + if (currentView.get() == LauncherView.DISCOVER + && !currentProjects.isEmpty() + && renderer.shouldRenderForLayout(viewStyles.style(), selectedPageSize())) { + renderProjectsForLayoutChange(); + } + }); + } + + private record PageToken(Integer page, boolean ellipsis) { + + static PageToken page(int page) { + return new PageToken(page, false); + } + + static PageToken gap() { + return new PageToken(null, true); + } + } + +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFactory.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFactory.java new file mode 100644 index 00000000..fcf0ef93 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFactory.java @@ -0,0 +1,402 @@ +package net.modtale.launcher.ui.browse.card; + +import static net.modtale.launcher.ui.browse.card.ProjectCardFormatter.classificationLabel; +import static net.modtale.launcher.ui.browse.card.ProjectCardFormatter.number; +import static net.modtale.launcher.ui.browse.card.ProjectCardFormatter.value; +import static net.modtale.launcher.ui.browse.card.ProjectCardMedia.lockHeight; +import static net.modtale.launcher.ui.browse.card.ProjectCardMedia.lockWidth; + +import java.util.Optional; +import java.util.concurrent.Executor; +import java.util.function.Consumer; +import java.util.function.Function; +import javafx.css.PseudoClass; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.CacheHint; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.OverrunStyle; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import net.modtale.launcher.install.VersionSelector; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.ui.browse.controls.BrowseOptions; +import net.modtale.launcher.ui.common.LauncherIcons; + +public final class ProjectCardFactory { + + public static final String SCROLL_ACTIVE_PROPERTY = "net.modtale.launcher.scrollActive"; + + private static final double GRID_WIDTH = 400; + private static final double GRID_ICON_SIZE = 104; + private static final double GRID_BODY_PADDING = 22; + private static final double LIST_ICON_SIZE = 128; + private static final double COMPACT_WIDTH = 330; + private static final double CARD_STAT_HEIGHT = 38; + private static final double CARD_STAT_ICON_SIZE = 16; + private static final double COMPACT_STAT_ICON_SIZE = 14; + private static final double TITLE_FONT_SIZE = 20; + private static final double COMPACT_TITLE_FONT_SIZE = 14; + private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected"); + + private final ProjectCardMedia media; + + public ProjectCardFactory(Function assetResolver, Executor executor) { + this.media = new ProjectCardMedia(assetResolver, executor); + } + + public void clearImageCache() { + media.clearImageCache(); + } + + public Node create( + ProjectSummary project, + ProjectCardViewStyle viewStyle, + String gameVersion, + boolean favorite, + Consumer onInstall, + Consumer onOpenPage, + Consumer onOpenCreator, + Consumer onToggleFavorite, + double cardWidth, + double cardHeight + ) { + return switch (viewStyle) { + case LIST -> listCard(project, gameVersion, favorite, onInstall, onOpenPage, onOpenCreator, onToggleFavorite); + case COMPACT -> compactCard(project, gameVersion, favorite, onInstall, onOpenPage, onOpenCreator, onToggleFavorite, cardWidth, cardHeight); + case GRID -> gridCard(project, gameVersion, favorite, onInstall, onOpenPage, onOpenCreator, onToggleFavorite, cardWidth, cardHeight); + }; + } + + private Node gridCard( + ProjectSummary project, + String gameVersion, + boolean favorite, + Consumer onInstall, + Consumer onOpenPage, + Consumer onOpenCreator, + Consumer onToggleFavorite, + double cardWidth, + double cardHeight + ) { + double width = cardWidth > 0 ? cardWidth : GRID_WIDTH; + double height = cardHeight > 0 ? cardHeight : Math.round(width); + double bannerHeight = Math.round(width / 3.0); + double bodyHeight = Math.max(0, height - bannerHeight); + boolean tight = width < 390 || bodyHeight < 272; + boolean shelfTight = tight && bodyHeight < 216 && height < width * 0.95; + double bodyPadding = shelfTight ? 14 : GRID_BODY_PADDING; + double iconSize = shelfTight + ? Math.max(64, Math.min(72, Math.round(width * 0.215))) + : Math.max(84, Math.min(GRID_ICON_SIZE, Math.round(width * 0.215))); + double iconOverlap = Math.round(iconSize / 2.0); + double bodySpacing = shelfTight ? 3 : tight ? 5 : 6; + double copySpacing = shelfTight ? 3 : tight ? 6 : 8; + double descriptionHeight = shelfTight ? 24 : tight ? 44 : 52; + Optional latestVersion = latestCompatible(project, gameVersion); + StackPane shell = new StackPane(); + shell.getStyleClass().add("project-card-shell"); + shell.setAlignment(Pos.TOP_LEFT); + lockWidth(shell, width); + lockHeight(shell, height); + ProjectCardInteraction.openOnCardClick(shell, project, onOpenPage); + + VBox card = new VBox(0); + card.getStyleClass().addAll("project-card", "project-card-grid"); + cacheCardSurface(card); + lockWidth(card, width); + lockHeight(card, height); + + StackPane banner = media.banner(project, width, bannerHeight); + Node bannerMedia = banner.getChildren().isEmpty() ? null : banner.getChildren().get(0); + banner.getChildren().add(classificationBadge(project.classification())); + StackPane.setAlignment(banner.getChildren().getLast(), Pos.TOP_RIGHT); + StackPane.setMargin(banner.getChildren().getLast(), new Insets(8)); + + VBox body = new VBox(bodySpacing); + body.getStyleClass().add("project-card-body"); + if (shelfTight) { + body.getStyleClass().add("project-card-body-shelf-tight"); + } + lockHeight(body, bodyHeight); + VBox.setVgrow(body, Priority.ALWAYS); + StackPane icon = media.projectIcon(project, iconSize, 4); + VBox.setMargin(icon, new Insets(-(iconOverlap + bodyPadding), 0, 0, 0)); + + VBox copy = new VBox(copySpacing); + copy.getStyleClass().add("project-copy"); + Label title = titleText(value(project.title(), "Untitled Project"), "project-title", TITLE_FONT_SIZE); + title.setTextOverrun(OverrunStyle.ELLIPSIS); + Label description = text(value(project.description(), "No description provided."), "project-description"); + description.setWrapText(true); + description.setAlignment(Pos.TOP_LEFT); + description.setPrefHeight(descriptionHeight); + description.setMinHeight(descriptionHeight); + description.setMaxHeight(descriptionHeight); + VBox.setMargin(description, new Insets(tight ? 1 : 2, 0, 0, 0)); + copy.getChildren().addAll(title, authorLine(project, "By", "byline", onOpenCreator), description); + + Region footerSpacer = new Region(); + VBox.setVgrow(footerSpacer, Priority.ALWAYS); + body.getChildren().addAll(icon, copy, footerSpacer, + installStatsRow(project, latestVersion, favorite, onInstall, onToggleFavorite, tight)); + card.getChildren().addAll(banner, body); + shell.getChildren().addAll(card, media.restingOutline(shell), media.hoverOutline(shell, shell)); + ProjectCardInteraction.addHoverAnimation(shell, icon, bannerMedia); + return shell; + } + + private Node listCard( + ProjectSummary project, + String gameVersion, + boolean favorite, + Consumer onInstall, + Consumer onOpenPage, + Consumer onOpenCreator, + Consumer onToggleFavorite + ) { + HBox card = new HBox(18); + card.getStyleClass().addAll("project-card", "project-card-list"); + cacheCardSurface(card); + card.setAlignment(Pos.TOP_LEFT); + card.setMaxWidth(Double.MAX_VALUE); + ProjectCardInteraction.openOnCardClick(card, project, onOpenPage); + Optional latestVersion = latestCompatible(project, gameVersion); + + StackPane icon = media.projectIcon(project, LIST_ICON_SIZE, 4); + VBox copy = new VBox(8); + copy.setMinWidth(0); + HBox.setHgrow(copy, Priority.ALWAYS); + + HBox titleRow = new HBox(12); + titleRow.setAlignment(Pos.TOP_LEFT); + Label title = titleText(value(project.title(), "Untitled Project"), "project-title", TITLE_FONT_SIZE); + title.setTextOverrun(OverrunStyle.ELLIPSIS); + HBox.setHgrow(title, Priority.ALWAYS); + titleRow.getChildren().addAll(title, classificationBadge(project.classification())); + + Label description = text(value(project.description(), "No description provided."), "project-description"); + description.setWrapText(true); + description.setMaxHeight(40); + copy.getChildren().addAll(titleRow, authorLine(project, "by", "byline", onOpenCreator), description, statsRow(project, favorite, onToggleFavorite)); + + VBox actions = new VBox(8); + actions.setAlignment(Pos.CENTER_RIGHT); + actions.getChildren().addAll(versionLabel(latestVersion), installButton(project, onInstall)); + card.getChildren().addAll(icon, copy, actions); + ProjectCardInteraction.addHoverAnimation(card, icon); + return card; + } + + private Node compactCard( + ProjectSummary project, + String gameVersion, + boolean favorite, + Consumer onInstall, + Consumer onOpenPage, + Consumer onOpenCreator, + Consumer onToggleFavorite, + double cardWidth, + double cardHeight + ) { + HBox card = new HBox(16); + card.getStyleClass().addAll("project-card", "project-card-compact"); + cacheCardSurface(card); + card.setAlignment(Pos.CENTER_LEFT); + lockWidth(card, cardWidth > 0 ? cardWidth : COMPACT_WIDTH); + if (cardHeight > 0) { + lockHeight(card, cardHeight); + } + ProjectCardInteraction.openOnCardClick(card, project, onOpenPage); + Optional latestVersion = latestCompatible(project, gameVersion); + + StackPane icon = media.projectIcon(project, 64, 2); + VBox copy = new VBox(5); + copy.setMinWidth(0); + HBox.setHgrow(copy, Priority.ALWAYS); + Label title = titleText(value(project.title(), "Untitled Project"), "compact-title", COMPACT_TITLE_FONT_SIZE); + title.setTextOverrun(OverrunStyle.ELLIPSIS); + copy.getChildren().addAll(title, authorLine(project, "by", "compact-byline", onOpenCreator)); + + VBox stats = new VBox(4, statLabel(LauncherIcons.Glyph.DOWNLOAD, number(project.downloadCount())), + favoriteStat(project, favorite, onToggleFavorite)); + stats.getStyleClass().add("compact-stats"); + + Button install = installButton(project, onInstall); + install.getStyleClass().add("icon-only-button"); + install.setText(""); + install.setMinWidth(42); + install.setPrefWidth(42); + install.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 16)); + + card.getChildren().addAll(icon, copy, stats, install, LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_RIGHT, 16)); + ProjectCardInteraction.addHoverAnimation(card, icon); + return card; + } + + private Node classificationBadge(String classification) { + HBox badge = new HBox(6); + badge.getStyleClass().add("classification-badge"); + badge.setAlignment(Pos.CENTER); + badge.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + badge.getChildren().addAll( + LauncherIcons.icon(BrowseOptions.classification(classification).icon(), 14), + text(classificationLabel(classification), "classification-label") + ); + return badge; + } + + private static void cacheCardSurface(Region card) { + card.setCache(true); + card.setCacheHint(CacheHint.SPEED); + } + + private Node installStatsRow( + ProjectSummary project, + Optional latestVersion, + boolean favorite, + Consumer onInstall, + Consumer onToggleFavorite, + boolean tight + ) { + HBox row = new HBox(tight ? 12 : 16); + row.getStyleClass().add("project-stats"); + row.setAlignment(Pos.CENTER_LEFT); + row.setMinHeight(CARD_STAT_HEIGHT); + row.setPrefHeight(CARD_STAT_HEIGHT); + + HBox left = new HBox(tight ? 12 : 16, statLabel(LauncherIcons.Glyph.DOWNLOAD, number(project.downloadCount()), true), + favoriteStat(project, favorite, onToggleFavorite, true)); + left.setAlignment(Pos.CENTER_LEFT); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Button install = installButton(project, onInstall); + if (tight) { + install.getStyleClass().add("icon-only-button"); + install.setText(""); + install.setMinWidth(38); + install.setPrefWidth(38); + } + install.setMinHeight(CARD_STAT_HEIGHT); + install.setPrefHeight(CARD_STAT_HEIGHT); + row.getChildren().addAll(left, spacer, install); + return row; + } + + private Node statsRow(ProjectSummary project, boolean favorite, Consumer onToggleFavorite) { + HBox row = new HBox(16, statLabel(LauncherIcons.Glyph.DOWNLOAD, number(project.downloadCount()), true), + favoriteStat(project, favorite, onToggleFavorite, true)); + row.getStyleClass().add("project-stats"); + row.setAlignment(Pos.CENTER_LEFT); + return row; + } + + private HBox statLabel(LauncherIcons.Glyph glyph, String value) { + return statLabel(glyph, value, false); + } + + private HBox statLabel(LauncherIcons.Glyph glyph, String value, boolean fullSize) { + HBox stat = new HBox(5); + stat.getStyleClass().addAll(fullSize ? "project-stat-large" : "project-stat"); + stat.setAlignment(Pos.CENTER_LEFT); + if (fullSize) { + stat.setMinHeight(CARD_STAT_HEIGHT); + stat.setPrefHeight(CARD_STAT_HEIGHT); + } + stat.getChildren().addAll(LauncherIcons.icon(glyph, fullSize ? CARD_STAT_ICON_SIZE : COMPACT_STAT_ICON_SIZE), + text(value, fullSize ? "project-stat-text-large" : "project-stat-text")); + return stat; + } + + private Button favoriteStat(ProjectSummary project, boolean favorite, Consumer onToggleFavorite) { + return favoriteStat(project, favorite, onToggleFavorite, false); + } + + private Button favoriteStat( + ProjectSummary project, + boolean favorite, + Consumer onToggleFavorite, + boolean fullSize + ) { + Button button = new Button(number(project.favoriteCount())); + button.getStyleClass().addAll(fullSize ? "project-stat-large" : "project-stat", "favorite-stat"); + if (fullSize) { + button.setMinHeight(CARD_STAT_HEIGHT); + button.setPrefHeight(CARD_STAT_HEIGHT); + } + button.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.HEART, + fullSize ? CARD_STAT_ICON_SIZE : COMPACT_STAT_ICON_SIZE)); + button.pseudoClassStateChanged(SELECTED, favorite); + button.setOnAction(event -> { + event.consume(); + onToggleFavorite.accept(project); + }); + return button; + } + + private HBox authorLine( + ProjectSummary project, + String prefix, + String textStyleClass, + Consumer onOpenCreator + ) { + HBox row = new HBox(4); + row.getStyleClass().add("byline-row"); + row.setAlignment(Pos.CENTER_LEFT); + Label by = text(prefix, textStyleClass); + Button author = new Button(value(project.author(), "Unknown")); + author.getStyleClass().addAll("author-link", textStyleClass); + author.setAlignment(Pos.CENTER_LEFT); + author.setTextOverrun(OverrunStyle.ELLIPSIS); + author.setMinWidth(0); + author.setOnAction(event -> { + event.consume(); + onOpenCreator.accept(project); + }); + row.getChildren().addAll(by, author); + return row; + } + + private Label versionLabel(Optional latestVersion) { + Label latest = text(latestVersion.map(version -> "Latest " + version.versionNumber()).orElse(""), "latest-label"); + latest.setVisible(latestVersion.isPresent()); + latest.setManaged(latestVersion.isPresent()); + latest.setTextOverrun(OverrunStyle.ELLIPSIS); + return latest; + } + + private Button installButton(ProjectSummary project, Consumer onInstall) { + Button install = new Button("Install"); + install.getStyleClass().addAll("btn", "primary", "small", "project-install-button"); + install.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 16)); + install.setOnAction(event -> { + event.consume(); + onInstall.accept(project); + }); + return install; + } + + private Optional latestCompatible(ProjectSummary project, String gameVersion) { + return VersionSelector.latestCompatible(project.versions(), gameVersion); + } + + private Label text(String value, String styleClass) { + Label label = new Label(value); + label.getStyleClass().add(styleClass); + return label; + } + + private Label titleText(String value, String styleClass, double fontSize) { + Label label = text(value, styleClass); + label.setFont(Font.font("Arial Black", FontWeight.BLACK, fontSize)); + return label; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFormatter.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFormatter.java new file mode 100644 index 00000000..3e2a1085 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardFormatter.java @@ -0,0 +1,80 @@ +package net.modtale.launcher.ui.browse.card; + +import java.text.NumberFormat; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeParseException; +import java.util.Locale; +import net.modtale.launcher.model.project.ProjectClassification; + +public final class ProjectCardFormatter { + + private static final NumberFormat NUMBER_FORMAT = NumberFormat.getIntegerInstance(Locale.US); + + private ProjectCardFormatter() { + } + + public static String value(String value, String fallback) { + return value == null || value.isBlank() ? fallback : value; + } + + public static String number(int value) { + return NUMBER_FORMAT.format(value); + } + + public static String classificationLabel(String classification) { + return ProjectClassification.compactLabelFor(classification); + } + + public static String timeAgo(String rawDate) { + if (rawDate == null || rawDate.isBlank()) { + return "Unknown"; + } + try { + Instant instant = Instant.parse(rawDate); + return timeAgo(instant); + } catch (DateTimeParseException ex) { + try { + return timeAgo(LocalDateTime.parse(rawDate).atZone(ZoneId.systemDefault()).toInstant()); + } catch (DateTimeParseException ignored) { + try { + return timeAgo(LocalDate.parse(rawDate).atStartOfDay(ZoneId.systemDefault()).toInstant()); + } catch (DateTimeParseException ignoredAgain) { + return rawDate; + } + } + } + } + + private static String timeAgo(Instant instant) { + Duration age = Duration.between(instant, Instant.now()); + if (age.isNegative()) { + return "Just now"; + } + long seconds = age.toSeconds(); + double interval = seconds / 31_536_000.0; + if (interval > 1) { + return (long) interval + "y ago"; + } + interval = seconds / 2_592_000.0; + if (interval > 1) { + return (long) interval + "mo ago"; + } + interval = seconds / 86_400.0; + if (interval > 1) { + return (long) interval + "d ago"; + } + interval = seconds / 3_600.0; + if (interval > 1) { + return (long) interval + "h ago"; + } + interval = seconds / 60.0; + if (interval > 1) { + return (long) interval + "m ago"; + } + return "Just now"; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardInteraction.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardInteraction.java new file mode 100644 index 00000000..5bc4a9a1 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardInteraction.java @@ -0,0 +1,208 @@ +package net.modtale.launcher.ui.browse.card; + +import java.util.function.Consumer; +import javafx.animation.Animation; +import javafx.animation.Interpolator; +import javafx.animation.ScaleTransition; +import javafx.animation.TranslateTransition; +import javafx.scene.CacheHint; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.ScrollEvent; +import javafx.scene.layout.Region; +import javafx.util.Duration; +import net.modtale.launcher.model.project.ProjectSummary; + +public final class ProjectCardInteraction { + + private static final String ANIMATION_CACHE_ENABLED_PROPERTY = "net.modtale.launcher.animationCacheEnabled"; + private static final String ANIMATION_CACHE_HINT_PROPERTY = "net.modtale.launcher.animationCacheHint"; + private static final Interpolator HOVER_EASE = Interpolator.SPLINE(0.16, 1.0, 0.30, 1.0); + private static final Duration HOVER_TRANSLATE_DURATION = Duration.millis(800); + private static final Duration HOVER_SCALE_DURATION = Duration.millis(900); + + private ProjectCardInteraction() { + } + + public static void openOnCardClick(Region card, ProjectSummary project, Consumer onOpenPage) { + card.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> { + if (isInteractive(event.getTarget())) { + return; + } + onOpenPage.accept(project); + }); + } + + public static void addHoverAnimation(Region card, Node floatingIcon) { + addHoverAnimation(card, floatingIcon, null); + } + + public static void addHoverAnimation(Region card, Node floatingIcon, Node zoomMedia) { + TranslateTransition cardTransition = hoverTransition(card); + TranslateTransition iconTransition = hoverTransition(floatingIcon); + ScaleTransition mediaTransition = zoomMedia == null ? null : scaleTransition(zoomMedia); + card.addEventFilter(ScrollEvent.SCROLL, event -> { + if (hasHoverEffects(cardTransition, iconTransition, mediaTransition)) { + resetHoverEffects(cardTransition, iconTransition, mediaTransition); + } + }); + card.setOnMouseEntered(event -> { + if (isScrollActive(card)) { + resetHoverEffects(cardTransition, iconTransition, mediaTransition); + return; + } + animateY(cardTransition, -4); + animateY(iconTransition, -7); + animateScale(mediaTransition, 1.05); + }); + card.setOnMouseExited(event -> { + if (isScrollActive(card)) { + resetHoverEffects(cardTransition, iconTransition, mediaTransition); + return; + } + animateY(cardTransition, 0); + animateY(iconTransition, 0); + animateScale(mediaTransition, 1); + }); + } + + private static boolean isInteractive(Object target) { + if (!(target instanceof Node node)) { + return false; + } + while (node != null) { + if (node instanceof Button) { + return true; + } + node = node.getParent(); + } + return false; + } + + private static TranslateTransition hoverTransition(Node node) { + TranslateTransition transition = new TranslateTransition(HOVER_TRANSLATE_DURATION, node); + transition.setInterpolator(HOVER_EASE); + transition.setOnFinished(event -> releaseAnimationCache(node)); + return transition; + } + + private static ScaleTransition scaleTransition(Node node) { + ScaleTransition transition = new ScaleTransition(HOVER_SCALE_DURATION, node); + transition.setInterpolator(HOVER_EASE); + transition.setOnFinished(event -> releaseAnimationCache(node)); + return transition; + } + + private static void animateY(TranslateTransition transition, double y) { + Node node = transition.getNode(); + if (Math.abs(node.getTranslateY() - y) < 0.1) { + return; + } + transition.stop(); + transition.setFromY(node.getTranslateY()); + transition.setToY(y); + prepareAnimationCache(node); + transition.playFromStart(); + } + + private static void animateScale(ScaleTransition transition, double scale) { + if (transition == null) { + return; + } + Node node = transition.getNode(); + if (Math.abs(node.getScaleX() - scale) < 0.01 && Math.abs(node.getScaleY() - scale) < 0.01) { + return; + } + transition.stop(); + transition.setFromX(node.getScaleX()); + transition.setFromY(node.getScaleY()); + transition.setToX(scale); + transition.setToY(scale); + prepareAnimationCache(node); + transition.playFromStart(); + } + + private static void resetHoverOffsets(TranslateTransition... transitions) { + for (TranslateTransition transition : transitions) { + transition.stop(); + Node node = transition.getNode(); + if (Math.abs(node.getTranslateY()) >= 0.1) { + node.setTranslateY(0); + } + releaseAnimationCache(node); + } + } + + private static void resetHoverEffects( + TranslateTransition cardTransition, + TranslateTransition iconTransition, + ScaleTransition mediaTransition + ) { + resetHoverOffsets(cardTransition, iconTransition); + if (mediaTransition != null) { + mediaTransition.stop(); + Node node = mediaTransition.getNode(); + if (Math.abs(node.getScaleX() - 1) >= 0.01) { + node.setScaleX(1); + } + if (Math.abs(node.getScaleY() - 1) >= 0.01) { + node.setScaleY(1); + } + releaseAnimationCache(node); + } + } + + private static boolean hasHoverEffects( + TranslateTransition cardTransition, + TranslateTransition iconTransition, + ScaleTransition mediaTransition + ) { + return isTranslateActive(cardTransition) + || isTranslateActive(iconTransition) + || isScaleActive(mediaTransition); + } + + private static boolean isTranslateActive(TranslateTransition transition) { + return transition.getStatus() == Animation.Status.RUNNING + || Math.abs(transition.getNode().getTranslateY()) >= 0.1; + } + + private static boolean isScaleActive(ScaleTransition transition) { + if (transition == null) { + return false; + } + Node node = transition.getNode(); + return transition.getStatus() == Animation.Status.RUNNING + || Math.abs(node.getScaleX() - 1) >= 0.01 + || Math.abs(node.getScaleY() - 1) >= 0.01; + } + + private static void prepareAnimationCache(Node node) { + if (!node.getProperties().containsKey(ANIMATION_CACHE_ENABLED_PROPERTY)) { + node.getProperties().put(ANIMATION_CACHE_ENABLED_PROPERTY, node.isCache()); + node.getProperties().put(ANIMATION_CACHE_HINT_PROPERTY, node.getCacheHint()); + } + node.setCache(true); + node.setCacheHint(CacheHint.SPEED); + } + + private static void releaseAnimationCache(Node node) { + Object cached = node.getProperties().remove(ANIMATION_CACHE_ENABLED_PROPERTY); + Object hint = node.getProperties().remove(ANIMATION_CACHE_HINT_PROPERTY); + if (!(cached instanceof Boolean wasCached)) { + return; + } + node.setCache(wasCached); + if (hint instanceof CacheHint cacheHint) { + node.setCacheHint(cacheHint); + } else { + node.setCacheHint(CacheHint.DEFAULT); + } + } + + private static boolean isScrollActive(Node node) { + return node.getScene() != null + && Boolean.TRUE.equals(node.getScene().getRoot().getProperties().get(ProjectCardFactory.SCROLL_ACTIVE_PROPERTY)); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardMedia.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardMedia.java new file mode 100644 index 00000000..2b349db0 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardMedia.java @@ -0,0 +1,238 @@ +package net.modtale.launcher.ui.browse.card; + +import static net.modtale.launcher.ui.browse.card.ProjectCardFormatter.value; + +import java.util.Locale; +import java.util.concurrent.Executor; +import java.util.function.Function; +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import javafx.scene.shape.ClosePath; +import javafx.scene.shape.LineTo; +import javafx.scene.shape.MoveTo; +import javafx.scene.shape.Path; +import javafx.scene.shape.QuadCurveTo; +import javafx.scene.shape.Rectangle; +import javafx.stage.Screen; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.ui.common.CachedImageLoader; + +public final class ProjectCardMedia { + + private static final double CARD_RADIUS = 16; + private static final double RESTING_OUTLINE_WIDTH = 1; + private static final double HOVER_OUTLINE_WIDTH = 3; + private static final double MAX_IMAGE_RENDER_SCALE = 3; + private static final double PROJECT_ICON_RADIUS = 16; + private static final double COMPACT_PROJECT_ICON_RADIUS = 10; + + private final CachedImageLoader imageLoader; + private final double imageRenderScale; + + public ProjectCardMedia(Function assetResolver, Executor executor) { + this.imageLoader = new CachedImageLoader(assetResolver, executor); + this.imageRenderScale = computeImageRenderScale(); + } + + public void clearImageCache() { + imageLoader.clearMemory(); + } + + public StackPane banner(ProjectSummary project, double width, double height) { + StackPane banner = new StackPane(); + banner.getStyleClass().add("project-banner"); + lockWidth(banner, width); + banner.setMinHeight(height); + banner.setPrefHeight(height); + banner.setMaxHeight(height); + banner.setClip(topRoundedClip(banner, 16)); + StackPane mediaLayer = new StackPane(); + mediaLayer.getStyleClass().add("project-banner-media"); + mediaLayer.setMouseTransparent(true); + mediaLayer.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + StackPane.setAlignment(mediaLayer, Pos.TOP_CENTER); + banner.getChildren().add(mediaLayer); + + if (project.bannerUrl() != null && !project.bannerUrl().isBlank()) { + mediaLayer.getStyleClass().add("letterboxed"); + ImageView image = remoteBannerImage(project.bannerUrl(), width, height); + image.fitWidthProperty().bind(banner.widthProperty()); + image.fitHeightProperty().bind(banner.heightProperty()); + image.setSmooth(true); + image.setMouseTransparent(true); + image.getStyleClass().add("project-banner-image"); + StackPane.setAlignment(image, Pos.CENTER); + mediaLayer.getChildren().add(image); + } else { + Region fallback = new Region(); + fallback.getStyleClass().add("project-banner-fallback"); + fallback.setMouseTransparent(true); + fallback.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + mediaLayer.getChildren().add(fallback); + } + return banner; + } + + public StackPane projectIcon(ProjectSummary project, double size, double borderWidth) { + StackPane icon = new StackPane(); + icon.getStyleClass().add("project-icon"); + if (borderWidth <= 2) { + icon.getStyleClass().add("project-icon-compact"); + } + icon.setMinSize(size, size); + icon.setPrefSize(size, size); + icon.setMaxSize(size, size); + icon.setPadding(new javafx.geometry.Insets(borderWidth)); + + double mediaSize = Math.max(1, size - borderWidth * 2); + StackPane media = new StackPane(); + media.getStyleClass().add("project-icon-media"); + media.setMinSize(mediaSize, mediaSize); + media.setPrefSize(mediaSize, mediaSize); + media.setMaxSize(mediaSize, mediaSize); + + Rectangle clip = new Rectangle(mediaSize, mediaSize); + double mediaRadius = projectIconMediaRadius(borderWidth); + clip.setArcWidth(mediaRadius * 2); + clip.setArcHeight(mediaRadius * 2); + media.setClip(clip); + + if (project.imageUrl() != null && !project.imageUrl().isBlank()) { + media.getChildren().add(iconBackdrop(mediaSize)); + + ImageView foreground = remoteImage(project.imageUrl(), mediaSize, mediaSize); + foreground.setMouseTransparent(true); + media.getChildren().add(foreground); + } else { + media.getStyleClass().add("project-icon-fallback-media"); + Label initial = new Label(value(project.title(), "M").substring(0, 1).toUpperCase(Locale.ROOT)); + media.getChildren().add(initial); + } + icon.getChildren().add(media); + return icon; + } + + public Rectangle hoverOutline(Region visualOwner, Region hoverOwner) { + Rectangle outline = outline(visualOwner, HOVER_OUTLINE_WIDTH); + outline.getStyleClass().add("project-hover-outline"); + outline.setStroke(Color.web("#3b82f6")); + outline.visibleProperty().bind(hoverOwner.hoverProperty()); + return outline; + } + + public Rectangle restingOutline(Region visualOwner) { + Rectangle outline = outline(visualOwner, RESTING_OUTLINE_WIDTH); + outline.setStroke(Color.rgb(255, 255, 255, 0.20)); + return outline; + } + + public static void lockWidth(Region region, double width) { + region.setMinWidth(width); + region.setPrefWidth(width); + region.setMaxWidth(width); + } + + public static void lockHeight(Region region, double height) { + region.setMinHeight(height); + region.setPrefHeight(height); + region.setMaxHeight(height); + } + + private StackPane iconBackdrop(double size) { + StackPane backdrop = new StackPane(); + backdrop.getStyleClass().add("project-icon-backdrop"); + backdrop.setMinSize(size, size); + backdrop.setPrefSize(size, size); + backdrop.setMaxSize(size, size); + backdrop.setMouseTransparent(true); + return backdrop; + } + + private double projectIconMediaRadius(double borderWidth) { + double outerRadius = borderWidth <= 2 ? COMPACT_PROJECT_ICON_RADIUS : PROJECT_ICON_RADIUS; + return Math.max(0, outerRadius - borderWidth); + } + + private Rectangle outline(Region visualOwner, double strokeWidth) { + Rectangle outline = new Rectangle(); + double inset = strokeWidth / 2.0; + outline.setX(inset); + outline.setY(inset); + outline.widthProperty().bind(visualOwner.widthProperty().subtract(strokeWidth)); + outline.heightProperty().bind(visualOwner.heightProperty().subtract(strokeWidth)); + outline.setArcWidth(CARD_RADIUS * 2); + outline.setArcHeight(CARD_RADIUS * 2); + outline.setFill(Color.TRANSPARENT); + outline.setStrokeWidth(strokeWidth); + outline.setMouseTransparent(true); + outline.setManaged(false); + return outline; + } + + private Path topRoundedClip(Region owner, double radius) { + MoveTo start = new MoveTo(0, radius); + QuadCurveTo topLeft = new QuadCurveTo(0, 0, radius, 0); + LineTo top = new LineTo(); + top.xProperty().bind(owner.widthProperty().subtract(radius)); + top.setY(0); + QuadCurveTo topRight = new QuadCurveTo(); + topRight.controlXProperty().bind(owner.widthProperty()); + topRight.setControlY(0); + topRight.xProperty().bind(owner.widthProperty()); + topRight.setY(radius); + LineTo right = new LineTo(); + right.xProperty().bind(owner.widthProperty()); + right.yProperty().bind(owner.heightProperty()); + LineTo bottom = new LineTo(); + bottom.setX(0); + bottom.yProperty().bind(owner.heightProperty()); + Path clip = new Path(start, topLeft, top, topRight, right, bottom, new ClosePath()); + clip.setFill(Color.BLACK); + clip.setStroke(null); + return clip; + } + + private ImageView remoteImage(String rawUrl, double width, double height) { + ImageView view = imageView(width, height, false); + imageLoader.loadInto(view, rawUrl, requestedImageDimension(width, imageRenderScale), requestedImageDimension(height, imageRenderScale)); + return view; + } + + private ImageView remoteBannerImage(String rawUrl, double width, double height) { + ImageView view = imageView(width, height, true); + imageLoader.loadInto(view, rawUrl, + requestedImageDimension(width, imageRenderScale), + requestedImageDimension(height, imageRenderScale), + true); + return view; + } + + private ImageView imageView(double width, double height, boolean preserveRatio) { + ImageView view = new ImageView(); + view.setPreserveRatio(preserveRatio); + view.setFitWidth(width); + if (height > 0) { + view.setFitHeight(height); + } + view.setSmooth(true); + return view; + } + + private double computeImageRenderScale() { + return Math.max(1, Math.min(MAX_IMAGE_RENDER_SCALE, Screen.getScreens().stream() + .mapToDouble(screen -> Math.max(screen.getOutputScaleX(), screen.getOutputScaleY())) + .max() + .orElse(1))); + } + + private double requestedImageDimension(double logicalSize, double renderScale) { + if (!Double.isFinite(logicalSize) || logicalSize <= 0) { + return 0; + } + return Math.ceil(logicalSize * renderScale); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardViewStyle.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardViewStyle.java new file mode 100644 index 00000000..eb4af87a --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/card/ProjectCardViewStyle.java @@ -0,0 +1,7 @@ +package net.modtale.launcher.ui.browse.card; + +public enum ProjectCardViewStyle { + GRID, + LIST, + COMPACT +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/BrowseOptions.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/BrowseOptions.java new file mode 100644 index 00000000..631263f8 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/BrowseOptions.java @@ -0,0 +1,153 @@ +package net.modtale.launcher.ui.browse.controls; + +import java.util.Arrays; +import java.util.List; +import net.modtale.launcher.model.project.ProjectClassification; +import net.modtale.launcher.ui.common.LauncherIcons; + +public final class BrowseOptions { + + public static final List BROWSE_VIEWS = List.of(BrowseViewOption.values()); + + public static final List PROJECT_TYPES = List.of( + ClassificationOption.ALL, + ClassificationOption.MODPACKS, + ClassificationOption.PLUGINS, + ClassificationOption.WORLDS, + ClassificationOption.ART, + ClassificationOption.DATA + ); + + public static final List BROWSE_ITEMS_PER_PAGE_OPTIONS = List.of(6, 12, 24, 48, 96); + + public static final int DEFAULT_ITEMS_PER_PAGE = 12; + + public static final List GLOBAL_TAGS = List.of( + "Adventure", "RPG", "Sci-Fi", "Fantasy", "Survival", "Magic", "Tech", "Exploration", + "Minigame", "PvP", "Parkour", "Hardcore", "Skyblock", "Puzzle", "Quests", "Mobs", + "Economy", "Protection", "Admin Tools", "Chat", "Anti-Cheat", "Performance", "NPCs", + "Library", "API", "Mechanics", "World Gen", "Recipes", "Loot Tables", "Functions", + "Decoration", "Vanilla+", "Kitchen Sink", "City", "Landscape", "Spawn", "Lobby", + "Medieval", "Modern", "Futuristic", "Models", "Textures", "Animations", "Particles" + ); + + private BrowseOptions() { + } + + public static BrowseViewOption browseView(BrowseViewOption view) { + return view == null ? BrowseViewOption.defaultOption() : view; + } + + public static int itemsPerPage(Integer value) { + return BROWSE_ITEMS_PER_PAGE_OPTIONS.contains(value) ? value : DEFAULT_ITEMS_PER_PAGE; + } + + public static ClassificationOption classification(String classification) { + if (classification == null || classification.isBlank()) { + return ClassificationOption.defaultOption(); + } + return Arrays.stream(ClassificationOption.values()) + .filter(option -> option.apiValue().equalsIgnoreCase(classification.trim())) + .findFirst() + .orElse(ClassificationOption.defaultOption()); + } + + public enum BrowseViewOption { + ALL("All Projects", null, ProjectBrowseSort.RELEVANCE, LauncherIcons.Glyph.GLOBE), + POPULAR("Popular", null, ProjectBrowseSort.POPULAR, LauncherIcons.Glyph.STAR), + TRENDING("Trending", null, ProjectBrowseSort.TRENDING, LauncherIcons.Glyph.FLAME), + NEW("New Releases", null, ProjectBrowseSort.NEWEST, LauncherIcons.Glyph.ZAP), + UPDATED("Recently Updated", null, ProjectBrowseSort.UPDATED, LauncherIcons.Glyph.CLOCK), + FAVORITES("My Favorites", "favorites", ProjectBrowseSort.RELEVANCE, LauncherIcons.Glyph.HEART); + + private final String label; + private final String category; + private final ProjectBrowseSort defaultSort; + private final LauncherIcons.Glyph icon; + + BrowseViewOption(String label, String category, ProjectBrowseSort defaultSort, LauncherIcons.Glyph icon) { + this.label = label; + this.category = category; + this.defaultSort = defaultSort; + this.icon = icon; + } + + public String label() { + return label; + } + + public String category() { + return category; + } + + public ProjectBrowseSort defaultSort() { + return defaultSort; + } + + public LauncherIcons.Glyph icon() { + return icon; + } + + public boolean isDefault() { + return this == ALL; + } + + public static BrowseViewOption defaultOption() { + return ALL; + } + } + + public enum ClassificationOption { + ALL("All Projects", null, "All Projects", LauncherIcons.Glyph.LAYOUT), + PLUGINS("Plugins", ProjectClassification.PLUGIN, "Plugins", LauncherIcons.Glyph.FILE_CODE), + DATA("Data", ProjectClassification.DATA, "Data Assets", LauncherIcons.Glyph.DATABASE), + ART("Art", ProjectClassification.ART, "Art Assets", LauncherIcons.Glyph.PALETTE), + WORLDS("Worlds", ProjectClassification.SAVE, "Worlds", LauncherIcons.Glyph.SAVE), + MODPACKS("Modpacks", ProjectClassification.MODPACK, "Modpacks", LauncherIcons.Glyph.LAYERS); + + private final String label; + private final ProjectClassification projectClassification; + private final String browseMenuLabel; + private final LauncherIcons.Glyph icon; + + ClassificationOption( + String label, + ProjectClassification projectClassification, + String browseMenuLabel, + LauncherIcons.Glyph icon + ) { + this.label = label; + this.projectClassification = projectClassification; + this.browseMenuLabel = browseMenuLabel; + this.icon = icon; + } + + public String label() { + return label; + } + + public String classification() { + return apiValue(); + } + + public String apiValue() { + return projectClassification == null ? "" : projectClassification.apiValue(); + } + + public String browseMenuLabel() { + return browseMenuLabel; + } + + public LauncherIcons.Glyph icon() { + return icon; + } + + public boolean isDefault() { + return this == ALL; + } + + public static ClassificationOption defaultOption() { + return ALL; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/GameVersionFilterCatalog.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/GameVersionFilterCatalog.java new file mode 100644 index 00000000..316df392 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/GameVersionFilterCatalog.java @@ -0,0 +1,104 @@ +package net.modtale.launcher.ui.browse.controls; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import net.modtale.launcher.model.project.GameVersionCatalog; + +public final class GameVersionFilterCatalog { + + private static final GameVersionFilterCatalog EMPTY = new GameVersionFilterCatalog(List.of(), Set.of()); + + private final List allVersions; + private final Set preReleaseVersions; + + private GameVersionFilterCatalog(List allVersions, Set preReleaseVersions) { + this.allVersions = allVersions; + this.preReleaseVersions = preReleaseVersions; + } + + public static GameVersionFilterCatalog empty() { + return EMPTY; + } + + public static GameVersionFilterCatalog fromVersions(List versions) { + return new GameVersionFilterCatalog(distinctVersions(versions), Set.of()); + } + + public static GameVersionFilterCatalog from(GameVersionCatalog catalog) { + if (catalog == null) { + return empty(); + } + Set preReleases = preReleaseVersions(catalog); + List ordered = orderedVersions(catalog); + if (ordered.isEmpty()) { + ordered = distinctVersions(catalog.releaseVersions()); + } + return new GameVersionFilterCatalog(ordered, preReleases); + } + + public boolean hasPreReleases() { + return !preReleaseVersions.isEmpty(); + } + + public List visibleVersions(boolean includePreReleases) { + if (allVersions.isEmpty()) { + return List.of(); + } + if (!includePreReleases || preReleaseVersions.isEmpty()) { + return allVersions.stream() + .filter(version -> !preReleaseVersions.contains(version)) + .toList(); + } + List preReleases = allVersions.stream() + .filter(preReleaseVersions::contains) + .toList(); + List releases = allVersions.stream() + .filter(version -> !preReleaseVersions.contains(version)) + .toList(); + List visible = new ArrayList<>(preReleases.size() + releases.size()); + visible.addAll(preReleases); + visible.addAll(releases); + return visible; + } + + private static List orderedVersions(GameVersionCatalog catalog) { + if (catalog.versions() != null && !catalog.versions().isEmpty()) { + return distinctVersions(catalog.versions().stream() + .filter(Objects::nonNull) + .map(GameVersionCatalog.GameVersionEntry::version) + .toList()); + } + return distinctVersions(catalog.allVersions()); + } + + private static Set preReleaseVersions(GameVersionCatalog catalog) { + LinkedHashSet versions = new LinkedHashSet<>(); + if (catalog.versions() != null && !catalog.versions().isEmpty()) { + catalog.versions().stream() + .filter(Objects::nonNull) + .filter(GameVersionCatalog.GameVersionEntry::preRelease) + .map(GameVersionCatalog.GameVersionEntry::version) + .filter(version -> version != null && !version.isBlank()) + .forEach(versions::add); + } + if (versions.isEmpty() && catalog.preReleaseVersions() != null) { + catalog.preReleaseVersions().stream() + .filter(version -> version != null && !version.isBlank()) + .forEach(versions::add); + } + return versions; + } + + private static List distinctVersions(List versions) { + if (versions == null || versions.isEmpty()) { + return List.of(); + } + return versions.stream() + .filter(version -> version != null && !version.isBlank()) + .distinct() + .toList(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseCategories.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseCategories.java new file mode 100644 index 00000000..6e197e3c --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseCategories.java @@ -0,0 +1,255 @@ +package net.modtale.launcher.ui.browse.controls; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.application.Platform; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyBooleanWrapper; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.property.ReadOnlyDoubleWrapper; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import javafx.util.Duration; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherScrollSupport; + +public final class ProjectBrowseCategories { + + private static final double VIEWPORT_CHROME_BUFFER = 8; + private static final double OVERFLOW_TOLERANCE = 12; + private static final Interpolator PILL_EASE = Interpolator.SPLINE(0.16, 1.0, 0.30, 1.0); + private static final Duration PILL_TRANSITION_DURATION = Duration.millis(700); + + private final LauncherScrollSupport scrollSupport; + private final Runnable onSearch; + private final Map categoryButtons = new LinkedHashMap<>(); + private final Region pillIndicator = new Region(); + private final Region leftFade = new Region(); + private final Region rightFade = new Region(); + private final ReadOnlyDoubleWrapper contentWidth = new ReadOnlyDoubleWrapper(); + private final ReadOnlyBooleanWrapper overflowing = new ReadOnlyBooleanWrapper(); + + private Timeline pillTimeline; + private BrowseOptions.ClassificationOption selectedClassification = BrowseOptions.ClassificationOption.defaultOption(); + private Node view; + + public ProjectBrowseCategories(LauncherScrollSupport scrollSupport, Runnable onSearch) { + this.scrollSupport = scrollSupport; + this.onSearch = onSearch; + } + + public Node view() { + if (view == null) { + view = buildView(); + } + return view; + } + + public BrowseOptions.ClassificationOption selectedClassification() { + return selectedClassification; + } + + public double contentWidth() { + return contentWidth.get(); + } + + public ReadOnlyDoubleProperty contentWidthProperty() { + return contentWidth.getReadOnlyProperty(); + } + + public boolean isOverflowing() { + return overflowing.get(); + } + + public ReadOnlyBooleanProperty overflowingProperty() { + return overflowing.getReadOnlyProperty(); + } + + public void selectClassification(BrowseOptions.ClassificationOption classification) { + selectedClassification = classification == null + ? BrowseOptions.ClassificationOption.defaultOption() + : classification; + refresh(); + onSearch.run(); + } + + public void refresh() { + categoryButtons.forEach((key, button) -> pseudo(button, "selected", key == selectedClassification)); + animatePill(); + } + + private Node buildView() { + HBox pills = new HBox(4); + pills.getStyleClass().add("category-pill-buttons"); + for (BrowseOptions.ClassificationOption option : BrowseOptions.PROJECT_TYPES) { + addCategory(pills, option); + } + pillIndicator.getStyleClass().add("category-pill-indicator"); + pillIndicator.setMouseTransparent(true); + pillIndicator.setVisible(false); + pillIndicator.setMinWidth(0); + pillIndicator.setMinHeight(36); + pillIndicator.setPrefHeight(36); + pillIndicator.setMaxWidth(0); + pillIndicator.setMaxHeight(36); + pillIndicator.setScaleX(1); + StackPane pillShell = new StackPane(pillIndicator, pills); + pillShell.getStyleClass().add("category-pills"); + pillShell.setMinHeight(46); + pillShell.setPrefHeight(46); + pillShell.setAlignment(Pos.CENTER_LEFT); + StackPane.setAlignment(pillIndicator, Pos.CENTER_LEFT); + StackPane.setAlignment(pills, Pos.CENTER_LEFT); + + ScrollPane categoryScroll = new ScrollPane(pillShell); + categoryScroll.getStyleClass().add("category-scroll"); + categoryScroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + categoryScroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + categoryScroll.setFitToHeight(true); + categoryScroll.setPannable(true); + categoryScroll.setMinWidth(0); + categoryScroll.setPrefHeight(48); + scrollSupport.configure(categoryScroll, true); + configureFades(categoryScroll); + + StackPane frame = new StackPane(categoryScroll, leftFade, rightFade); + frame.getStyleClass().add("category-scroll-frame"); + frame.setMinWidth(0); + frame.setPrefHeight(48); + StackPane.setAlignment(categoryScroll, Pos.CENTER_LEFT); + StackPane.setAlignment(leftFade, Pos.CENTER_LEFT); + StackPane.setAlignment(rightFade, Pos.CENTER_RIGHT); + HBox.setHgrow(frame, Priority.NEVER); + pillShell.layoutBoundsProperty().addListener((observable, oldValue, bounds) -> + updateContentWidth(frame, bounds.getWidth())); + Platform.runLater(() -> updateContentWidth(frame, pillShell.getLayoutBounds().getWidth())); + Platform.runLater(this::refresh); + return frame; + } + + private void addCategory(HBox pane, BrowseOptions.ClassificationOption option) { + Button button = new Button(); + button.getStyleClass().add("pill"); + HBox content = new HBox(8, LauncherIcons.icon(option.icon(), 15), + spacedTitleText(option.label(), "pill-label", 14)); + content.setAlignment(Pos.CENTER); + content.setMouseTransparent(true); + button.setGraphic(content); + button.setOnAction(event -> selectClassification(option)); + categoryButtons.put(option, button); + pane.getChildren().add(button); + } + + private Label text(String value, String styleClass) { + Label label = new Label(value); + label.getStyleClass().add(styleClass); + return label; + } + + private Node spacedTitleText(String value, String styleClass, double fontSize) { + HBox text = new HBox(); + text.getStyleClass().add(styleClass); + text.setAlignment(Pos.CENTER); + for (char letter : value.toCharArray()) { + Label letterLabel = text(String.valueOf(letter), styleClass + "-letter"); + letterLabel.setFont(Font.font("Arial Black", FontWeight.EXTRA_BOLD, fontSize)); + text.getChildren().add(letterLabel); + } + return text; + } + + private void configureFades(ScrollPane categoryScroll) { + leftFade.getStyleClass().setAll("category-edge-fade", "left"); + rightFade.getStyleClass().setAll("category-edge-fade", "right"); + for (Region fade : List.of(leftFade, rightFade)) { + fade.setMouseTransparent(true); + fade.setMinWidth(42); + fade.setPrefWidth(42); + fade.setMaxWidth(42); + fade.setMaxHeight(Double.MAX_VALUE); + fade.setVisible(false); + } + + categoryScroll.hvalueProperty().addListener((observable, oldValue, newValue) -> updateFades(categoryScroll)); + categoryScroll.viewportBoundsProperty().addListener((observable, oldValue, newValue) -> updateFades(categoryScroll)); + categoryScroll.getContent().layoutBoundsProperty().addListener((observable, oldValue, newValue) -> updateFades(categoryScroll)); + Platform.runLater(() -> updateFades(categoryScroll)); + } + + private void updateFades(ScrollPane categoryScroll) { + double contentWidth = categoryScroll.getContent().getLayoutBounds().getWidth(); + double viewportWidth = categoryScroll.getViewportBounds().getWidth(); + boolean overflow = contentWidth > viewportWidth + OVERFLOW_TOLERANCE; + overflowing.set(overflow); + double hValue = categoryScroll.getHvalue(); + leftFade.setVisible(overflow && hValue > 0.01); + rightFade.setVisible(overflow && hValue < 0.99); + } + + private void updateContentWidth(Region frame, double width) { + if (!Double.isFinite(width) || width <= 0) { + return; + } + double nextWidth = Math.ceil(width); + contentWidth.set(nextWidth); + frame.setPrefWidth(nextWidth + VIEWPORT_CHROME_BUFFER); + frame.setMaxWidth(nextWidth + VIEWPORT_CHROME_BUFFER); + } + + private void animatePill() { + Button selected = categoryButtons.getOrDefault( + selectedClassification, + categoryButtons.get(BrowseOptions.ClassificationOption.defaultOption()) + ); + if (selected == null) { + return; + } + if (selected.getWidth() <= 0) { + Platform.runLater(this::animatePill); + return; + } + pillIndicator.setVisible(true); + double targetX = selected.getBoundsInParent().getMinX(); + double targetWidth = selected.getWidth(); + if (pillTimeline != null) { + pillTimeline.stop(); + } + if (pillIndicator.getPrefWidth() <= 0) { + pillIndicator.setTranslateX(targetX); + pillIndicator.setMinWidth(targetWidth); + pillIndicator.setPrefWidth(targetWidth); + pillIndicator.setMaxWidth(targetWidth); + pillIndicator.setScaleX(1); + return; + } + double startWidth = Math.max(1, pillIndicator.getBoundsInParent().getWidth()); + double startX = pillIndicator.getBoundsInParent().getMinX(); + double startScale = startWidth / targetWidth; + double startTranslate = startX - (targetWidth - startWidth) / 2.0; + pillIndicator.setMinWidth(targetWidth); + pillIndicator.setPrefWidth(targetWidth); + pillIndicator.setMaxWidth(targetWidth); + pillIndicator.setTranslateX(startTranslate); + pillIndicator.setScaleX(startScale); + pillTimeline = new Timeline(new KeyFrame(PILL_TRANSITION_DURATION, + new KeyValue(pillIndicator.translateXProperty(), targetX, PILL_EASE), + new KeyValue(pillIndicator.scaleXProperty(), 1, PILL_EASE))); + pillTimeline.play(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseDownloadTimeframeSelector.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseDownloadTimeframeSelector.java new file mode 100644 index 00000000..9451303c --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseDownloadTimeframeSelector.java @@ -0,0 +1,101 @@ +package net.modtale.launcher.ui.browse.controls; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; +import static net.modtale.launcher.ui.common.LauncherUi.setVisibleManaged; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.HBox; + +public final class ProjectBrowseDownloadTimeframeSelector { + + private final Consumer onSelect; + private final Supplier selectedRange; + private final Map buttons = new LinkedHashMap<>(); + private HBox view; + + public ProjectBrowseDownloadTimeframeSelector(Consumer onSelect, Supplier selectedRange) { + this.onSelect = onSelect; + this.selectedRange = selectedRange; + } + + public Node view() { + if (view == null) { + view = new HBox(4); + view.getStyleClass().add("download-timeframe-control"); + view.setAlignment(Pos.CENTER); + addButton(DownloadTimeframe.SEVEN_DAYS); + addButton(DownloadTimeframe.THIRTY_DAYS); + addButton(DownloadTimeframe.NINETY_DAYS); + addButton(DownloadTimeframe.ALL_TIME); + refresh(); + } + return view; + } + + public void setVisible(boolean visible) { + setVisibleManaged(view(), visible); + } + + public void refresh() { + DownloadTimeframe active = DownloadTimeframe.fromDateRange(selectedRange.get()); + buttons.forEach((range, button) -> pseudo(button, "selected", range.equals(active))); + } + + private void addButton(DownloadTimeframe timeframe) { + Button button = new Button(timeframe.label()); + button.getStyleClass().add("download-timeframe-button"); + button.setTooltip(new Tooltip(timeframe.tooltip())); + button.setOnAction(event -> onSelect.accept(timeframe.dateRange())); + buttons.put(timeframe, button); + view.getChildren().add(button); + } + + private enum DownloadTimeframe { + SEVEN_DAYS("7d", "7d", "Downloads in the last 7 days"), + THIRTY_DAYS("30d", "30d", "Downloads in the last 30 days"), + NINETY_DAYS("90d", "90d", "Downloads in the last 90 days"), + ALL_TIME("All", null, "All-time downloads"); + + private final String label; + private final String dateRange; + private final String tooltip; + + DownloadTimeframe(String label, String dateRange, String tooltip) { + this.label = label; + this.dateRange = dateRange; + this.tooltip = tooltip; + } + + String label() { + return label; + } + + String dateRange() { + return dateRange; + } + + String tooltip() { + return tooltip; + } + + static DownloadTimeframe fromDateRange(String range) { + if (range == null || range.isBlank()) { + return ALL_TIME; + } + String normalized = range.trim(); + for (DownloadTimeframe timeframe : values()) { + if (normalized.equals(timeframe.dateRange)) { + return timeframe; + } + } + return ALL_TIME; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseFilterOptions.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseFilterOptions.java new file mode 100644 index 00000000..5b7ca6a0 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseFilterOptions.java @@ -0,0 +1,503 @@ +package net.modtale.launcher.ui.browse.controls; + +import static net.modtale.launcher.ui.common.LauncherUi.dangerButton; +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; +import static net.modtale.launcher.ui.common.LauncherUi.styleInput; + +import java.time.LocalDate; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.DatePicker; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.input.ScrollEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.model.project.GameVersionCatalog; +import net.modtale.launcher.ui.common.GameVersionDropdown; +import net.modtale.launcher.ui.common.GameVersionGroups; +import net.modtale.launcher.ui.common.LauncherIcons; + +public final class ProjectBrowseFilterOptions { + + private final Runnable onSearch; + private final Runnable onChange; + private final Runnable onResetTags; + private final VBox popover = new VBox(20); + private final GameVersionDropdown gameVersionDropdown = GameVersionDropdown.multiSelect(); + private final Button preReleaseToggle = new Button("Pre Releases"); + private final Button openSourceButton = new Button(); + private final TextField customMinFavoritesField = new TextField(); + private final TextField customMinDownloadsField = new TextField(); + private final DatePicker updatedAfterPicker = new DatePicker(); + private final Map minFavoritesButtons = new LinkedHashMap<>(); + private final Map minDownloadsButtons = new LinkedHashMap<>(); + private final Map dateRangeButtons = new LinkedHashMap<>(); + private GameVersionFilterCatalog gameVersions = GameVersionFilterCatalog.empty(); + private Integer minFavoritesPreset; + private Integer minDownloadsPreset; + private DateRangePreset dateRangePreset = DateRangePreset.ANY; + private boolean showPreReleases; + private boolean openSourceOnly; + private boolean downloadSort; + private boolean suppressSearch; + + public ProjectBrowseFilterOptions(Runnable onSearch, Runnable onChange, Runnable onResetTags) { + this.onSearch = onSearch; + this.onChange = onChange; + this.onResetTags = onResetTags; + configureInputs(); + configurePopover(); + } + + public VBox popover() { + return popover; + } + + public int activeFilterCount() { + int count = 0; + if (selectedGameVersion() != null) { + count++; + } + if (openSourceOnly) { + count++; + } + if (selectedMinimumFavorites() != null) { + count++; + } + if (selectedMinimumDownloads() != null) { + count++; + } + if (!downloadSort && selectedDateRange() != null) { + count++; + } + return count; + } + + public void setDownloadSort(boolean downloadSort) { + this.downloadSort = downloadSort; + } + + public String selectedGameVersion() { + return gameVersionDropdown.selectedQuery(); + } + + public Boolean selectedOpenSource() { + return openSourceOnly ? Boolean.TRUE : null; + } + + public Integer selectedMinimumFavorites() { + Integer custom = parsePositiveInteger(customMinFavoritesField.getText()); + if (custom != null) { + return custom; + } + return minFavoritesPreset; + } + + public Integer selectedMinimumDownloads() { + Integer custom = parsePositiveInteger(customMinDownloadsField.getText()); + if (custom != null) { + return custom; + } + return minDownloadsPreset; + } + + public String selectedDateRange() { + LocalDate customDate = updatedAfterPicker.getValue(); + if (customDate != null) { + return customDate.toString(); + } + return dateRangePreset.apiValue(); + } + + public void replaceGameVersions(List versions) { + String selected = selectedGameVersion(); + withSuppressedSearch(() -> { + gameVersions = GameVersionFilterCatalog.fromVersions(versions); + showPreReleases = false; + updateGameVersionOptions(selected); + }); + refreshAndNotify(false); + } + + public void replaceGameVersionCatalog(GameVersionCatalog catalog) { + if (catalog == null) { + replaceGameVersions(List.of()); + return; + } + + String selected = selectedGameVersion(); + withSuppressedSearch(() -> { + gameVersions = GameVersionFilterCatalog.from(catalog); + showPreReleases = false; + updateGameVersionOptions(selected); + }); + refreshAndNotify(false); + } + + public void selectDateRange(String dateRange) { + withSuppressedSearch(() -> { + dateRangePreset = DateRangePreset.fromApiValue(dateRange); + updatedAfterPicker.setValue(null); + }); + refreshAndNotify(true); + } + + private void configureInputs() { + gameVersionDropdown.setOnSelectionChange(ignored -> changedAndSearch()); + gameVersionDropdown.getStyleClass().add("filter-game-version-dropdown"); + gameVersionDropdown.setMaxListHeight(192); + preReleaseToggle.getStyleClass().add("pre-release-toggle"); + preReleaseToggle.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 11)); + preReleaseToggle.setOnAction(event -> togglePreReleases()); + openSourceButton.getStyleClass().add("filter-toggle-button"); + openSourceButton.setMaxWidth(Double.MAX_VALUE); + HBox openSourceContent = openSourceButtonContent(); + openSourceContent.prefWidthProperty().bind(openSourceButton.widthProperty().subtract(24)); + openSourceButton.setGraphic(openSourceContent); + openSourceButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + openSourceButton.setAccessibleText("Open source license filter"); + openSourceButton.setOnAction(event -> toggleOpenSource()); + updatedAfterPicker.setOnAction(event -> { + if (updatedAfterPicker.getValue() != null) { + dateRangePreset = DateRangePreset.ANY; + } + changedAndSearch(); + }); + customMinFavoritesField.setPromptText("Custom min favorites..."); + customMinFavoritesField.textProperty().addListener((observable, oldValue, newValue) -> changedAndSearch()); + customMinDownloadsField.setPromptText("Custom min downloads..."); + customMinDownloadsField.textProperty().addListener((observable, oldValue, newValue) -> changedAndSearch()); + updatedAfterPicker.setPromptText("Pick a date"); + styleInput(customMinFavoritesField, customMinDownloadsField); + customMinFavoritesField.getStyleClass().add("filter-input"); + customMinDownloadsField.getStyleClass().add("filter-input"); + customMinFavoritesField.getStyleClass().add("filter-input-with-icon"); + customMinDownloadsField.getStyleClass().add("filter-input-with-icon"); + updatedAfterPicker.getStyleClass().addAll("date-picker", "filter-date-picker"); + } + + private void configurePopover() { + popover.getStyleClass().add("filter-popover"); + popover.setPrefWidth(288); + popover.setMaxWidth(288); + popover.setVisible(false); + popover.setManaged(false); + popover.addEventHandler(ScrollEvent.SCROLL, ScrollEvent::consume); + + Node version = gameVersionSection(); + Node license = filterSection("LICENSE", openSourceButton); + Node favorites = filterSection( + "MINIMUM FAVORITES", + numberPresetRow(minFavoritesButtons, List.of( + new NumberPreset("Any", null), + new NumberPreset("10+", 10), + new NumberPreset("50+", 50), + new NumberPreset("100+", 100) + ), this::selectMinimumFavoritesPreset), + inputWithIcon(customMinFavoritesField, LauncherIcons.Glyph.HEART) + ); + Node downloads = filterSection( + "DOWNLOADS", + numberPresetRow(minDownloadsButtons, List.of( + new NumberPreset("Any", null), + new NumberPreset("1k+", 1_000), + new NumberPreset("5k+", 5_000), + new NumberPreset("10k+", 10_000) + ), this::selectMinimumDownloadsPreset), + inputWithIcon(customMinDownloadsField, LauncherIcons.Glyph.DOWNLOAD) + ); + Node updated = filterSection( + "LAST UPDATED", + datePresetRow(), + datePickerWithIcon() + ); + + Button reset = dangerButton("Reset Filters"); + reset.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.ROTATE_CCW, 14)); + reset.getStyleClass().add("filter-reset-button"); + reset.setMaxWidth(Double.MAX_VALUE); + reset.setOnAction(event -> reset(true)); + VBox resetSection = new VBox(reset); + resetSection.getStyleClass().add("filter-reset-section"); + + popover.getChildren().setAll(version, license, favorites, downloads, updated, resetSection); + refreshPresetButtons(); + } + + private Node gameVersionSection() { + VBox box = new VBox(6); + box.getStyleClass().add("filter-section"); + HBox header = new HBox(8); + header.setAlignment(Pos.CENTER_LEFT); + Label labelNode = new Label("GAME VERSION"); + labelNode.getStyleClass().add("filter-label"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + header.getChildren().addAll(labelNode, spacer, preReleaseToggle); + box.getChildren().addAll(header, gameVersionDropdown); + gameVersionDropdown.setMaxWidth(Double.MAX_VALUE); + return box; + } + + private HBox openSourceButtonContent() { + HBox content = new HBox(8); + content.getStyleClass().add("filter-toggle-content"); + content.setAlignment(Pos.CENTER_LEFT); + Node check = LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 13); + check.getStyleClass().add("filter-toggle-check"); + Label label = new Label("Open Source"); + label.getStyleClass().add("filter-toggle-label"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Node scale = LauncherIcons.icon(LauncherIcons.Glyph.SCALE, 14); + scale.getStyleClass().add("filter-toggle-icon"); + content.getChildren().addAll(check, label, spacer, scale); + return content; + } + + private Node inputWithIcon(TextField field, LauncherIcons.Glyph glyph) { + StackPane wrapper = new StackPane(field); + wrapper.getStyleClass().add("filter-input-wrap"); + Node icon = LauncherIcons.icon(glyph, 14); + icon.getStyleClass().add("filter-input-icon"); + icon.setMouseTransparent(true); + StackPane.setAlignment(icon, Pos.CENTER_LEFT); + StackPane.setMargin(icon, new Insets(0, 0, 0, 12)); + wrapper.getChildren().add(icon); + field.setMaxWidth(Double.MAX_VALUE); + return wrapper; + } + + private Node datePickerWithIcon() { + StackPane wrapper = new StackPane(updatedAfterPicker); + wrapper.getStyleClass().add("filter-input-wrap"); + Node icon = LauncherIcons.icon(LauncherIcons.Glyph.CALENDAR, 14); + icon.getStyleClass().add("filter-input-icon"); + icon.setMouseTransparent(true); + StackPane.setAlignment(icon, Pos.CENTER_LEFT); + StackPane.setMargin(icon, new Insets(0, 0, 0, 12)); + wrapper.getChildren().add(icon); + updatedAfterPicker.setMaxWidth(Double.MAX_VALUE); + return wrapper; + } + + private Node filterSection(String label, Node... controls) { + VBox box = new VBox(6); + Label labelNode = new Label(label); + labelNode.getStyleClass().add("filter-label"); + box.getStyleClass().add("filter-section"); + box.getChildren().add(labelNode); + for (Node control : controls) { + if (control instanceof Region region) { + region.setMaxWidth(Double.MAX_VALUE); + } + box.getChildren().add(control); + } + return box; + } + + private HBox numberPresetRow( + Map buttons, + List presets, + Consumer onSelect + ) { + HBox row = new HBox(4); + row.getStyleClass().add("filter-preset-row"); + row.setAlignment(Pos.CENTER); + for (NumberPreset preset : presets) { + Button button = presetButton(preset.label()); + button.setOnAction(event -> onSelect.accept(preset.value())); + buttons.put(preset.value(), button); + row.getChildren().add(button); + HBox.setHgrow(button, Priority.ALWAYS); + } + return row; + } + + private HBox datePresetRow() { + HBox row = new HBox(4); + row.getStyleClass().add("filter-preset-row"); + row.setAlignment(Pos.CENTER); + for (DateRangePreset preset : List.of( + DateRangePreset.ANY, + DateRangePreset.SEVEN_DAYS, + DateRangePreset.THIRTY_DAYS, + DateRangePreset.NINETY_DAYS + )) { + Button button = presetButton(preset.label()); + button.setOnAction(event -> selectDateRange(preset.apiValue())); + dateRangeButtons.put(preset, button); + row.getChildren().add(button); + HBox.setHgrow(button, Priority.ALWAYS); + } + return row; + } + + private Button presetButton(String label) { + Button button = new Button(label); + button.getStyleClass().add("filter-preset-button"); + button.setMaxWidth(Double.MAX_VALUE); + return button; + } + + public void reset(boolean runSearch) { + withSuppressedSearch(() -> { + gameVersionDropdown.setSelectedVersions(List.of()); + minFavoritesPreset = null; + minDownloadsPreset = null; + dateRangePreset = DateRangePreset.ANY; + showPreReleases = false; + openSourceOnly = false; + customMinFavoritesField.clear(); + customMinDownloadsField.clear(); + updatedAfterPicker.setValue(null); + onResetTags.run(); + updateGameVersionOptions(null); + }); + refreshAndNotify(runSearch); + } + + private void selectMinimumFavoritesPreset(Integer value) { + withSuppressedSearch(() -> { + minFavoritesPreset = value; + customMinFavoritesField.clear(); + }); + refreshAndNotify(true); + } + + private void selectMinimumDownloadsPreset(Integer value) { + withSuppressedSearch(() -> { + minDownloadsPreset = value; + customMinDownloadsField.clear(); + }); + refreshAndNotify(true); + } + + private void refreshAndNotify(boolean runSearch) { + refreshPresetButtons(); + onChange.run(); + if (runSearch) { + onSearch.run(); + } + } + + private void refreshPresetButtons() { + boolean customFavorites = parsePositiveInteger(customMinFavoritesField.getText()) != null; + boolean customDownloads = parsePositiveInteger(customMinDownloadsField.getText()) != null; + boolean customDate = updatedAfterPicker.getValue() != null; + minFavoritesButtons.forEach((value, button) -> + pseudo(button, "selected", !customFavorites && Objects.equals(value, minFavoritesPreset))); + minDownloadsButtons.forEach((value, button) -> + pseudo(button, "selected", !customDownloads && Objects.equals(value, minDownloadsPreset))); + dateRangeButtons.forEach((value, button) -> + pseudo(button, "selected", !customDate && value == dateRangePreset)); + pseudo(openSourceButton, "selected", openSourceOnly); + boolean hasPreReleases = gameVersions.hasPreReleases(); + preReleaseToggle.setVisible(hasPreReleases); + preReleaseToggle.setManaged(hasPreReleases); + pseudo(preReleaseToggle, "selected", showPreReleases); + } + + private void changedAndSearch() { + if (suppressSearch) { + return; + } + refreshAndNotify(true); + } + + private void withSuppressedSearch(Runnable work) { + boolean previous = suppressSearch; + suppressSearch = true; + try { + work.run(); + } finally { + suppressSearch = previous; + } + } + + private void togglePreReleases() { + String previous = selectedGameVersion(); + withSuppressedSearch(() -> { + showPreReleases = !showPreReleases; + updateGameVersionOptions(previous); + }); + refreshAndNotify(!Objects.equals(previous, selectedGameVersion())); + } + + private void toggleOpenSource() { + openSourceOnly = !openSourceOnly; + changedAndSearch(); + } + + private void updateGameVersionOptions(String preferredSelection) { + List options = gameVersions.visibleVersions(showPreReleases); + List preferred = GameVersionGroups.parseSelection(preferredSelection).stream() + .filter(options::contains) + .toList(); + gameVersionDropdown.setVersions(options); + gameVersionDropdown.setSelectedVersions(preferred); + } + + private static Integer parsePositiveInteger(String value) { + if (value == null || value.isBlank()) { + return null; + } + try { + int parsed = Integer.parseInt(value.trim()); + return parsed > 0 ? parsed : null; + } catch (NumberFormatException ex) { + return null; + } + } + + private record NumberPreset(String label, Integer value) { + } + + private enum DateRangePreset { + ANY("Any", null), + SEVEN_DAYS("7d", "7d"), + THIRTY_DAYS("30d", "30d"), + NINETY_DAYS("90d", "90d"); + + private final String label; + private final String apiValue; + + DateRangePreset(String label, String apiValue) { + this.label = label; + this.apiValue = apiValue; + } + + String label() { + return label; + } + + String apiValue() { + return apiValue; + } + + static DateRangePreset fromApiValue(String rawValue) { + if (rawValue == null || rawValue.isBlank()) { + return ANY; + } + String normalized = rawValue.trim(); + for (DateRangePreset preset : values()) { + if (Objects.equals(preset.apiValue, normalized)) { + return preset; + } + } + return ANY; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseSort.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseSort.java new file mode 100644 index 00000000..ce4a2de9 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseSort.java @@ -0,0 +1,62 @@ +package net.modtale.launcher.ui.browse.controls; + +import java.util.Arrays; +import java.util.Locale; + +public enum ProjectBrowseSort { + RELEVANCE("relevance", "Relevance", ""), + POPULAR("popular", "Popular", "Popular"), + TRENDING("trending", "Trending", "Trending"), + DOWNLOADS("downloads", "Downloads", "Most Downloaded"), + FAVORITES("favorites", "Favorites", "Most Favorited"), + NEWEST("newest", "Newest", "New Releases"), + UPDATED("updated", "Updated", "Recently Updated"); + + private final String apiValue; + private final String label; + private final String title; + + ProjectBrowseSort(String apiValue, String label, String title) { + this.apiValue = apiValue; + this.label = label; + this.title = title; + } + + public String apiValue() { + return apiValue; + } + + public String label() { + return label; + } + + public String title() { + return title; + } + + public BrowseOptions.BrowseViewOption browseView() { + return switch (this) { + case POPULAR -> BrowseOptions.BrowseViewOption.POPULAR; + case TRENDING -> BrowseOptions.BrowseViewOption.TRENDING; + case NEWEST -> BrowseOptions.BrowseViewOption.NEW; + case UPDATED -> BrowseOptions.BrowseViewOption.UPDATED; + case RELEVANCE, DOWNLOADS, FAVORITES -> BrowseOptions.BrowseViewOption.ALL; + }; + } + + public static ProjectBrowseSort defaultSort() { + return RELEVANCE; + } + + public static ProjectBrowseSort fromLabel(String label) { + if (label == null || label.isBlank()) { + return defaultSort(); + } + String normalized = label.trim().toLowerCase(Locale.ROOT); + return Arrays.stream(values()) + .filter(sort -> sort.label.toLowerCase(Locale.ROOT).equals(normalized) + || sort.title.toLowerCase(Locale.ROOT).equals(normalized)) + .findFirst() + .orElse(defaultSort()); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseTags.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseTags.java new file mode 100644 index 00000000..08e184be --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseTags.java @@ -0,0 +1,135 @@ +package net.modtale.launcher.ui.browse.controls; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; + +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.input.ScrollEvent; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; + +public final class ProjectBrowseTags { + + private final Runnable onSearch; + private final Runnable onChange; + private final Map tagButtons = new LinkedHashMap<>(); + private final Set selectedTags = new LinkedHashSet<>(); + private final VBox popover = new VBox(12); + + public ProjectBrowseTags(Runnable onSearch, Runnable onChange) { + this.onSearch = onSearch; + this.onChange = onChange; + configurePopover(); + } + + public VBox popover() { + return popover; + } + + public boolean isEmpty() { + return selectedTags.isEmpty(); + } + + public int selectedCount() { + return selectedTags.size(); + } + + public String selectedQuery() { + return selectedTags.isEmpty() ? null : String.join(",", selectedTags); + } + + public String title() { + String first = selectedTags.iterator().next(); + int remaining = selectedTags.size() - 1; + return remaining > 0 ? "Tagged: " + first + " (+" + remaining + ")" : "Tagged: " + first; + } + + public void clear() { + selectedTags.clear(); + updateButtons(); + } + + public void refresh() { + updateButtons(); + } + + private void configurePopover() { + popover.getStyleClass().addAll("filter-popover", "tag-popover"); + popover.setPrefWidth(288); + popover.setMaxWidth(288); + popover.setVisible(false); + popover.setManaged(false); + popover.addEventHandler(ScrollEvent.SCROLL, ScrollEvent::consume); + + HBox header = new HBox(12); + header.getStyleClass().add("tag-popover-header"); + header.setAlignment(Pos.CENTER_LEFT); + Label title = new Label("Filter by Tag"); + title.getStyleClass().add("popover-title"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Button clear = new Button("Clear All"); + clear.getStyleClass().add("tag-clear-button"); + clear.setOnAction(event -> { + selectedTags.clear(); + updateButtons(); + onSearch.run(); + }); + header.getChildren().addAll(title, spacer, clear); + + FlowPane tags = new FlowPane(8, 8); + tags.getStyleClass().add("tag-grid"); + for (String tag : BrowseOptions.GLOBAL_TAGS) { + Button button = new Button(tag); + button.getStyleClass().add("tag-chip"); + button.setOnAction(event -> { + if (!selectedTags.add(tag)) { + selectedTags.remove(tag); + } + updateButtons(); + onSearch.run(); + }); + tagButtons.put(tag, button); + tags.getChildren().add(button); + } + + ScrollPane tagScroll = new ScrollPane(tags); + tagScroll.getStyleClass().add("tag-scroll"); + tagScroll.setFitToWidth(true); + tagScroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + tagScroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + tagScroll.setMaxHeight(240); + tagScroll.addEventFilter(ScrollEvent.SCROLL, event -> scrollTags(tagScroll, event)); + header.addEventFilter(ScrollEvent.SCROLL, ScrollEvent::consume); + popover.getChildren().setAll(header, tagScroll); + } + + private void updateButtons() { + tagButtons.forEach((tag, button) -> pseudo(button, "selected", selectedTags.contains(tag))); + onChange.run(); + } + + private static void scrollTags(ScrollPane scrollPane, ScrollEvent event) { + double scrollable = scrollPane.getContent().getLayoutBounds().getHeight() + - scrollPane.getViewportBounds().getHeight(); + if (scrollable > 1) { + double pixels = switch (event.getTextDeltaYUnits()) { + case LINES -> event.getTextDeltaY() * 48; + case PAGES -> event.getTextDeltaY() * Math.max(120, scrollPane.getViewportBounds().getHeight() * 0.86); + case NONE -> event.getDeltaY(); + }; + double next = scrollPane.getVvalue() - pixels / scrollable; + scrollPane.setVvalue(Math.max(scrollPane.getVmin(), Math.min(next, scrollPane.getVmax()))); + } + event.consume(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseViewStyleSelector.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseViewStyleSelector.java new file mode 100644 index 00000000..1164d888 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/controls/ProjectBrowseViewStyleSelector.java @@ -0,0 +1,61 @@ +package net.modtale.launcher.ui.browse.controls; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; + +import java.util.LinkedHashMap; +import java.util.Map; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.HBox; +import net.modtale.launcher.ui.browse.card.ProjectCardViewStyle; +import net.modtale.launcher.ui.common.LauncherIcons; + +public final class ProjectBrowseViewStyleSelector { + + private final Runnable onRender; + private final Map buttons = new LinkedHashMap<>(); + private ProjectCardViewStyle style = ProjectCardViewStyle.GRID; + private Node view; + + public ProjectBrowseViewStyleSelector(Runnable onRender) { + this.onRender = onRender; + } + + public ProjectCardViewStyle style() { + return style; + } + + public Node view() { + if (view == null) { + HBox selector = new HBox(4); + selector.getStyleClass().add("segmented-control"); + selector.setAlignment(Pos.CENTER); + addButton(selector, ProjectCardViewStyle.GRID, LauncherIcons.Glyph.GRID, "Grid"); + addButton(selector, ProjectCardViewStyle.LIST, LauncherIcons.Glyph.LIST, "List"); + addButton(selector, ProjectCardViewStyle.COMPACT, LauncherIcons.Glyph.ALIGN_JUSTIFY, "Compact"); + refresh(); + view = selector; + } + return view; + } + + public void refresh() { + buttons.forEach((candidate, button) -> pseudo(button, "selected", candidate == style)); + } + + private void addButton(HBox selector, ProjectCardViewStyle candidate, LauncherIcons.Glyph icon, String label) { + Button button = new Button(); + button.getStyleClass().add("segmented-button"); + button.setGraphic(LauncherIcons.icon(icon, 16)); + button.setTooltip(new Tooltip(label)); + button.setOnAction(event -> { + style = candidate; + refresh(); + onRender.run(); + }); + buttons.put(candidate, button); + selector.getChildren().add(button); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/render/ProjectBrowserRenderer.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/render/ProjectBrowserRenderer.java new file mode 100644 index 00000000..2ea2fbc2 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/render/ProjectBrowserRenderer.java @@ -0,0 +1,385 @@ +package net.modtale.launcher.ui.browse.render; + +import static net.modtale.launcher.ui.common.LauncherUi.emptyState; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import javafx.geometry.Bounds; +import javafx.scene.Node; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.LauncherPerformanceProbe; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.ui.browse.card.ProjectCardFactory; +import net.modtale.launcher.ui.browse.card.ProjectCardViewStyle; + +public final class ProjectBrowserRenderer { + + private static final int MAX_CACHED_PROJECT_CARDS = 256; + private static final int LIST_PAGE_SIZE = 12; + private static final int CARD_PAGE_SIZE = 12; + private static final int COMPACT_PAGE_SIZE = 45; + private static final double GRID_MIN_CARD_BODY_HEIGHT = 216; + private static final double GRID_MAX_CARD_BODY_HEIGHT = 228; + private static final double GRID_FALLBACK_WIDTH = 936; + private static final double GRID_THREE_COLUMN_WIDTH = 1320; + private static final double GRID_HORIZONTAL_GAP = 27; + private static final double GRID_VERTICAL_GAP = 30; + private static final double COMPACT_FALLBACK_WIDTH = 936; + private static final double COMPACT_CARD_HEIGHT = 90; + private static final double COMPACT_THREE_COLUMN_WIDTH = 1120; + private static final double COMPACT_HORIZONTAL_GAP = 19.5; + private static final double COMPACT_VERTICAL_GAP = 19.5; + + private final StackPane projectResults; + private final StackPane viewDeck; + private final Supplier contentBody; + private final ProjectCardFactory projectCardFactory; + private final Function favoriteResolver; + private final Supplier gameVersion; + private final Consumer onInstall; + private final Consumer onOpenPage; + private final Consumer onOpenCreator; + private final Consumer onToggleFavorite; + private final Map projectCardCache = new LinkedHashMap<>(128, 0.75f, true) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > MAX_CACHED_PROJECT_CARDS; + } + }; + + private LayoutMetrics lastRenderedLayout = LayoutMetrics.unset(); + + public ProjectBrowserRenderer( + StackPane projectResults, + StackPane viewDeck, + Supplier contentBody, + ProjectCardFactory projectCardFactory, + Function favoriteResolver, + Supplier gameVersion, + Consumer onInstall, + Consumer onOpenPage, + Consumer onOpenCreator, + Consumer onToggleFavorite + ) { + this.projectResults = projectResults; + this.viewDeck = viewDeck; + this.contentBody = contentBody; + this.projectCardFactory = projectCardFactory; + this.favoriteResolver = favoriteResolver; + this.gameVersion = gameVersion; + this.onInstall = onInstall; + this.onOpenPage = onOpenPage; + this.onOpenCreator = onOpenCreator; + this.onToggleFavorite = onToggleFavorite; + } + + public void render(List projects, ProjectCardViewStyle cardViewStyle) { + render(projects, cardViewStyle, pageSizeForView(cardViewStyle)); + } + + public void render(List projects, ProjectCardViewStyle cardViewStyle, int pageSize) { + long operationStart = LauncherPerformanceProbe.operationStartNanos(); + try { + if (projects.isEmpty()) { + lastRenderedLayout = LayoutMetrics.unset(); + projectResults.getChildren().setAll(emptyState("No matches found", "Try another search term or category.")); + return; + } + LayoutMetrics layout = layoutMetricsFor(cardViewStyle, pageSize); + Node container = resultsContainer(cardViewStyle, layout); + int cardCount = Math.min(projects.size(), layout.pageSize()); + List cards = new ArrayList<>(cardCount); + String selectedGameVersion = gameVersion.get(); + for (int i = 0; i < cardCount; i++) { + cards.add(projectCard(projects.get(i), cardViewStyle, selectedGameVersion, + layout.cardWidth(), layout.cardHeight())); + } + if (container instanceof GridPane gridPane) { + gridPane.getChildren().clear(); + for (int i = 0; i < cards.size(); i++) { + gridPane.add(cards.get(i), i % layout.columns(), i / layout.columns()); + } + } else if (container instanceof VBox vBox) { + vBox.getChildren().setAll(cards); + } + projectResults.getChildren().setAll(container); + lastRenderedLayout = layout; + } finally { + LauncherPerformanceProbe.recordOperation("browse.render", operationStart); + } + } + + public boolean shouldRenderForLayout(ProjectCardViewStyle cardViewStyle) { + return shouldRenderForLayout(cardViewStyle, pageSizeForView(cardViewStyle)); + } + + public boolean shouldRenderForLayout(ProjectCardViewStyle cardViewStyle, int pageSize) { + if (cardViewStyle == ProjectCardViewStyle.LIST) { + return false; + } + LayoutMetrics nextLayout = layoutMetricsFor(cardViewStyle, pageSize); + return !nextLayout.sameGeometry(lastRenderedLayout); + } + + public int pageSizeForView(ProjectCardViewStyle cardViewStyle) { + return layoutMetricsFor(cardViewStyle).pageSize(); + } + + int columnsForView(ProjectCardViewStyle cardViewStyle) { + return layoutMetricsFor(cardViewStyle).columns(); + } + + int pageSizeForView(ProjectCardViewStyle cardViewStyle, int requestedPageSize) { + return layoutMetricsFor(cardViewStyle, requestedPageSize).pageSize(); + } + + private Node projectCard( + ProjectSummary project, + ProjectCardViewStyle cardViewStyle, + String selectedGameVersion, + double cardWidth, + double cardHeight + ) { + boolean favorite = Boolean.TRUE.equals(favoriteResolver.apply(project.id())); + ProjectCardKey key = new ProjectCardKey(project.routeKey(), cardViewStyle, selectedGameVersion, favorite, + cardWidthKey(cardViewStyle, cardWidth), cardHeightKey(cardViewStyle, cardHeight), projectSignature(project)); + Node card = projectCardCache.get(key); + if (card == null) { + card = projectCardFactory.create(project, cardViewStyle, selectedGameVersion, favorite, + onInstall, onOpenPage, onOpenCreator, onToggleFavorite, cardWidth, cardHeight); + projectCardCache.put(key, card); + } + detachFromParent(card); + return card; + } + + private Node resultsContainer(ProjectCardViewStyle cardViewStyle, LayoutMetrics layout) { + if (cardViewStyle == ProjectCardViewStyle.LIST) { + VBox list = new VBox(21); + list.getStyleClass().add("project-list"); + list.setFillWidth(true); + return list; + } + + GridPane grid = new GridPane(); + grid.getStyleClass().add(cardViewStyle == ProjectCardViewStyle.COMPACT ? "compact-grid" : "project-grid"); + grid.setAlignment(javafx.geometry.Pos.TOP_LEFT); + grid.setHgap(layout.horizontalGap()); + grid.setVgap(layout.verticalGap()); + grid.setMinWidth(0); + grid.setMaxWidth(Double.MAX_VALUE); + grid.setPrefWidth(layout.availableWidth()); + return grid; + } + + private void detachFromParent(Node node) { + if (node.getParent() instanceof Pane pane) { + pane.getChildren().remove(node); + } + } + + private int cardWidthKey(ProjectCardViewStyle cardViewStyle, double cardWidth) { + return cardViewStyle == ProjectCardViewStyle.LIST ? 0 : (int) Math.round(cardWidth); + } + + private int cardHeightKey(ProjectCardViewStyle cardViewStyle, double cardHeight) { + return cardViewStyle == ProjectCardViewStyle.LIST ? 0 : (int) Math.round(cardHeight); + } + + private int projectSignature(ProjectSummary project) { + return Objects.hash(project.slug(), project.title(), project.description(), project.authorId(), project.author(), + project.imageUrl(), project.bannerUrl(), project.classification(), project.downloadCount(), + project.favoriteCount(), project.updatedAt(), project.versions()); + } + + private LayoutMetrics layoutMetricsFor(ProjectCardViewStyle cardViewStyle) { + return layoutMetricsFor(cardViewStyle, defaultPageSizeForView(cardViewStyle)); + } + + private LayoutMetrics layoutMetricsFor(ProjectCardViewStyle cardViewStyle, int requestedPageSize) { + int pageSize = sanitizePageSize(requestedPageSize); + return switch (cardViewStyle) { + case LIST -> LayoutMetrics.list(pageSize); + case COMPACT -> compactLayoutMetrics(pageSize); + case GRID -> gridLayoutMetrics(pageSize); + }; + } + + private int defaultPageSizeForView(ProjectCardViewStyle cardViewStyle) { + return switch (cardViewStyle) { + case LIST -> LIST_PAGE_SIZE; + case COMPACT -> COMPACT_PAGE_SIZE; + case GRID -> CARD_PAGE_SIZE; + }; + } + + private int sanitizePageSize(int requestedPageSize) { + return Math.max(1, Math.min(100, requestedPageSize)); + } + + private LayoutMetrics gridLayoutMetrics(int pageSize) { + double availableWidth = measuredOrFallback(browseResultsWidth(), GRID_FALLBACK_WIDTH); + int columns = breakpointColumns(availableWidth, GRID_THREE_COLUMN_WIDTH); + double cardWidth = cellSize(availableWidth, columns, GRID_HORIZONTAL_GAP); + double bannerHeight = Math.round(cardWidth / 3.0); + double bodyHeight = Math.round(clamp(cardWidth * 0.52, GRID_MIN_CARD_BODY_HEIGHT, GRID_MAX_CARD_BODY_HEIGHT)); + double cardHeight = bannerHeight + bodyHeight; + return new LayoutMetrics( + columns, + rowsForPageSize(columns, pageSize), + pageSize, + cardWidth, + cardHeight, + availableWidth, + GRID_HORIZONTAL_GAP, + GRID_VERTICAL_GAP + ); + } + + private LayoutMetrics compactLayoutMetrics(int pageSize) { + double availableWidth = measuredOrFallback(browseResultsWidth(), COMPACT_FALLBACK_WIDTH); + int columns = breakpointColumns(availableWidth, COMPACT_THREE_COLUMN_WIDTH); + double cardWidth = cellSize(availableWidth, columns, COMPACT_HORIZONTAL_GAP); + return new LayoutMetrics( + columns, + rowsForPageSize(columns, pageSize), + pageSize, + cardWidth, + COMPACT_CARD_HEIGHT, + availableWidth, + COMPACT_HORIZONTAL_GAP, + COMPACT_VERTICAL_GAP + ); + } + + private int breakpointColumns(double availableWidth, double threeColumnWidth) { + if (availableWidth >= threeColumnWidth) { + return 3; + } + return 2; + } + + private int rowsForPageSize(int columns, int pageSize) { + return Math.max(1, (int) Math.ceil((double) pageSize / Math.max(1, columns))); + } + + private double cellSize(double available, int count, double gap) { + return Math.max(1, (available - gap * (count - 1)) / count); + } + + private double measuredOrFallback(double measured, double fallback) { + return Double.isFinite(measured) && measured > 0 ? measured : fallback; + } + + private double clamp(double value, double min, double max) { + return Math.max(min, Math.min(max, value)); + } + + private double browseResultsWidth() { + double viewportWidth = enclosingScrollViewportWidth(); + if (viewportWidth > 0) { + return viewportWidth; + } + double parentWidth = nodeWidth(projectResults.getParent()); + if (parentWidth > 0) { + return parentWidth; + } + double deckWidth = nodeWidth(viewDeck); + if (deckWidth > 0) { + return deckWidth; + } + VBox body = contentBody.get(); + double bodyWidth = nodeWidth(body); + if (bodyWidth > 0) { + return bodyWidth; + } + return nodeWidth(projectResults); + } + + private double enclosingScrollViewportWidth() { + double width = scrollViewportWidth(projectResults); + if (width > 0) { + return width; + } + return scrollViewportWidth(contentBody.get()); + } + + private double scrollViewportWidth(Node start) { + for (Node current = start; current != null; current = current.getParent()) { + if (current instanceof ScrollPane scrollPane) { + Bounds viewport = scrollPane.getViewportBounds(); + return viewport == null ? 0 : usableWidth(viewport.getWidth()); + } + } + return 0; + } + + private double nodeWidth(Node node) { + if (node == null) { + return 0; + } + if (node instanceof Region region) { + double regionWidth = usableWidth(region.getWidth()); + if (regionWidth > 0) { + return regionWidth; + } + } + return usableWidth(node.getLayoutBounds().getWidth()); + } + + private double usableWidth(double width) { + return Double.isFinite(width) && width > 0 ? width : 0; + } + + private record ProjectCardKey( + String projectId, + ProjectCardViewStyle viewStyle, + String gameVersion, + boolean favorite, + int cardWidth, + int cardHeight, + int projectSignature + ) { + } + + private record LayoutMetrics( + int columns, + int rows, + int pageSize, + double cardWidth, + double cardHeight, + double availableWidth, + double horizontalGap, + double verticalGap + ) { + + static LayoutMetrics list(int pageSize) { + return new LayoutMetrics(1, pageSize, pageSize, 0, 0, 0, 0, 0); + } + + static LayoutMetrics unset() { + return new LayoutMetrics(0, 0, 0, -1, -1, -1, 0, 0); + } + + boolean sameGeometry(LayoutMetrics other) { + return other != null + && columns == other.columns + && rows == other.rows + && pageSize == other.pageSize + && Math.abs(cardWidth - other.cardWidth) <= 1 + && Math.abs(cardHeight - other.cardHeight) <= 1 + && Math.abs(availableWidth - other.availableWidth) <= 1; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/browse/search/ProjectBrowseSearchState.java b/launcher/src/main/java/net/modtale/launcher/ui/browse/search/ProjectBrowseSearchState.java new file mode 100644 index 00000000..886d62e5 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/browse/search/ProjectBrowseSearchState.java @@ -0,0 +1,62 @@ +package net.modtale.launcher.ui.browse.search; + +import java.util.List; +import java.util.Objects; +import net.modtale.launcher.api.ProjectSearchQuery; +import net.modtale.launcher.model.project.ProjectSummary; + +public final class ProjectBrowseSearchState { + + public static final long DUPLICATE_SEARCH = -1; + + private long sequence; + private ProjectSearchQuery inFlightSearch; + private ProjectSearchQuery lastCompletedSearch; + + public long start(ProjectSearchQuery query) { + if (query.equals(inFlightSearch)) { + return DUPLICATE_SEARCH; + } + inFlightSearch = query; + return ++sequence; + } + + public boolean acceptCompletion(ProjectSearchQuery query, long requestId) { + if (query.equals(inFlightSearch)) { + inFlightSearch = null; + } + return requestId == sequence; + } + + public void recordCompleted(ProjectSearchQuery query) { + lastCompletedSearch = query; + } + + public boolean shouldSearchForLayout(ProjectSearchQuery nextQuery, List currentProjects) { + if (lastCompletedSearch == null) { + return true; + } + if (!sameSearchWithoutSize(nextQuery, lastCompletedSearch)) { + return true; + } + if (nextQuery.size() < lastCompletedSearch.size()) { + return true; + } + return nextQuery.size() > lastCompletedSearch.size() + && currentProjects.size() >= lastCompletedSearch.size(); + } + + private static boolean sameSearchWithoutSize(ProjectSearchQuery left, ProjectSearchQuery right) { + return Objects.equals(left.search(), right.search()) + && Objects.equals(left.classification(), right.classification()) + && Objects.equals(left.gameVersion(), right.gameVersion()) + && Objects.equals(left.sort(), right.sort()) + && left.page() == right.page() + && Objects.equals(left.tags(), right.tags()) + && Objects.equals(left.minDownloads(), right.minDownloads()) + && Objects.equals(left.minFavorites(), right.minFavorites()) + && Objects.equals(left.category(), right.category()) + && Objects.equals(left.dateRange(), right.dateRange()) + && Objects.equals(left.openSource(), right.openSource()); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/CachedImageLoader.java b/launcher/src/main/java/net/modtale/launcher/ui/common/CachedImageLoader.java new file mode 100644 index 00000000..2e3de011 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/CachedImageLoader.java @@ -0,0 +1,199 @@ +package net.modtale.launcher.ui.common; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.util.Collections; +import java.util.HexFormat; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executor; +import java.util.function.Function; +import javafx.application.Platform; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import net.modtale.launcher.cache.LauncherCachePaths; + +public final class CachedImageLoader { + + private static final String IMAGE_KEY_PROPERTY = CachedImageLoader.class.getName() + ".imageKey"; + private static final int MAX_MEMORY_IMAGES = 384; + + private final Function assetResolver; + private final Executor executor; + private final HttpClient httpClient; + private final Path cacheDirectory; + private final ConcurrentMap> downloads = new ConcurrentHashMap<>(); + private final Map memoryImages = Collections.synchronizedMap(new LinkedHashMap<>(64, 0.75f, true) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > MAX_MEMORY_IMAGES; + } + }); + + public CachedImageLoader(Function assetResolver, Executor executor) { + this(assetResolver, executor, LauncherCachePaths.cacheDirectory("images")); + } + + public CachedImageLoader(Function assetResolver, Executor executor, Path cacheDirectory) { + this.assetResolver = assetResolver; + this.executor = executor; + this.cacheDirectory = cacheDirectory; + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(12)) + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); + } + + public void loadInto(ImageView view, String rawUrl, double requestedWidth, double requestedHeight) { + loadInto(view, rawUrl, requestedWidth, requestedHeight, false); + } + + public void loadInto(ImageView view, String rawUrl, double requestedWidth, double requestedHeight, boolean preserveRatio) { + String resolvedUrl = assetResolver.apply(rawUrl); + ImageKey key = new ImageKey(resolvedUrl, requestedWidth, requestedHeight, preserveRatio); + view.getProperties().put(IMAGE_KEY_PROPERTY, key); + + Image memoryImage = memoryImages.get(key); + if (memoryImage != null) { + view.setImage(memoryImage); + return; + } + + if (!isHttpUrl(resolvedUrl)) { + setImage(view, key, imageFor(key, resolvedUrl)); + return; + } + + Path cachedFile = cacheFile(resolvedUrl); + if (Files.isRegularFile(cachedFile)) { + setImage(view, key, imageFor(key, cachedFile.toUri().toString())); + return; + } + + downloads.computeIfAbsent(resolvedUrl, this::downloadAsync) + .whenComplete((path, error) -> { + if (error != null || path == null) { + return; + } + Platform.runLater(() -> { + if (Objects.equals(view.getProperties().get(IMAGE_KEY_PROPERTY), key)) { + setImage(view, key, imageFor(key, path.toUri().toString())); + } + }); + }); + } + + public void clearMemory() { + memoryImages.clear(); + downloads.clear(); + } + + public void clear(ImageView view) { + view.getProperties().remove(IMAGE_KEY_PROPERTY); + view.setImage(null); + } + + private CompletableFuture downloadAsync(String resolvedUrl) { + return CompletableFuture.supplyAsync(() -> download(resolvedUrl), executor) + .whenComplete((path, error) -> downloads.remove(resolvedUrl)); + } + + private Path download(String resolvedUrl) { + URI uri = URI.create(resolvedUrl); + HttpRequest request = HttpRequest.newBuilder(uri) + .timeout(Duration.ofSeconds(45)) + .header("Accept", "image/png,image/jpeg,image/gif,image/bmp,image/*;q=0.8,*/*;q=0.5") + .header("User-Agent", "ModtaleLauncher/0.1") + .GET() + .build(); + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); + if (response.statusCode() < 200 || response.statusCode() >= 300) { + throw new IOException("Image request returned HTTP " + response.statusCode()); + } + + Files.createDirectories(cacheDirectory); + Path destination = cacheFile(resolvedUrl); + Path temporary = Files.createTempFile(cacheDirectory, "image-", ".tmp"); + try (InputStream body = response.body()) { + Files.copy(body, temporary, StandardCopyOption.REPLACE_EXISTING); + } + try { + Files.move(temporary, destination, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + } catch (AtomicMoveNotSupportedException ex) { + Files.move(temporary, destination, StandardCopyOption.REPLACE_EXISTING); + } + return destination; + } catch (IOException ex) { + throw new IllegalStateException("Could not cache image " + resolvedUrl, ex); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Image download was interrupted.", ex); + } + } + + private void setImage(ImageView view, ImageKey key, Image image) { + if (!Objects.equals(view.getProperties().get(IMAGE_KEY_PROPERTY), key)) { + return; + } + view.setImage(image); + } + + private Image imageFor(ImageKey key, String imageUrl) { + Image cached = memoryImages.get(key); + if (cached != null) { + return cached; + } + Image image = new Image(imageUrl, key.requestedWidth(), key.requestedHeight(), key.preserveRatio(), true, true); + memoryImages.put(key, image); + return image; + } + + private Path cacheFile(String resolvedUrl) { + return cacheDirectory.resolve(sha256(resolvedUrl) + imageExtension(resolvedUrl)); + } + + private static boolean isHttpUrl(String url) { + return url != null && (url.startsWith("http://") || url.startsWith("https://")); + } + + private static String sha256(String value) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] bytes = digest.digest(value.getBytes(StandardCharsets.UTF_8)); + return HexFormat.of().formatHex(bytes); + } catch (NoSuchAlgorithmException ex) { + throw new IllegalStateException("SHA-256 is not available.", ex); + } + } + + private static String imageExtension(String resolvedUrl) { + String path = URI.create(resolvedUrl).getPath(); + String normalized = path == null ? "" : path.toLowerCase(java.util.Locale.ROOT); + for (String extension : java.util.List.of(".png", ".jpg", ".jpeg", ".gif", ".bmp")) { + if (normalized.endsWith(extension)) { + return extension; + } + } + return ".img"; + } + + private record ImageKey(String url, double requestedWidth, double requestedHeight, boolean preserveRatio) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionDropdown.java b/launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionDropdown.java new file mode 100644 index 00000000..d9699344 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionDropdown.java @@ -0,0 +1,318 @@ +package net.modtale.launcher.ui.common; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import javafx.css.PseudoClass; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; + +public final class GameVersionDropdown extends VBox { + + private static final PseudoClass PARTIAL = PseudoClass.getPseudoClass("indeterminate"); + + private final Button toggle = new Button(); + private final Label toggleLabel = new Label("Any"); + private final Node toggleChevron = LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_DOWN, 14); + private final VBox panel = new VBox(0); + private final VBox options = new VBox(0); + private final ScrollPane scroll = new ScrollPane(options); + private final Set expandedGroups = new LinkedHashSet<>(); + + private List versions = List.of(); + private List selectedVersions = List.of(); + private String emptyText = "No versions found"; + private String anyLabel = "Any"; + private double maxListHeight = 224; + private Consumer> selectionListener = ignored -> { + }; + private Consumer openListener = ignored -> { + }; + + public GameVersionDropdown() { + getStyleClass().add("game-version-dropdown"); + setSpacing(6); + setMaxWidth(Double.MAX_VALUE); + + toggle.getStyleClass().add("game-version-dropdown-toggle"); + toggle.setMaxWidth(Double.MAX_VALUE); + toggle.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + HBox toggleContent = toggleContent(); + toggleContent.prefWidthProperty().bind(toggle.widthProperty().subtract(22)); + toggle.setGraphic(toggleContent); + toggle.setOnAction(event -> setOpen(!isOpen())); + + scroll.getStyleClass().add("game-version-dropdown-scroll"); + scroll.setFitToWidth(true); + scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + scroll.setMaxHeight(maxListHeight); + + panel.getStyleClass().add("game-version-dropdown-panel"); + panel.getChildren().add(scroll); + panel.setVisible(false); + panel.setManaged(false); + + getChildren().setAll(toggle, panel); + refresh(); + } + + public static GameVersionDropdown multiSelect() { + return new GameVersionDropdown(); + } + + public void setVersions(List versions) { + List safeVersions = versions == null ? List.of() : versions.stream() + .filter(version -> version != null && !version.isBlank()) + .distinct() + .toList(); + this.versions = List.copyOf(safeVersions); + this.selectedVersions = GameVersionGroups.orderedSelection(this.selectedVersions, this.versions); + refresh(); + } + + public List versions() { + return versions; + } + + public void setSelectedVersions(List selectedVersions) { + this.selectedVersions = selectedVersions(selectedVersions); + refresh(); + } + + public List selectedVersions() { + return selectedVersions; + } + + public String selectedQuery() { + return GameVersionGroups.selectionQuery(selectedVersions, versions); + } + + public void setAnyLabel(String anyLabel) { + this.anyLabel = anyLabel == null || anyLabel.isBlank() ? "Any" : anyLabel; + refresh(); + } + + public void setEmptyText(String emptyText) { + this.emptyText = emptyText == null || emptyText.isBlank() ? "No versions found" : emptyText; + refresh(); + } + + public void setMaxListHeight(double maxListHeight) { + this.maxListHeight = Math.max(120, maxListHeight); + scroll.setMaxHeight(this.maxListHeight); + } + + public boolean isOpen() { + return panel.isVisible(); + } + + public void setOpen(boolean open) { + if (panel.isVisible() == open) { + return; + } + panel.setVisible(open); + panel.setManaged(open); + pseudo(toggle, "open", open); + toggleChevron.setRotate(open ? 180 : 0); + openListener.accept(open); + } + + public void setOnSelectionChange(Consumer> selectionListener) { + this.selectionListener = selectionListener == null ? ignored -> { + } : selectionListener; + } + + public void setOnOpenChange(Consumer openListener) { + this.openListener = openListener == null ? ignored -> { + } : openListener; + } + + private HBox toggleContent() { + HBox content = new HBox(8); + content.getStyleClass().add("game-version-dropdown-toggle-content"); + content.setAlignment(Pos.CENTER_LEFT); + toggleLabel.getStyleClass().add("game-version-dropdown-toggle-label"); + toggleLabel.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(toggleLabel, Priority.ALWAYS); + toggleChevron.getStyleClass().add("game-version-dropdown-chevron"); + content.getChildren().addAll(toggleLabel, toggleChevron); + return content; + } + + private void refresh() { + toggleLabel.setText(GameVersionGroups.displayLabel(selectedVersions, versions, anyLabel)); + options.getChildren().setAll(optionNodes()); + } + + private List optionNodes() { + List nodes = new ArrayList<>(); + nodes.add(optionRow(anyLabel, selectedVersions.isEmpty(), () -> commitSelection(List.of()))); + List groups = GameVersionGroups.build(versions); + if (groups.isEmpty()) { + Label empty = new Label(emptyText); + empty.getStyleClass().add("game-version-dropdown-empty"); + nodes.add(empty); + return nodes; + } + for (GameVersionGroups.Group group : groups) { + if (!group.grouped()) { + String version = group.versions().isEmpty() ? "" : group.versions().getFirst(); + if (!version.isBlank()) { + nodes.add(optionRow(version, selectedVersions.contains(version), () -> toggleVersion(version))); + } + continue; + } + nodes.add(groupRow(group)); + if (expandedGroups.contains(group.label())) { + for (String version : group.versions()) { + nodes.add(childRow(version, selectedVersions.contains(version), () -> toggleVersion(version))); + } + } + } + return nodes; + } + + private Button optionRow(String label, boolean selected, Runnable action) { + Button row = new Button(); + row.getStyleClass().add("game-version-dropdown-row"); + row.setMaxWidth(Double.MAX_VALUE); + HBox content = rowContent(label, selected, null); + content.prefWidthProperty().bind(row.widthProperty().subtract(20)); + row.setGraphic(content); + row.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + pseudo(row, "selected", selected); + row.setOnAction(event -> action.run()); + return row; + } + + private Button childRow(String label, boolean selected, Runnable action) { + Button row = optionRow(label, selected, action); + row.getStyleClass().add("game-version-dropdown-child-row"); + return row; + } + + private HBox groupRow(GameVersionGroups.Group group) { + HBox row = new HBox(0); + row.getStyleClass().add("game-version-dropdown-group-row"); + row.setAlignment(Pos.CENTER_LEFT); + row.setMaxWidth(Double.MAX_VALUE); + + int selectedCount = (int) group.versions().stream().filter(selectedVersions::contains).count(); + boolean selected = selectedCount == group.versions().size(); + boolean partial = selectedCount > 0 && !selected; + pseudo(row, "selected", selected); + row.pseudoClassStateChanged(PARTIAL, partial); + + Button select = new Button(); + select.getStyleClass().add("game-version-dropdown-group-select"); + select.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + HBox selectContent = rowContent(group.label(), false, partial ? selectedCount + "/" + group.versions().size() : null); + selectContent.prefWidthProperty().bind(select.widthProperty().subtract(10)); + select.setGraphic(selectContent); + select.setMaxWidth(Double.MAX_VALUE); + select.setOnAction(event -> toggleGroupSelection(group.versions())); + HBox.setHgrow(select, Priority.ALWAYS); + + Button expand = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_RIGHT, 13)); + expand.getStyleClass().add("game-version-dropdown-expand"); + expand.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + expand.setOnAction(event -> toggleGroupExpanded(group.label())); + expand.getGraphic().setRotate(expandedGroups.contains(group.label()) ? 90 : 0); + + row.getChildren().addAll(select, expand); + if (selected) { + Node check = LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 14); + check.getStyleClass().add("game-version-dropdown-check"); + row.getChildren().add(check); + } + return row; + } + + private HBox rowContent(String label, boolean selected, String count) { + HBox content = new HBox(8); + content.getStyleClass().add("game-version-dropdown-row-content"); + content.setAlignment(Pos.CENTER_LEFT); + Label text = new Label(label); + text.getStyleClass().add("game-version-dropdown-row-label"); + text.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(text, Priority.ALWAYS); + content.getChildren().add(text); + if (count != null && !count.isBlank()) { + Label countLabel = new Label(count); + countLabel.getStyleClass().add("game-version-dropdown-count"); + content.getChildren().add(countLabel); + } + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + content.getChildren().add(spacer); + if (selected) { + Node check = LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 14); + check.getStyleClass().add("game-version-dropdown-check"); + content.getChildren().add(check); + } + return content; + } + + private void toggleVersion(String version) { + List next = new ArrayList<>(selectedVersions); + if (next.contains(version)) { + next.remove(version); + } else { + next.add(version); + } + commitSelection(next); + } + + private void toggleGroupSelection(List groupVersions) { + boolean hasEntireGroup = groupVersions.stream().allMatch(selectedVersions::contains); + List next = new ArrayList<>(selectedVersions); + if (hasEntireGroup) { + next.removeIf(groupVersions::contains); + } else { + for (String version : groupVersions) { + if (!next.contains(version)) { + next.add(version); + } + } + } + commitSelection(next); + } + + private void toggleGroupExpanded(String label) { + if (expandedGroups.contains(label)) { + expandedGroups.remove(label); + } else { + expandedGroups.add(label); + } + refresh(); + } + + private void commitSelection(List nextSelection) { + selectedVersions = selectedVersions(nextSelection); + refresh(); + selectionListener.accept(selectedVersions); + } + + private List selectedVersions(List selectedVersions) { + if (selectedVersions == null || selectedVersions.isEmpty()) { + return List.of(); + } + Set selected = new LinkedHashSet<>(selectedVersions); + return versions.stream() + .filter(selected::contains) + .toList(); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionGroups.java b/launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionGroups.java new file mode 100644 index 00000000..dc95b43f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/GameVersionGroups.java @@ -0,0 +1,106 @@ +package net.modtale.launcher.ui.common; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public final class GameVersionGroups { + + private GameVersionGroups() { + } + + public static List parseSelection(String value) { + if (value == null || value.isBlank() || "Any".equalsIgnoreCase(value.trim())) { + return List.of(); + } + return Arrays.stream(value.split(",")) + .map(String::trim) + .filter(version -> !version.isBlank() && !"Any".equalsIgnoreCase(version)) + .distinct() + .toList(); + } + + public static String selectionQuery(List selectedVersions, List orderedVersions) { + List ordered = orderedSelection(selectedVersions, orderedVersions); + return ordered.isEmpty() ? null : String.join(",", ordered); + } + + public static List orderedSelection(List selectedVersions, List orderedVersions) { + if (selectedVersions == null || selectedVersions.isEmpty()) { + return List.of(); + } + Set selected = new LinkedHashSet<>(selectedVersions); + List ordered = new ArrayList<>(); + if (orderedVersions != null) { + for (String version : orderedVersions) { + if (selected.remove(version)) { + ordered.add(version); + } + } + } + ordered.addAll(selected); + return List.copyOf(ordered); + } + + public static String rangeLabel(String version) { + if (version == null || version.isBlank()) { + return null; + } + String base = version.split("-", 2)[0]; + String[] parts = base.split("\\."); + if (parts.length < 2 || !isDigits(parts[0]) || !isDigits(parts[1])) { + return null; + } + return parts[0] + "." + parts[1] + ".x"; + } + + public static List build(List versions) { + if (versions == null || versions.isEmpty()) { + return List.of(); + } + Map> groups = new LinkedHashMap<>(); + for (String version : versions) { + if (version == null || version.isBlank()) { + continue; + } + String label = rangeLabel(version); + String key = label == null ? version : label; + groups.computeIfAbsent(key, ignored -> new ArrayList<>()).add(version); + } + return groups.entrySet().stream() + .map(entry -> new Group(entry.getKey(), List.copyOf(entry.getValue()), entry.getValue().size() > 1)) + .toList(); + } + + public static String displayLabel(List selectedVersions, List orderedVersions, String anyLabel) { + List selected = orderedSelection(selectedVersions, orderedVersions); + if (selected.isEmpty()) { + return anyLabel == null || anyLabel.isBlank() ? "Any" : anyLabel; + } + for (Group group : build(orderedVersions)) { + if (group.grouped() + && selected.size() == group.versions().size() + && selected.containsAll(group.versions())) { + return group.label(); + } + } + if (selected.size() == 1) { + return selected.getFirst(); + } + return selected.size() + " versions"; + } + + private static boolean isDigits(String value) { + return value != null && !value.isBlank() && value.chars().allMatch(Character::isDigit); + } + + public record Group(String label, List versions, boolean grouped) { + public Group { + versions = versions == null ? List.of() : List.copyOf(versions); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherAssetResolver.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherAssetResolver.java new file mode 100644 index 00000000..68e0d6ae --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherAssetResolver.java @@ -0,0 +1,52 @@ +package net.modtale.launcher.ui.common; + +import java.util.Objects; +import java.util.function.Supplier; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.settings.LauncherConfig; + +public final class LauncherAssetResolver { + + private final ModtaleApiClient apiClient; + private final Supplier fallbackAssetUrl; + + public LauncherAssetResolver(ModtaleApiClient apiClient, Supplier fallbackAssetUrl) { + this.apiClient = apiClient; + this.fallbackAssetUrl = fallbackAssetUrl; + } + + public String resolve(String rawUrl) { + if (rawUrl == null || rawUrl.isBlank()) { + return Objects.requireNonNull(fallbackAssetUrl.get()); + } + if (rawUrl.startsWith("http://") || rawUrl.startsWith("https://")) { + return rawUrl; + } + if (rawUrl.startsWith("/api")) { + return apiRoot() + rawUrl; + } + if (rawUrl.startsWith("/")) { + return LauncherConfig.siteBaseUrl().replaceAll("/+$", "") + rawUrl; + } + return rawUrl; + } + + public String resolveBackendAsset(String rawUrl) { + if (rawUrl == null || rawUrl.isBlank()) { + return Objects.requireNonNull(fallbackAssetUrl.get()); + } + if (rawUrl.startsWith("http://") || rawUrl.startsWith("https://")) { + return rawUrl; + } + if (rawUrl.startsWith("/")) { + return apiRoot() + rawUrl; + } + return rawUrl; + } + + private String apiRoot() { + var uri = apiClient.apiBaseUri(); + int port = uri.getPort(); + return uri.getScheme() + "://" + uri.getHost() + (port < 0 ? "" : ":" + port); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherExternalLinks.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherExternalLinks.java new file mode 100644 index 00000000..5a788efe --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherExternalLinks.java @@ -0,0 +1,41 @@ +package net.modtale.launcher.ui.common; + +import java.awt.Desktop; +import java.net.URI; +import java.util.function.BiConsumer; +import net.modtale.launcher.settings.LauncherConfig; + +public final class LauncherExternalLinks { + + private LauncherExternalLinks() { + } + + public static void open(String rawLink, BiConsumer toast) { + URI uri = resolve(rawLink); + if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + showError(toast, "Desktop browser integration is not available."); + return; + } + try { + Desktop.getDesktop().browse(uri); + } catch (Exception ex) { + showError(toast, "Could not open " + uri + "."); + } + } + + public static URI resolve(String rawLink) { + String link = rawLink == null || rawLink.isBlank() ? "/" : rawLink.trim(); + if (link.startsWith("http://") || link.startsWith("https://")) { + return URI.create(link); + } + String base = LauncherConfig.siteBaseUrl().replaceAll("/+$", ""); + String path = link.startsWith("/") ? link : "/" + link; + return URI.create(base + path); + } + + private static void showError(BiConsumer toast, String message) { + if (toast != null) { + toast.accept("Could not open link", message); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherFonts.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherFonts.java new file mode 100644 index 00000000..7913c327 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherFonts.java @@ -0,0 +1,30 @@ +package net.modtale.launcher.ui.common; + +import java.net.URL; +import java.util.concurrent.atomic.AtomicBoolean; +import javafx.scene.text.Font; + +public final class LauncherFonts { + + private static final AtomicBoolean LOADED = new AtomicBoolean(); + private static final String[] INTER_FONTS = { + "/net/modtale/launcher/ui/nativefx/fonts/Inter-Regular.ttf", + "/net/modtale/launcher/ui/nativefx/fonts/Inter-Bold.ttf", + "/net/modtale/launcher/ui/nativefx/fonts/Inter-Black.ttf" + }; + + private LauncherFonts() { + } + + public static void load() { + if (!LOADED.compareAndSet(false, true)) { + return; + } + for (String fontPath : INTER_FONTS) { + URL font = LauncherFonts.class.getResource(fontPath); + if (font != null) { + Font.loadFont(font.toExternalForm(), 16); + } + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherIcons.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherIcons.java new file mode 100644 index 00000000..e0ae4efc --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherIcons.java @@ -0,0 +1,165 @@ +package net.modtale.launcher.ui.common; + +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Group; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import javafx.scene.shape.SVGPath; +import javafx.scene.shape.StrokeLineCap; +import javafx.scene.shape.StrokeLineJoin; + +public final class LauncherIcons { + + public enum Glyph { + ALIGN_JUSTIFY("M3 6h18 M3 12h18 M3 18h18"), + ARROW_BIG_DOWN("M15 5H9v6H4.16a1 1 0 0 0-.82 1.57l8.84 9.58a1 1 0 0 0 1.48 0l8.84-9.58A1 1 0 0 0 21.84 11H17V5a2 2 0 0 0-2-2Z"), + ARROW_BIG_UP("M9 19h6v-6h4.84a1 1 0 0 0 .82-1.57l-8.84-9.58a1 1 0 0 0-1.48 0L2.34 11.43A1 1 0 0 0 3.16 13H8v6a2 2 0 0 0 2 2Z"), + BELL("M10.3 21a2 2 0 0 0 3.4 0 M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"), + BOOK_OPEN("M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2Z M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7Z"), + BOX("M21 8a2 2 0 0 0-1-1.73L12 2 4 6.27A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73L12 22l8-4.27A2 2 0 0 0 21 16Z M3.3 7 12 12l8.7-5 M12 22V12"), + CALENDAR("M8 2v4 M16 2v4 M3 10h18 M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Z"), + CHECK("M20 6 9 17l-5-5"), + ALERT_CIRCLE("M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Z M12 8v4 M12 16h.01"), + ALERT_TRIANGLE("M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z M12 9v4 M12 17h.01"), + ARROW_RIGHT("M5 12h14 M12 5l7 7-7 7"), + CHEVRON_DOWN("m6 9 6 6 6-6"), + CHEVRON_LEFT("m15 18-6-6 6-6"), + CHEVRON_RIGHT("m9 18 6-6-6-6"), + CHEVRON_UP("m18 15-6-6-6 6"), + CIRCLE("M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Z"), + CLOCK("M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Z M12 6v6l4 2"), + CODE("m16 18 6-6-6-6 M8 6l-6 6 6 6"), + COPY("M8 8h11a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2Z M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3"), + CORNER_DOWN_LEFT("m9 10-5 5 5 5 M20 4v7a4 4 0 0 1-4 4H4"), + CORNER_DOWN_RIGHT("m15 10 5 5-5 5 M4 4v7a4 4 0 0 0 4 4h12"), + DATABASE("M3 6c0 2 4 4 9 4s9-2 9-4-4-4-9-4-9 2-9 4Z M3 6v6c0 2 4 4 9 4s9-2 9-4V6 M3 12v6c0 2 4 4 9 4s9-2 9-4v-6"), + DOWNLOAD("M12 3v12 M7 10l5 5 5-5 M5 21h14"), + EDIT("M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7 M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4Z"), + EXTERNAL_LINK("M15 3h6v6 M10 14 21 3 M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"), + FILE_CODE("M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z M14 2v6h6 M10 13l-2 2 2 2 M14 17l2-2-2-2"), + FILTER("M22 3H2l8 9.46V19l4 2v-8.54Z"), + FLAG("M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z M4 22V15"), + FLAME("M8.5 14.5A4.5 4.5 0 1 0 16 11c0-4-4-6-4-9-3 2-5 5-5 9a5 5 0 0 0 1.5 3.5Z"), + GEAR("M12.2 2h-.4a2 2 0 0 0-2 2v.2a2 2 0 0 1-1 1.7l-.4.2a2 2 0 0 1-2 0l-.2-.1a2 2 0 0 0-2.7.7l-.2.4A2 2 0 0 0 4 9.8l.2.1a2 2 0 0 1 1 1.7v.6a2 2 0 0 1-1 1.7l-.2.1a2 2 0 0 0-.7 2.7l.2.4a2 2 0 0 0 2.7.7l.2-.1a2 2 0 0 1 2 0l.4.2a2 2 0 0 1 1 1.7v.4a2 2 0 0 0 2 2h.4a2 2 0 0 0 2-2v-.2a2 2 0 0 1 1-1.7l.4-.2a2 2 0 0 1 2 0l.2.1a2 2 0 0 0 2.7-.7l.2-.4a2 2 0 0 0-.7-2.7l-.2-.1a2 2 0 0 1-1-1.7v-.5a2 2 0 0 1 1-1.7l.2-.1a2 2 0 0 0 .7-2.7l-.2-.4a2 2 0 0 0-2.7-.7l-.2.1a2 2 0 0 1-2 0l-.4-.2a2 2 0 0 1-1-1.7V4a2 2 0 0 0-2-2Z M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"), + GEM("M6 3h12l4 6-10 12L2 9Z M2 9h20 M6 3l6 18 6-18"), + GLOBE("M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Z M2 12h20 M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10Z"), + GRID("M3 3h7v7H3Z M14 3h7v7h-7Z M14 14h7v7h-7Z M3 14h7v7H3Z"), + HASH("M4 9h16 M4 15h16 M10 3 8 21 M16 3l-2 18"), + HEART("M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.6l-1-1a5.5 5.5 0 1 0-7.8 7.8l1 1L12 21l7.8-7.6 1-1a5.5 5.5 0 0 0 0-7.8Z"), + IMAGE("M21 15V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11 M21 15l-5-5L5 21 M14 14l2-2 5 5 M8.5 8.5h.01"), + INFO("M12 16v-4 M12 8h.01 M22 12a10 10 0 1 1-20 0 10 10 0 0 1 20 0Z"), + LAYERS("m12 2 9 5-9 5-9-5Z M3 12l9 5 9-5 M3 17l9 5 9-5"), + LAYOUT("M3 3h18v18H3Z M3 9h18 M9 21V9"), + LINK("M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71 M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"), + LIST("M8 6h13 M8 12h13 M8 18h13 M3 6h.01 M3 12h.01 M3 18h.01"), + LOADER_2("M21 12a9 9 0 1 1-6.219-8.56"), + LOG_OUT("M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4 M16 17l5-5-5-5 M21 12H9"), + MAXIMIZE("M8 3H5a2 2 0 0 0-2 2v3 M16 3h3a2 2 0 0 1 2 2v3 M21 16v3a2 2 0 0 1-2 2h-3 M8 21H5a2 2 0 0 1-2-2v-3"), + MESSAGE_SQUARE("M21 15a4 4 0 0 1-4 4H7l-4 4V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z"), + MINUS("M5 12h14"), + PALETTE("M12 22a10 10 0 1 1 10-10c0 2-1.5 3-3.5 3H17a2 2 0 0 0 0 4h.5c-1.6 1.9-3.6 3-5.5 3Z M6.5 11.5h.01 M9.5 7.5h.01 M14.5 7.5h.01 M17.5 11.5h.01"), + PACKAGE_PLUS("M16 16h6 M19 13v6 M21 8a2 2 0 0 0-1-1.73L12 2 4 6.27A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73L12 22l3-1.6 M3.3 7 12 12l8.7-5 M12 22V12"), + REFRESH_CW("M21 12a9 9 0 0 0-9-9 9.8 9.8 0 0 0-6.7 2.7L3 8 M3 3v5h5 M3 12a9 9 0 0 0 9 9 9.8 9.8 0 0 0 6.7-2.7L21 16 M16 16h5v5"), + RESTORE("M8 3h11a2 2 0 0 1 2 2v11 M3 8h11a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2Z"), + ROTATE_CCW("M3 12a9 9 0 1 0 3-6.7L3 8 M3 3v5h5"), + SAVE("M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2Z M17 21v-8H7v8 M7 3v5h8"), + SCALE("M16 16l3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z M2 16l3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z M7 21h10 M12 3v18 M3 7h2c2 0 5-1 7-4 2 3 5 4 7 4h2"), + SEARCH("M21 21l-4.35-4.35 M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16Z"), + SEND("m22 2-7 20-4-9-9-4 20-7Z M22 2 11 13"), + SHARE_2("M18 2a3 3 0 1 1 0 6a3 3 0 1 1 0-6 M6 9a3 3 0 1 1 0 6a3 3 0 1 1 0-6 M18 16a3 3 0 1 1 0 6a3 3 0 1 1 0-6 M8.59 13.51l6.83 3.98 M15.41 6.51l-6.82 3.98"), + SLIDERS("M21 4h-7 M10 4H3 M21 12h-9 M8 12H3 M21 20h-5 M12 20H3 M14 2v4 M8 10v4 M16 18v4"), + STAR("M12 2l3.1 6.3 6.9 1-5 4.9 1.2 6.8L12 17.8 5.8 21 7 14.2 2 9.3l6.9-1Z"), + TAG("M20.6 13.4 13.4 20.6a2 2 0 0 1-2.8 0L3 13V3h10l7.6 7.6a2 2 0 0 1 0 2.8Z M7.5 7.5h.01"), + TRASH("M3 6h18 M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2 M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6 M10 11v6 M14 11v6"), + USER("M20 21a8 8 0 0 0-16 0 M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"), + X("M18 6 6 18 M6 6l12 12"), + ZAP("M13 2 3 14h8l-1 8 10-12h-8Z"); + + private final String path; + + Glyph(String path) { + this.path = path; + } + } + + public enum BrandGlyph { + DISCORD(127.14, 96.36, new BrandPath[]{ + new BrandPath("M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.11,77.11,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.89,105.89,0,0,0,126.6,80.22c2.36-24.44-4.2-48.62-18.9-72.15ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z", "#5865F2") + }), + GITHUB(24, 24, new BrandPath[]{ + new BrandPath("M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z", "#ffffff") + }), + GITLAB(24, 24, new BrandPath[]{ + new BrandPath("M22.65 14.39L12 22.13L1.35 14.39L4.74 3.99C4.82 3.73 5.12 3.63 5.33 3.82L8.99 7.5L12 10.5L15.01 7.5L18.67 3.82C18.88 3.63 19.18 3.73 19.26 3.99L22.65 14.39Z", "#FC6D26") + }), + GOOGLE(32, 32, new BrandPath[]{ + new BrandPath("M23.75,16A7.7446,7.7446,0,0,1,8.7177,18.6259L4.2849,22.1721A13.244,13.244,0,0,0,29.25,16", "#00ac47"), + new BrandPath("M23.75,16a7.7387,7.7387,0,0,1-3.2516,6.2987l4.3824,3.5059A13.2042,13.2042,0,0,0,29.25,16", "#4285f4"), + new BrandPath("M8.25,16a7.698,7.698,0,0,1,.4677-2.6259L4.2849,9.8279a13.177,13.177,0,0,0,0,12.3442l4.4328-3.5462A7.698,7.698,0,0,1,8.25,16Z", "#ffba00"), + new BrandPath("M16,8.25a7.699,7.699,0,0,1,4.558,1.4958l4.06-3.7893A13.2152,13.2152,0,0,0,4.2849,9.8279l4.4328,3.5462A7.756,7.756,0,0,1,16,8.25Z", "#ea4435"), + new BrandPath("M29.25,15v1L27,19.5H16.5V14H28.25A1,1,0,0,1,29.25,15Z", "#4285f4") + }), + TWITTER(24, 24, new BrandPath[]{ + new BrandPath("M23.954 4.569c-.885.392-1.83.656-2.825.775a4.932 4.932 0 0 0 2.163-2.723 9.864 9.864 0 0 1-3.127 1.195 4.916 4.916 0 0 0-8.38 4.482A13.944 13.944 0 0 1 1.671 3.149a4.916 4.916 0 0 0 1.523 6.557 4.897 4.897 0 0 1-2.228-.616v.06a4.918 4.918 0 0 0 3.946 4.827 4.996 4.996 0 0 1-2.212.085 4.923 4.923 0 0 0 4.604 3.417A9.867 9.867 0 0 1 0 19.54a13.93 13.93 0 0 0 7.548 2.212c9.057 0 14.01-7.503 14.01-14.01 0-.213-.005-.425-.014-.636a10.012 10.012 0 0 0 2.46-2.548Z", "#ffffff") + }), + FACEBOOK(24, 24, new BrandPath[]{ + new BrandPath("M22.675 0H1.325C.593 0 0 .593 0 1.326v21.348C0 23.407.593 24 1.325 24h11.495v-9.294H9.692v-3.622h3.128V8.413c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.795.143v3.24l-1.918.001c-1.504 0-1.795.715-1.795 1.763v2.312h3.587l-.467 3.622h-3.12V24h6.116C23.407 24 24 23.407 24 22.674V1.326C24 .593 23.407 0 22.675 0Z", "#ffffff") + }); + + private final double viewBoxWidth; + private final double viewBoxHeight; + private final BrandPath[] paths; + + BrandGlyph(double viewBoxWidth, double viewBoxHeight, BrandPath[] paths) { + this.viewBoxWidth = viewBoxWidth; + this.viewBoxHeight = viewBoxHeight; + this.paths = paths; + } + } + + private LauncherIcons() { + } + + public static Node icon(Glyph glyph, double size) { + SVGPath path = new SVGPath(); + path.setContent(glyph.path); + path.setStrokeLineCap(StrokeLineCap.ROUND); + path.setStrokeLineJoin(StrokeLineJoin.ROUND); + path.getStyleClass().add("svg-icon"); + path.setScaleX(size / 24.0); + path.setScaleY(size / 24.0); + + StackPane pane = new StackPane(path); + pane.getStyleClass().add("icon-wrap"); + pane.setAlignment(Pos.CENTER); + pane.setMinSize(size, size); + pane.setPrefSize(size, size); + pane.setMaxSize(size, size); + return pane; + } + + public static Node brandIcon(BrandGlyph glyph, double size) { + Group group = new Group(); + for (BrandPath brandPath : glyph.paths) { + SVGPath path = new SVGPath(); + path.setContent(brandPath.path); + path.setFill(Color.web(brandPath.fill)); + group.getChildren().add(path); + } + double scale = size / Math.max(glyph.viewBoxWidth, glyph.viewBoxHeight); + group.setScaleX(scale); + group.setScaleY(scale); + + StackPane pane = new StackPane(group); + pane.getStyleClass().add("brand-icon-wrap"); + pane.setAlignment(Pos.CENTER); + pane.setMinSize(size, size); + pane.setPrefSize(size, size); + pane.setMaxSize(size, size); + return pane; + } + + private record BrandPath(String path, String fill) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherLayout.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherLayout.java new file mode 100644 index 00000000..b29a2fbc --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherLayout.java @@ -0,0 +1,36 @@ +package net.modtale.launcher.ui.common; + +import javafx.geometry.Insets; + +public final class LauncherLayout { + + public static final double WORKSPACE_HORIZONTAL_INSET = 112; + public static final double NAVBAR_RIGHT_EXTRA_INSET = 16; + public static final Insets WORKSPACE_INSETS = new Insets( + 18, + WORKSPACE_HORIZONTAL_INSET, + 28, + WORKSPACE_HORIZONTAL_INSET + ); + public static final Insets LAUNCHER_WORKSPACE_INSETS = new Insets(18, 40, 28, 40); + public static final Insets NAVBAR_INSETS = navbarInsets(0, 0); + + private LauncherLayout() { + } + + public static double navbarLeftInset() { + return WORKSPACE_HORIZONTAL_INSET; + } + + public static double navbarRightInset() { + return WORKSPACE_HORIZONTAL_INSET + NAVBAR_RIGHT_EXTRA_INSET; + } + + public static Insets navbarInsets(double top, double bottom) { + return new Insets(top, navbarRightInset(), bottom, navbarLeftInset()); + } + + public static Insets launcherPageInsets(double top, double bottom) { + return navbarInsets(top, bottom); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherOverlaySupport.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherOverlaySupport.java new file mode 100644 index 00000000..3d70d0b4 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherOverlaySupport.java @@ -0,0 +1,29 @@ +package net.modtale.launcher.ui.common; + +import javafx.event.EventTarget; +import javafx.scene.Node; + +public final class LauncherOverlaySupport { + + private LauncherOverlaySupport() { + } + + public static boolean eventTargetInside(EventTarget target, Node root) { + if (!(target instanceof Node node) || root == null) { + return false; + } + for (Node current = node; current != null; current = current.getParent()) { + if (current == root) { + return true; + } + } + return false; + } + + public static double clamp(double value, double min, double max) { + if (max < min) { + return min; + } + return Math.max(min, Math.min(value, max)); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherScrollSupport.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherScrollSupport.java new file mode 100644 index 00000000..cf93a2fb --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherScrollSupport.java @@ -0,0 +1,330 @@ +package net.modtale.launcher.ui.common; + +import java.util.function.Supplier; +import javafx.animation.AnimationTimer; +import javafx.animation.PauseTransition; +import javafx.css.PseudoClass; +import javafx.scene.Node; +import javafx.scene.control.ScrollPane; +import javafx.scene.input.ScrollEvent; +import javafx.util.Duration; +import net.modtale.launcher.LauncherPerformanceProbe; +import net.modtale.launcher.ui.browse.card.ProjectCardFactory; + +public final class LauncherScrollSupport { + + private static final String DROPDOWN_POPOVER_STYLE_CLASS = "filter-popover"; + private static final double LINE_PIXELS = 48; + private static final double WHEEL_VELOCITY_GAIN = 8.6; + private static final double PIXEL_VELOCITY_GAIN = 0.42; + private static final double INERTIA_VELOCITY_GAIN = 0.12; + private static final double VELOCITY_CARRY = 0.28; + private static final double REVERSE_VELOCITY_CARRY = 0.08; + private static final double FRICTION_PER_SECOND = 0.035; + private static final double FRAME_SECONDS_CAP = 0.032; + private static final double FIRST_INPUT_SECONDS = 1.0 / 60.0; + private static final double INPUT_SECONDS_MIN = 1.0 / 180.0; + private static final double INPUT_SECONDS_MAX = 1.0 / 24.0; + private static final double MAX_VELOCITY = 8200; + private static final double STOP_VELOCITY = 10; + private static final double SMOOTH_PIXELS_EPSILON = 0.35; + private static final double WHEEL_SMOOTHING_SECONDS = 0.052; + private static final double PENDING_PIXELS_CAP = 2100; + private static final PseudoClass SCROLLING = PseudoClass.getPseudoClass("scrolling"); + + private final Supplier rootSupplier; + private final PauseTransition interactionCooldown = new PauseTransition(Duration.millis(120)); + + public LauncherScrollSupport(Supplier rootSupplier) { + this.rootSupplier = rootSupplier; + interactionCooldown.setOnFinished(event -> clearScrollInteraction()); + } + + public void configure(ScrollPane scrollPane, boolean horizontal) { + new MomentumScrollController(scrollPane, horizontal).install(); + } + + private final class MomentumScrollController { + + private final ScrollPane scrollPane; + private final boolean horizontal; + private double directPixels; + private double smoothPixels; + private double velocity; + private long previousInput; + private long previousFrame; + + private final AnimationTimer timer = new AnimationTimer() { + @Override + public void handle(long now) { + animate(now); + } + }; + + private MomentumScrollController(ScrollPane scrollPane, boolean horizontal) { + this.scrollPane = scrollPane; + this.horizontal = horizontal; + } + + private void install() { + scrollPane.addEventFilter(ScrollEvent.SCROLL, this::handleScroll); + } + + private void handleScroll(ScrollEvent event) { + long operationStart = LauncherPerformanceProbe.operationStartNanos(); + try { + if (event.isControlDown() || scrollPane.getContent() == null) { + return; + } + if (eventTargetInsideStyleClass(event, DROPDOWN_POPOVER_STYLE_CLASS) + || eventTargetInsideNestedScrollPane(event, scrollPane)) { + stopMomentum(); + return; + } + double eventPixels = scrollPixels(event, horizontal, viewportSize(scrollPane, horizontal)); + if (Math.abs(eventPixels) < 0.5) { + return; + } + double movementPixels = -eventPixels; + if (!canScrollByPixels(scrollPane, horizontal, movementPixels)) { + stopMomentum(); + return; + } + activateScrollInteraction(); + ScrollInputKind inputKind = inputKind(event, horizontal); + if (inputKind == ScrollInputKind.PIXEL) { + directPixels = clamp(directPixels + movementPixels, -PENDING_PIXELS_CAP, PENDING_PIXELS_CAP); + } else { + smoothPixels = clamp(smoothPixels + movementPixels, -PENDING_PIXELS_CAP, PENDING_PIXELS_CAP); + } + long inputNow = System.nanoTime(); + double inputVelocity = inputVelocity(event, inputKind, movementPixels, inputNow); + previousInput = inputNow; + velocity = nextVelocity(velocity, inputVelocity); + timer.start(); + event.consume(); + } finally { + LauncherPerformanceProbe.recordOperation("scroll.input", operationStart); + } + } + + private double inputVelocity(ScrollEvent event, ScrollInputKind inputKind, double movementPixels, long inputNow) { + if (inputKind == ScrollInputKind.PIXEL) { + double seconds = previousInput == 0 + ? FIRST_INPUT_SECONDS + : clamp((inputNow - previousInput) / 1_000_000_000.0, INPUT_SECONDS_MIN, INPUT_SECONDS_MAX); + double gain = event.isInertia() ? INERTIA_VELOCITY_GAIN : PIXEL_VELOCITY_GAIN; + return movementPixels / seconds * gain; + } + return movementPixels * WHEEL_VELOCITY_GAIN; + } + + private void animate(long now) { + long operationStart = LauncherPerformanceProbe.operationStartNanos(); + try { + if (previousFrame == 0) { + previousFrame = now - Math.round(FIRST_INPUT_SECONDS * 1_000_000_000.0); + } + double deltaSeconds = Math.min(FRAME_SECONDS_CAP, (now - previousFrame) / 1_000_000_000.0); + previousFrame = now; + + double movementPixels = directPixels + drainSmoothPixels(deltaSeconds); + directPixels = 0; + boolean hasPendingPixels = Math.abs(movementPixels) >= 0.25 || Math.abs(smoothPixels) >= SMOOTH_PIXELS_EPSILON; + if (!hasPendingPixels && Math.abs(velocity) >= STOP_VELOCITY) { + movementPixels += velocity * deltaSeconds; + } + if (!hasPendingPixels && Math.abs(movementPixels) < 0.25 && Math.abs(velocity) < STOP_VELOCITY) { + stopMomentum(); + return; + } + if (Math.abs(movementPixels) >= 0.25 && !scrollByPixels(scrollPane, horizontal, movementPixels)) { + stopMomentum(); + return; + } + velocity *= Math.pow(FRICTION_PER_SECOND, deltaSeconds); + } finally { + LauncherPerformanceProbe.recordOperation("scroll.animate", operationStart); + } + } + + private double drainSmoothPixels(double deltaSeconds) { + if (Math.abs(smoothPixels) < SMOOTH_PIXELS_EPSILON) { + double pixels = smoothPixels; + smoothPixels = 0; + return pixels; + } + double pixels = smoothPixels * smoothingFactor(deltaSeconds); + smoothPixels -= pixels; + return pixels; + } + + private void stopMomentum() { + directPixels = 0; + smoothPixels = 0; + velocity = 0; + previousInput = 0; + previousFrame = 0; + timer.stop(); + scheduleScrollInteractionIdle(); + } + } + + private enum ScrollInputKind { + PIXEL, + WHEEL + } + + private void activateScrollInteraction() { + interactionCooldown.stop(); + Node root = rootSupplier.get(); + if (root != null + && !Boolean.TRUE.equals(root.getProperties().get(ProjectCardFactory.SCROLL_ACTIVE_PROPERTY))) { + root.getProperties().put(ProjectCardFactory.SCROLL_ACTIVE_PROPERTY, Boolean.TRUE); + root.pseudoClassStateChanged(SCROLLING, true); + } + } + + private void scheduleScrollInteractionIdle() { + interactionCooldown.playFromStart(); + } + + private void clearScrollInteraction() { + Node root = rootSupplier.get(); + if (root != null + && Boolean.TRUE.equals(root.getProperties().get(ProjectCardFactory.SCROLL_ACTIVE_PROPERTY))) { + root.getProperties().remove(ProjectCardFactory.SCROLL_ACTIVE_PROPERTY); + root.pseudoClassStateChanged(SCROLLING, false); + } + } + + private static boolean canScrollByPixels(ScrollPane scrollPane, boolean horizontal, double pixels) { + double scrollable = scrollablePixels(scrollPane, horizontal); + if (scrollable <= 1) { + return false; + } + double previous = scrollValue(scrollPane, horizontal); + double next = clamp(previous + pixels / scrollable, scrollMin(scrollPane, horizontal), scrollMax(scrollPane, horizontal)); + return Math.abs(next - previous) >= 0.0001; + } + + private static boolean scrollByPixels(ScrollPane scrollPane, boolean horizontal, double pixels) { + double scrollable = scrollablePixels(scrollPane, horizontal); + if (scrollable <= 1) { + return false; + } + double previous = scrollValue(scrollPane, horizontal); + double next = clamp(previous + pixels / scrollable, scrollMin(scrollPane, horizontal), scrollMax(scrollPane, horizontal)); + if (Math.abs(next - previous) < 0.0001) { + return false; + } + setScrollValue(scrollPane, horizontal, next); + return true; + } + + private static boolean eventTargetInsideStyleClass(ScrollEvent event, String styleClass) { + if (!(event.getTarget() instanceof Node node)) { + return false; + } + for (Node current = node; current != null; current = current.getParent()) { + if (current.getStyleClass().contains(styleClass)) { + return true; + } + } + return false; + } + + private static boolean eventTargetInsideNestedScrollPane(ScrollEvent event, ScrollPane outerScrollPane) { + if (!(event.getTarget() instanceof Node node)) { + return false; + } + for (Node current = node; current != null && current != outerScrollPane; current = current.getParent()) { + if (current instanceof ScrollPane nestedScrollPane + && nestedScrollPane != outerScrollPane + && nestedScrollPane.getContent() != null + && nestedScrollPaneCanHandle(nestedScrollPane, event)) { + return true; + } + } + return false; + } + + private static boolean nestedScrollPaneCanHandle(ScrollPane scrollPane, ScrollEvent event) { + double verticalPixels = scrollPixels(event, false, viewportSize(scrollPane, false)); + if (Math.abs(verticalPixels) >= 0.5 && canScrollByPixels(scrollPane, false, -verticalPixels)) { + return true; + } + double horizontalPixels = scrollPixels(event, true, viewportSize(scrollPane, true)); + return Math.abs(horizontalPixels) >= 0.5 && canScrollByPixels(scrollPane, true, -horizontalPixels); + } + + private static double scrollablePixels(ScrollPane scrollPane, boolean horizontal) { + return horizontal + ? scrollPane.getContent().getLayoutBounds().getWidth() - scrollPane.getViewportBounds().getWidth() + : scrollPane.getContent().getLayoutBounds().getHeight() - scrollPane.getViewportBounds().getHeight(); + } + + private static double viewportSize(ScrollPane scrollPane, boolean horizontal) { + return horizontal ? scrollPane.getViewportBounds().getWidth() : scrollPane.getViewportBounds().getHeight(); + } + + private static double scrollPixels(ScrollEvent event, boolean horizontal, double viewportSize) { + if (horizontal && Math.abs(event.getDeltaX()) > 0.5) { + return event.getDeltaX(); + } + return switch (event.getTextDeltaYUnits()) { + case LINES -> event.getTextDeltaY() * LINE_PIXELS; + case PAGES -> event.getTextDeltaY() * Math.max(120, viewportSize * 0.86); + case NONE -> event.getDeltaY(); + }; + } + + private static ScrollInputKind inputKind(ScrollEvent event, boolean horizontal) { + if (event.isInertia() || (horizontal && Math.abs(event.getDeltaX()) > 0.5)) { + return ScrollInputKind.PIXEL; + } + return event.getTextDeltaYUnits() == ScrollEvent.VerticalTextScrollUnits.NONE + ? ScrollInputKind.PIXEL + : ScrollInputKind.WHEEL; + } + + private static double nextVelocity(double currentVelocity, double inputVelocity) { + double carry = Math.signum(currentVelocity) != 0 + && Math.signum(inputVelocity) != 0 + && Math.signum(currentVelocity) != Math.signum(inputVelocity) + ? REVERSE_VELOCITY_CARRY + : VELOCITY_CARRY; + return clamp(currentVelocity * carry + inputVelocity, -MAX_VELOCITY, MAX_VELOCITY); + } + + public static double smoothingFactor(double deltaSeconds) { + if (deltaSeconds <= 0) { + return 0; + } + return 1 - Math.exp(-deltaSeconds / WHEEL_SMOOTHING_SECONDS); + } + + private static double scrollValue(ScrollPane scrollPane, boolean horizontal) { + return horizontal ? scrollPane.getHvalue() : scrollPane.getVvalue(); + } + + private static void setScrollValue(ScrollPane scrollPane, boolean horizontal, double value) { + if (horizontal) { + scrollPane.setHvalue(value); + } else { + scrollPane.setVvalue(value); + } + } + + private static double scrollMin(ScrollPane scrollPane, boolean horizontal) { + return horizontal ? scrollPane.getHmin() : scrollPane.getVmin(); + } + + private static double scrollMax(ScrollPane scrollPane, boolean horizontal) { + return horizontal ? scrollPane.getHmax() : scrollPane.getVmax(); + } + + private static double clamp(double value, double min, double max) { + return Math.max(min, Math.min(max, value)); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherUi.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherUi.java new file mode 100644 index 00000000..d32c8444 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherUi.java @@ -0,0 +1,180 @@ +package net.modtale.launcher.ui.common; + +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.model.project.ProjectClassification; + +public final class LauncherUi { + + private LauncherUi() { + } + + public static VBox panel(String title, String subtitle) { + VBox panel = new VBox(14); + panel.getStyleClass().add("glass-panel"); + Label heading = new Label(title); + heading.getStyleClass().add("panel-title"); + Label sub = new Label(subtitle); + sub.getStyleClass().add("panel-subtitle"); + panel.getChildren().addAll(heading, sub); + return panel; + } + + public static GridPane formGrid() { + GridPane grid = new GridPane(); + grid.getStyleClass().add("form-grid"); + grid.setHgap(14); + grid.setVgap(14); + ColumnConstraints labelColumn = new ColumnConstraints(); + labelColumn.setMinWidth(98); + labelColumn.setPrefWidth(118); + ColumnConstraints fieldColumn = new ColumnConstraints(); + fieldColumn.setHgrow(Priority.ALWAYS); + fieldColumn.setFillWidth(true); + grid.getColumnConstraints().addAll(labelColumn, fieldColumn); + return grid; + } + + public static void addField(GridPane grid, int row, String label, Node field) { + Label labelNode = new Label(label); + labelNode.getStyleClass().add("field-label"); + grid.add(labelNode, 0, row); + if (field instanceof Region region) { + region.setMaxWidth(Double.MAX_VALUE); + } + grid.add(field, 1, row); + GridPane.setHgrow(field, Priority.ALWAYS); + GridPane.setFillWidth(field, true); + } + + public static void styleInput(TextField... fields) { + for (TextField field : fields) { + field.getStyleClass().add("input"); + } + } + + public static void styleCombo(ComboBox... combos) { + for (ComboBox combo : combos) { + combo.getStyleClass().add("select"); + combo.setMaxWidth(Double.MAX_VALUE); + } + } + + public static Button primaryButton(String label) { + Button button = new Button(label); + button.getStyleClass().addAll("btn", "primary"); + return button; + } + + public static Button secondaryButton(String label) { + Button button = new Button(label); + button.getStyleClass().addAll("btn", "secondary"); + return button; + } + + public static Button dangerButton(String label) { + Button button = new Button(label); + button.getStyleClass().addAll("btn", "danger"); + return button; + } + + public static Node statusDot() { + Region dot = new Region(); + dot.getStyleClass().add("status-dot"); + return dot; + } + + public static StackPane miniIcon(String text) { + Label label = new Label(text); + StackPane pane = new StackPane(label); + pane.getStyleClass().add("row-icon"); + return pane; + } + + public static Node toggleCard(CheckBox checkBox) { + StackPane card = new StackPane(checkBox); + card.getStyleClass().add("toggle-card"); + HBox.setHgrow(card, Priority.ALWAYS); + return card; + } + + public static Node metricCard(String label, Label value) { + VBox card = new VBox(6); + card.getStyleClass().add("metric-card"); + Label title = new Label(label); + title.getStyleClass().add("metric-label"); + value.getStyleClass().add("metric-value"); + card.getChildren().addAll(title, value); + HBox.setHgrow(card, Priority.ALWAYS); + return card; + } + + public static VBox emptyState(String title, String subtitle) { + VBox box = new VBox(8); + box.getStyleClass().add("empty-state"); + box.setAlignment(javafx.geometry.Pos.CENTER); + Label heading = new Label(title); + heading.getStyleClass().add("empty-title"); + Label sub = new Label(subtitle); + sub.getStyleClass().add("empty-subtitle"); + box.getChildren().addAll(heading, sub); + return box; + } + + public static HBox rowCard(String title, String subtitle) { + HBox row = new HBox(12); + row.getStyleClass().add("row-card"); + row.setAlignment(javafx.geometry.Pos.CENTER_LEFT); + StackPane icon = miniIcon("M"); + VBox copy = new VBox(4); + Label titleLabel = new Label(value(title, "Untitled Project")); + titleLabel.getStyleClass().add("row-title"); + Label subtitleLabel = new Label(subtitle); + subtitleLabel.getStyleClass().add("row-subtitle"); + copy.getChildren().addAll(titleLabel, subtitleLabel); + HBox.setHgrow(copy, Priority.ALWAYS); + row.getChildren().addAll(icon, copy); + return row; + } + + public static void setVisibleManaged(Node node, boolean visible) { + if (node == null) { + return; + } + node.setVisible(visible); + node.setManaged(visible); + } + + public static String readableField(String fieldName) { + return switch (fieldName) { + case "hytaleModsPath" -> "Hytale mods folder"; + case "hytaleGamePath" -> "Hytale game folder"; + case "hytaleUserDataPath" -> "Hytale user data folder"; + case "hytaleJavaPath" -> "Java executable"; + default -> "path"; + }; + } + + public static String value(String value, String fallback) { + return value == null || value.isBlank() ? fallback : value; + } + + public static String classificationLabel(String classification) { + return ProjectClassification.labelFor(classification); + } + + public static void pseudo(Node node, String pseudoClass, boolean active) { + node.pseudoClassStateChanged(javafx.css.PseudoClass.getPseudoClass(pseudoClass), active); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherView.java b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherView.java new file mode 100644 index 00000000..24104ae9 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/LauncherView.java @@ -0,0 +1,37 @@ +package net.modtale.launcher.ui.common; + +import java.util.Arrays; + +public enum LauncherView { + DISCOVER("discover"), + PLAY("play"), + LIBRARY("library"), + UPDATES("updates"), + NOTIFICATIONS("notifications"), + SETTINGS("settings"), + PROJECT("project"); + + private final String id; + + LauncherView(String id) { + this.id = id; + } + + public String id() { + return id; + } + + public static LauncherView defaultView() { + return PLAY; + } + + public static LauncherView fromId(String id) { + if (id == null || id.isBlank()) { + return defaultView(); + } + return Arrays.stream(values()) + .filter(view -> view.id.equalsIgnoreCase(id.trim())) + .findFirst() + .orElse(defaultView()); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/common/StatusModal.java b/launcher/src/main/java/net/modtale/launcher/ui/common/StatusModal.java new file mode 100644 index 00000000..4fb53375 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/common/StatusModal.java @@ -0,0 +1,475 @@ +package net.modtale.launcher.ui.common; + +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.function.Supplier; +import javafx.animation.AnimationTimer; +import javafx.application.Platform; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.effect.Effect; +import javafx.scene.effect.GaussianBlur; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; + +public final class StatusModal { + + public enum Type { + SUCCESS("success", LauncherIcons.Glyph.CHECK), + ERROR("error", LauncherIcons.Glyph.ALERT_TRIANGLE), + WARNING("warning", LauncherIcons.Glyph.TRASH), + INFO("info", LauncherIcons.Glyph.INFO); + + private final String styleSuffix; + private final LauncherIcons.Glyph glyph; + + Type(String styleSuffix, LauncherIcons.Glyph glyph) { + this.styleSuffix = styleSuffix; + this.glyph = glyph; + } + } + + public enum Result { + PRIMARY, + SECONDARY, + CLOSED + } + + public static Builder builder(Supplier host) { + return new Builder(host); + } + + private static final double MODAL_WIDTH = 448; + private static final double BODY_TEXT_WIDTH = 400; + + private final Supplier host; + private final Type type; + private final String title; + private final String message; + private final String actionLabel; + private final LauncherIcons.Glyph actionIcon; + private final String secondaryLabel; + private final Node content; + private final Map backdropEffects = new IdentityHashMap<>(); + + private StackPane overlay; + private StatusConfetti confetti; + private boolean completed; + + private StatusModal(Builder builder) { + this.host = builder.host == null ? () -> null : builder.host; + this.type = builder.type == null ? Type.INFO : builder.type; + this.title = value(builder.title); + this.message = value(builder.message); + this.actionLabel = value(builder.actionLabel).isBlank() ? "Close" : value(builder.actionLabel); + this.actionIcon = builder.actionIcon; + this.secondaryLabel = value(builder.secondaryLabel); + this.content = builder.content; + } + + public Result showAndWait() { + if (!Platform.isFxApplicationThread()) { + throw new IllegalStateException("StatusModal must be shown on the JavaFX application thread."); + } + if (!show()) { + return Result.CLOSED; + } + Object result = Platform.enterNestedEventLoop(this); + return result instanceof Result modalResult ? modalResult : Result.CLOSED; + } + + private boolean show() { + StackPane hostPane = host.get(); + if (hostPane == null) { + return false; + } + overlay = overlayShell(); + blurBackdrop(hostPane); + if (type == Type.SUCCESS) { + confetti = new StatusConfetti(); + overlay.getChildren().setAll(confetti.canvas, card()); + } else { + overlay.getChildren().setAll(card()); + } + hostPane.getChildren().add(overlay); + if (confetti != null) { + confetti.start(); + } + Platform.runLater(overlay::requestFocus); + return true; + } + + private StackPane overlayShell() { + StackPane shell = new StackPane(); + shell.getStyleClass().add("status-modal-overlay"); + shell.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + shell.setFocusTraversable(true); + shell.addEventHandler(KeyEvent.KEY_PRESSED, event -> { + if (event.getCode() == KeyCode.ESCAPE) { + complete(Result.CLOSED); + event.consume(); + } + }); + shell.setOnMouseClicked(event -> { + if (event.getTarget() == shell) { + complete(Result.CLOSED); + } + }); + return shell; + } + + private StackPane card() { + StackPane card = new StackPane(); + card.getStyleClass().addAll("status-modal", "status-modal-" + type.styleSuffix); + card.setMaxWidth(MODAL_WIDTH); + card.setMaxHeight(Region.USE_PREF_SIZE); + card.setPrefWidth(MODAL_WIDTH); + card.setOnMouseClicked(event -> event.consume()); + + VBox layout = new VBox(0); + layout.getChildren().addAll(body(), footer()); + + Button close = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.X, 20)); + close.getStyleClass().add("status-modal-close"); + close.setOnAction(event -> complete(Result.CLOSED)); + StackPane.setAlignment(close, Pos.TOP_RIGHT); + StackPane.setMargin(close, new Insets(16, 16, 0, 0)); + + card.getChildren().addAll(layout, close); + return card; + } + + private VBox body() { + VBox body = new VBox(0); + body.getStyleClass().add("status-modal-body"); + body.setAlignment(Pos.CENTER); + + StackPane icon = new StackPane(LauncherIcons.icon(type.glyph, 32)); + icon.getStyleClass().add("status-modal-icon"); + + Label titleLabel = new Label(title); + titleLabel.getStyleClass().add("status-modal-title"); + titleLabel.setWrapText(true); + titleLabel.setAlignment(Pos.CENTER); + titleLabel.setMaxWidth(BODY_TEXT_WIDTH); + + Label messageLabel = new Label(message); + messageLabel.getStyleClass().add("status-modal-message"); + messageLabel.setWrapText(true); + messageLabel.setAlignment(Pos.CENTER); + messageLabel.setMaxWidth(BODY_TEXT_WIDTH); + + body.getChildren().addAll(icon, titleLabel, messageLabel); + VBox.setMargin(icon, new Insets(0, 0, 16, 0)); + VBox.setMargin(titleLabel, new Insets(0, 0, 8, 0)); + if (content != null) { + content.getStyleClass().add("status-modal-custom-content"); + if (content instanceof Region region) { + region.setMaxWidth(BODY_TEXT_WIDTH); + } + if (content instanceof VBox box) { + box.setAlignment(Pos.CENTER); + } else if (content instanceof HBox box) { + box.setAlignment(Pos.CENTER); + } else if (content instanceof StackPane pane) { + pane.setAlignment(Pos.CENTER); + } + VBox.setMargin(content, new Insets(16, 0, 0, 0)); + body.getChildren().add(content); + } + return body; + } + + private HBox footer() { + HBox footer = new HBox(12); + footer.getStyleClass().add("status-modal-footer"); + footer.setAlignment(Pos.CENTER); + + if (showsSecondaryAction()) { + Button secondary = new Button(secondaryLabel.isBlank() ? "Cancel" : secondaryLabel); + secondary.getStyleClass().add("status-modal-secondary"); + secondary.setOnAction(event -> complete(Result.SECONDARY)); + footer.getChildren().add(secondary); + } + + Button primary = new Button(actionLabel); + primary.getStyleClass().add("status-modal-primary"); + primary.setOnAction(event -> complete(Result.PRIMARY)); + if (actionIcon != null || type == Type.SUCCESS) { + primary.setGraphic(LauncherIcons.icon(actionIcon == null ? LauncherIcons.Glyph.ARROW_RIGHT : actionIcon, 20)); + } + footer.getChildren().add(primary); + return footer; + } + + private boolean showsSecondaryAction() { + return !secondaryLabel.isBlank() || type == Type.WARNING || type == Type.INFO; + } + + private void complete(Result result) { + if (completed) { + return; + } + completed = true; + hide(); + Platform.exitNestedEventLoop(this, result); + } + + private void hide() { + if (overlay == null) { + return; + } + if (confetti != null) { + confetti.stop(); + confetti = null; + } + Parent parent = overlay.getParent(); + if (parent instanceof StackPane stack) { + stack.getChildren().remove(overlay); + } + overlay = null; + restoreBackdrop(); + } + + private void blurBackdrop(StackPane hostPane) { + restoreBackdrop(); + for (Node child : hostPane.getChildren()) { + backdropEffects.put(child, child.getEffect()); + child.setEffect(new GaussianBlur(6)); + } + } + + private void restoreBackdrop() { + backdropEffects.forEach(Node::setEffect); + backdropEffects.clear(); + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } + + public static final class Builder { + private final Supplier host; + private Type type = Type.INFO; + private String title = ""; + private String message = ""; + private String actionLabel = ""; + private LauncherIcons.Glyph actionIcon; + private String secondaryLabel = ""; + private Node content; + + private Builder(Supplier host) { + this.host = host; + } + + public Builder type(Type type) { + this.type = type; + return this; + } + + public Builder title(String title) { + this.title = title; + return this; + } + + public Builder message(String message) { + this.message = message; + return this; + } + + public Builder actionLabel(String actionLabel) { + this.actionLabel = actionLabel; + return this; + } + + public Builder actionIcon(LauncherIcons.Glyph actionIcon) { + this.actionIcon = actionIcon; + return this; + } + + public Builder secondaryLabel(String secondaryLabel) { + this.secondaryLabel = secondaryLabel; + return this; + } + + public Builder content(Node content) { + this.content = content; + return this; + } + + public Result showAndWait() { + return new StatusModal(this).showAndWait(); + } + } + + private static final class StatusConfetti { + private static final int PARTICLE_COUNT = 400; + private static final String[] COLORS = { + "#3b82f6", "#ef4444", "#10b981", "#f59e0b", + "#8b5cf6", "#ec4899", "#06b6d4", "#ffffff" + }; + + private final Canvas canvas = new Canvas(); + private final Random random = new Random(); + private final List particles = new ArrayList<>(PARTICLE_COUNT); + private final AnimationTimer timer = new AnimationTimer() { + @Override + public void handle(long now) { + draw(); + } + }; + + private StatusConfetti() { + canvas.getStyleClass().add("status-modal-confetti"); + canvas.setMouseTransparent(true); + canvas.parentProperty().addListener((observable, oldParent, newParent) -> { + canvas.widthProperty().unbind(); + canvas.heightProperty().unbind(); + if (newParent instanceof Region region) { + canvas.widthProperty().bind(region.widthProperty()); + canvas.heightProperty().bind(region.heightProperty()); + } else { + canvas.setWidth(0); + canvas.setHeight(0); + } + }); + } + + private void start() { + timer.start(); + } + + private void stop() { + timer.stop(); + } + + private void draw() { + double width = canvas.getWidth(); + double height = canvas.getHeight(); + if (width <= 0 || height <= 0) { + return; + } + if (particles.isEmpty()) { + seed(width, height); + } + GraphicsContext graphics = canvas.getGraphicsContext2D(); + graphics.clearRect(0, 0, width, height); + int activeCount = 0; + for (Particle particle : particles) { + if (!particle.active) { + continue; + } + particle.x += particle.vx; + particle.y += particle.vy; + particle.vy += particle.gravity; + particle.vx *= particle.drag; + particle.vy *= particle.drag; + particle.tilt += particle.tiltAngleIncrement; + particle.angle += particle.rotationSpeed; + if (particle.y > height + 100) { + particle.active = false; + continue; + } + activeCount++; + graphics.save(); + graphics.translate(particle.x, particle.y); + graphics.rotate(Math.toDegrees(particle.angle)); + graphics.scale(1, Math.cos(particle.tilt)); + graphics.setFill(particle.color); + graphics.fillRect(-particle.w / 2, -particle.h / 2, particle.w, particle.h); + graphics.restore(); + } + if (activeCount == 0) { + stop(); + } + } + + private void seed(double width, double height) { + double centerX = width / 2; + double centerY = height / 2; + for (int i = 0; i < PARTICLE_COUNT; i++) { + double angle = random.nextDouble() * Math.PI * 2; + double velocity = random.nextDouble() * 35 + 10; + particles.add(new Particle( + centerX, + centerY, + Math.cos(angle) * velocity, + Math.sin(angle) * velocity, + Color.web(COLORS[random.nextInt(COLORS.length)]), + random.nextDouble() * 12 + 4, + random.nextDouble() * 6 + 4, + 0.6, + 0.92, + random.nextDouble() * Math.PI * 2, + (random.nextDouble() - 0.5) * 0.3, + random.nextDouble() * 10, + random.nextDouble() * 0.1 + 0.05, + true + )); + } + } + } + + private static final class Particle { + private double x; + private double y; + private double vx; + private double vy; + private final Color color; + private final double w; + private final double h; + private final double gravity; + private final double drag; + private double angle; + private final double rotationSpeed; + private double tilt; + private final double tiltAngleIncrement; + private boolean active; + + private Particle( + double x, + double y, + double vx, + double vy, + Color color, + double w, + double h, + double gravity, + double drag, + double angle, + double rotationSpeed, + double tilt, + double tiltAngleIncrement, + boolean active + ) { + this.x = x; + this.y = y; + this.vx = vx; + this.vy = vy; + this.color = color; + this.w = w; + this.h = h; + this.gravity = gravity; + this.drag = drag; + this.angle = angle; + this.rotationSpeed = rotationSpeed; + this.tilt = tilt; + this.tiltAngleIncrement = tiltAngleIncrement; + this.active = active; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedback.java b/launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedback.java new file mode 100644 index 00000000..cd601d53 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedback.java @@ -0,0 +1,164 @@ +package net.modtale.launcher.ui.feedback; + +import java.time.format.DateTimeFormatter; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.ui.common.LauncherIcons; + +public final class LauncherFeedback { + + private static final DateTimeFormatter LOG_TIME = DateTimeFormatter.ofPattern("HH:mm"); + private static final String TOAST_SUCCESS = "toast-success"; + private static final String TOAST_ERROR = "toast-error"; + private static final String TOAST_NEUTRAL = "toast-neutral"; + + private final Executor executor; + private final Label statusText; + private final VBox logList; + private final StackPane toast; + private final Label toastTitle; + private final Label toastMessage; + private final Supplier idleStatus; + private StackPane toastIcon; + + public LauncherFeedback( + Executor executor, + Label statusText, + VBox logList, + StackPane toast, + Label toastTitle, + Label toastMessage, + Supplier idleStatus + ) { + this.executor = executor; + this.statusText = statusText; + this.logList = logList; + this.toast = toast; + this.toastTitle = toastTitle; + this.toastMessage = toastMessage; + this.idleStatus = idleStatus; + } + + public void runAsync(String status, Supplier work, Consumer onSuccess) { + runAsync(status, work, onSuccess, ignored -> { + }); + } + + public void runAsync(String status, Supplier work, Consumer onSuccess, Consumer onError) { + Platform.runLater(() -> statusText.setText(status)); + log(status); + CompletableFuture.supplyAsync(work, executor) + .whenComplete((value, error) -> Platform.runLater(() -> { + statusText.setText(idleStatus.get()); + if (error != null) { + Throwable cause = error.getCause() == null ? error : error.getCause(); + log("Error: " + cause.getMessage()); + showToast("Action failed", cause.getMessage()); + onError.accept(cause); + return; + } + onSuccess.accept(value); + })); + } + + public void log(String message) { + Platform.runLater(() -> { + HBox line = new HBox(10); + line.getStyleClass().add("log-line"); + Label time = new Label(LOG_TIME.format(java.time.LocalTime.now())); + time.getStyleClass().add("log-time"); + Label text = new Label(message); + text.getStyleClass().add("log-text"); + line.getChildren().addAll(time, text); + logList.getChildren().add(line); + if (logList.getChildren().size() > 80) { + logList.getChildren().remove(0); + } + }); + } + + public void showToast(String title, String message) { + toastTitle.setText(title == null ? "Modtale" : title); + toastMessage.setText(message == null ? "" : message); + ToastTone tone = toneFor(title); + if (toast.getChildren().isEmpty()) { + toastIcon = new StackPane(); + toastIcon.getStyleClass().add("toast-icon"); + + VBox copy = new VBox(1, toastTitle, toastMessage); + copy.getStyleClass().add("toast-copy"); + copy.setMaxWidth(292); + HBox.setHgrow(copy, Priority.ALWAYS); + + HBox box = new HBox(10, toastIcon, copy); + box.getStyleClass().add("toast-content"); + box.setAlignment(Pos.TOP_LEFT); + toastTitle.getStyleClass().add("toast-title"); + toastTitle.setWrapText(true); + toastTitle.setMaxWidth(292); + toastMessage.getStyleClass().add("toast-message"); + toastMessage.setWrapText(true); + toastMessage.setMaxWidth(292); + toast.getChildren().add(box); + } + toast.getStyleClass().removeAll(TOAST_SUCCESS, TOAST_ERROR, TOAST_NEUTRAL); + toast.getStyleClass().add(tone.styleClass); + if (toastIcon != null) { + Node icon = LauncherIcons.icon(tone.glyph, 14); + toastIcon.getChildren().setAll(icon); + } + toast.setVisible(true); + toast.setManaged(true); + CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS).execute(() -> + Platform.runLater(() -> { + toast.setVisible(false); + toast.setManaged(false); + })); + } + + private static ToastTone toneFor(String title) { + String normalized = title == null ? "" : title.toLowerCase(Locale.ROOT); + if (normalized.contains("failed") + || normalized.contains("error") + || normalized.startsWith("could not")) { + return ToastTone.ERROR; + } + if (normalized.contains("signed in") + || normalized.contains("saved") + || normalized.contains("installed") + || normalized.contains("ready") + || normalized.contains("cleared") + || normalized.contains("liked") + || normalized.contains("updated") + || normalized.equals("accepted")) { + return ToastTone.SUCCESS; + } + return ToastTone.NEUTRAL; + } + + private enum ToastTone { + SUCCESS(TOAST_SUCCESS, LauncherIcons.Glyph.CHECK), + ERROR(TOAST_ERROR, LauncherIcons.Glyph.X), + NEUTRAL(TOAST_NEUTRAL, LauncherIcons.Glyph.BELL); + + private final String styleClass; + private final LauncherIcons.Glyph glyph; + + ToastTone(String styleClass, LauncherIcons.Glyph glyph) { + this.styleClass = styleClass; + this.glyph = glyph; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedbackView.java b/launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedbackView.java new file mode 100644 index 00000000..fda309cb --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/feedback/LauncherFeedbackView.java @@ -0,0 +1,49 @@ +package net.modtale.launcher.ui.feedback; + +import static net.modtale.launcher.ui.common.LauncherUi.statusDot; + +import java.util.concurrent.Executor; +import java.util.function.Supplier; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; + +public final class LauncherFeedbackView { + + private final Label statusText = new Label("Ready"); + private final Label toastTitle = new Label(); + private final Label toastMessage = new Label(); + private final VBox logList = new VBox(4); + private final StackPane toast = new StackPane(); + + public LauncherFeedbackView() { + toast.getStyleClass().add("toast"); + toast.setMaxWidth(360); + toast.setMaxHeight(Region.USE_PREF_SIZE); + toast.setVisible(false); + toast.setManaged(false); + } + + public Label statusText() { + return statusText; + } + + public StackPane toast() { + return toast; + } + + public LauncherFeedback feedback(Executor executor, Supplier idleStatus) { + return new LauncherFeedback(executor, statusText, logList, toast, toastTitle, toastMessage, idleStatus); + } + + public Node statusChip() { + HBox status = new HBox(8, statusDot(), statusText); + status.getStyleClass().add("status-chip"); + status.setAlignment(Pos.CENTER_LEFT); + return status; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/InstallDuplicateWarning.java b/launcher/src/main/java/net/modtale/launcher/ui/library/InstallDuplicateWarning.java new file mode 100644 index 00000000..44964a31 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/InstallDuplicateWarning.java @@ -0,0 +1,258 @@ +package net.modtale.launcher.ui.library; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; +import net.modtale.launcher.model.project.ProjectDependency; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.model.worldlist.WorldModList; + +final class InstallDuplicateWarning { + + private InstallDuplicateWarning() { + } + + static Result forSummary(List installedProjects, ProjectSummary summary) { + if (summary == null) { + return Result.empty(); + } + return findDuplicates(installedProjects, List.of(new Candidate( + summary.id(), + summary.slug(), + summary.title(), + "" + ))); + } + + static Result forProject( + List installedProjects, + ProjectDetail project, + ProjectVersion version, + List dependencies, + boolean includeOptionalDependencies + ) { + if (project == null) { + return Result.empty(); + } + List candidates = new ArrayList<>(); + candidates.add(new Candidate( + project.id(), + project.slug(), + project.title(), + version == null ? "" : version.versionNumber() + )); + for (ProjectDependency dependency : installableDependencies(dependencies, includeOptionalDependencies)) { + candidates.add(new Candidate( + dependency.projectId(), + dependency.slug(), + first(dependency.title(), dependency.projectTitle(), dependency.projectId()), + dependency.versionNumber() + )); + } + return findDuplicates(installedProjects, candidates); + } + + static Result forWorldModList(List installedProjects, WorldModList list) { + if (list == null || list.mods().isEmpty()) { + return Result.empty(); + } + List candidates = list.mods().stream() + .filter(item -> item != null && item.downloadable()) + .map(item -> new Candidate( + item.projectId(), + item.slug(), + first(item.title(), item.projectId(), item.slug(), item.modId()), + item.versionNumber() + )) + .toList(); + return findDuplicates(installedProjects, candidates); + } + + private static Result findDuplicates(List installedProjects, List candidates) { + Map installedByKey = installedByKey(installedProjects); + Map duplicates = new LinkedHashMap<>(); + for (Candidate candidate : candidates) { + for (String key : candidate.keys()) { + InstalledEntry installed = installedByKey.get(key); + if (installed == null) { + continue; + } + duplicates.putIfAbsent(candidate.duplicateKey(), new Duplicate(candidate, installed)); + break; + } + } + return new Result(List.copyOf(duplicates.values())); + } + + private static Map installedByKey(List installedProjects) { + Map entries = new LinkedHashMap<>(); + if (installedProjects == null || installedProjects.isEmpty()) { + return entries; + } + for (InstalledProject installed : installedProjects) { + if (installed == null) { + continue; + } + InstalledEntry projectEntry = new InstalledEntry( + installed.projectId(), + installed.slug(), + first(installed.title(), installed.slug(), installed.projectId(), "Installed mod"), + installed.installedVersion() + ); + putEntry(entries, projectEntry); + for (InstalledProjectReference reference : bundledReferences(installed)) { + InstalledEntry referenceEntry = new InstalledEntry( + reference.projectId(), + reference.slug(), + first(reference.displayName(), reference.slug(), reference.projectId(), "Bundled mod"), + reference.versionNumber() + ); + putEntry(entries, referenceEntry); + } + } + return entries; + } + + private static void putEntry(Map entries, InstalledEntry entry) { + for (String key : entry.keys()) { + entries.putIfAbsent(key, entry); + } + } + + private static List bundledReferences(InstalledProject installed) { + if (installed == null) { + return List.of(); + } + if (!installed.bundledProjects().isEmpty()) { + return installed.bundledProjects(); + } + List references = new ArrayList<>(); + installed.dependencyProjectIds().forEach(id -> references.add(new InstalledProjectReference( + id, id, "", id, "", "", "", "MODTALE", "", "", "", "", "", "", null, null + ))); + return references; + } + + private static List installableDependencies( + List dependencies, + boolean includeOptionalDependencies + ) { + if (dependencies == null || dependencies.isEmpty()) { + return List.of(); + } + return dependencies.stream() + .filter(dependency -> dependency != null + && !dependency.isExternal() + && !dependency.isEmbedded() + && !isBlank(dependency.projectId()) + && (includeOptionalDependencies || !dependency.isOptional())) + .toList(); + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (!isBlank(value)) { + return value.trim(); + } + } + return ""; + } + + private static boolean isBlank(String value) { + return value == null || value.isBlank(); + } + + private static Set keys(String projectId, String slug) { + Set keys = new LinkedHashSet<>(); + addKey(keys, projectId); + addKey(keys, slug); + return keys; + } + + private static void addKey(Set keys, String value) { + String key = normalizeKey(value); + if (!key.isBlank()) { + keys.add(key); + } + } + + private static String normalizeKey(String value) { + return value == null ? "" : value.trim().toLowerCase(Locale.ROOT); + } + + record Result(List duplicates) { + Result { + duplicates = duplicates == null ? List.of() : List.copyOf(duplicates); + } + + static Result empty() { + return new Result(List.of()); + } + + boolean hasDuplicates() { + return !duplicates.isEmpty(); + } + + int count() { + return duplicates.size(); + } + + String summary() { + List names = duplicates.stream() + .map(Duplicate::displayName) + .filter(name -> !name.isBlank()) + .distinct() + .limit(4) + .toList(); + int remaining = duplicates.size() - names.size(); + return String.join(", ", names) + (remaining > 0 ? ", +" + remaining + " more" : ""); + } + } + + record Duplicate(Candidate candidate, InstalledEntry installed) { + String displayName() { + return first(candidate.title(), installed.title(), candidate.projectId(), candidate.slug()); + } + } + + private record Candidate(String projectId, String slug, String title, String version) { + private Candidate { + projectId = first(projectId); + slug = first(slug); + title = first(title, projectId, slug); + version = first(version); + } + + private Set keys() { + return InstallDuplicateWarning.keys(projectId, slug); + } + + private String duplicateKey() { + return first(projectId, slug, title).toLowerCase(Locale.ROOT); + } + } + + private record InstalledEntry(String projectId, String slug, String title, String version) { + private InstalledEntry { + projectId = first(projectId); + slug = first(slug); + title = first(title, projectId, slug); + version = first(version); + } + + private Set keys() { + return InstallDuplicateWarning.keys(projectId, slug); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LauncherLibraryController.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LauncherLibraryController.java new file mode 100644 index 00000000..99a423bb --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LauncherLibraryController.java @@ -0,0 +1,1300 @@ +package net.modtale.launcher.ui.library; + +import static net.modtale.launcher.ui.common.LauncherUi.emptyState; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.api.ModtaleApiException; +import net.modtale.launcher.hytale.HytaleWorldManager; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleInstalledMod; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorldConfig; +import net.modtale.launcher.install.ModInstaller; +import net.modtale.launcher.install.UpdateService; +import net.modtale.launcher.install.WorldModListInstaller; +import net.modtale.launcher.model.install.InstallResult; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; +import net.modtale.launcher.model.install.UpdateCandidate; +import net.modtale.launcher.model.project.ProjectDependency; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectMeta; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.model.worldlist.CreateWorldModListRequest; +import net.modtale.launcher.model.worldlist.WorldModList; +import net.modtale.launcher.model.worldlist.WorldModListInstallResult; +import net.modtale.launcher.settings.LauncherSettings; +import net.modtale.launcher.ui.account.LauncherAccountController; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherExternalLinks; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherView; +import net.modtale.launcher.ui.common.StatusModal; +import net.modtale.launcher.ui.feedback.LauncherFeedback; +import net.modtale.launcher.ui.settings.LauncherSettingsController; + +public final class LauncherLibraryController { + + private final ModtaleApiClient apiClient; + private final ModInstaller installer; + private final WorldModListInstaller worldModListInstaller; + private final UpdateService updateService; + private final LauncherSettingsController settingsController; + private final LauncherAccountController accountController; + private final LauncherFeedback feedback; + private final Executor executor; + private final Supplier overlayHost; + private final HytaleWorldManager worldManager = new HytaleWorldManager(); + private final VBox projectList = new VBox(10); + private final VBox projectDetail = new VBox(14); + private final VBox updatesList = new VBox(12); + private final Map projectDetails = new LinkedHashMap<>(); + private final Map projectMetadata = new LinkedHashMap<>(); + private final Map availableUpdates = new LinkedHashMap<>(); + private final Set loadingProjectIds = new LinkedHashSet<>(); + private final Set loadingMetadataIds = new LinkedHashSet<>(); + private final Set expandedModpackContents = new LinkedHashSet<>(); + private final LibraryWorldRenderer worldRenderer; + private final LibraryWorldListRenderer worldListRenderer; + private final LibraryProjectListRenderer listRenderer; + private final PostDownloadWorldModal postDownloadWorldModal; + + private List currentUpdates = List.of(); + private List installedProjects = List.of(); + private List worlds = List.of(); + private List installedMods = List.of(); + private String selectedWorldKey = ""; + private Node libraryView; + private Node updatesView; + private StackPane installLoadingOverlay; + private Label installLoadingTitle; + private Label installLoadingSubtitle; + + public LauncherLibraryController( + ModtaleApiClient apiClient, + ModInstaller installer, + WorldModListInstaller worldModListInstaller, + UpdateService updateService, + LauncherSettingsController settingsController, + LauncherAccountController accountController, + LauncherFeedback feedback, + Executor executor, + CachedImageLoader imageLoader, + Supplier overlayHost + ) { + this.apiClient = apiClient; + this.installer = installer; + this.worldModListInstaller = worldModListInstaller; + this.updateService = updateService; + this.settingsController = settingsController; + this.accountController = accountController; + this.feedback = feedback; + this.executor = executor; + this.overlayHost = overlayHost == null ? () -> null : overlayHost; + this.listRenderer = new LibraryProjectListRenderer(ignored -> { + }, this::updateSelected); + this.postDownloadWorldModal = new PostDownloadWorldModal( + this.overlayHost, + this::applyPostDownloadWorldSelection, + imageLoader + ); + this.worldListRenderer = new LibraryWorldListRenderer(imageLoader, this::selectWorld); + this.worldRenderer = new LibraryWorldRenderer( + imageLoader, + this::updateSelected, + this::ensureProjectDetailLoaded, + this::switchSelectedVersion, + this::uninstallSelected, + this::unlockModpack, + this::toggleModpackContents, + this::setModsEnabled, + this::shareWorldSnapshot, + this::createModpackFromWorld + ); + } + + public Node libraryView() { + if (libraryView == null) { + libraryView = buildLibraryView(); + renderLibrary(); + } + return libraryView; + } + + public Node updatesView() { + if (updatesView == null) { + VBox view = new VBox(12); + view.setUserData(LauncherView.UPDATES); + view.getStyleClass().addAll("view", "library-updates-view"); + view.getChildren().add(updatesList); + updatesView = view; + renderUpdates(); + } + return updatesView; + } + + public void refresh() { + renderLibrary(); + renderUpdates(); + } + + public LauncherSettings settings() { + return settingsController.settings(); + } + + public void installSelectedProject(ProjectSummary summary) { + settingsController.saveFromFields(false); + LauncherSettings settings = settingsController.settings(); + if (!confirmDuplicateInstall(InstallDuplicateWarning.forSummary(settings.getInstalledProjects(), summary))) { + return; + } + String status = "Installing " + summary + "..."; + runInstallWithOverlay(status, () -> { + accountController.ensureSignedIn(); + ProjectDetail project = detailWithVersions(summary.routeKey()); + return installer.installAndRecord(project, settings); + }, this::finishInstall); + } + + public void installSelectedProjectVersion(ProjectDetail project, ProjectVersion version, String gameVersion) { + settingsController.saveFromFields(false); + LauncherSettings settings = settingsController.settings(); + if (!confirmDuplicateInstall(InstallDuplicateWarning.forProject( + settings.getInstalledProjects(), + project, + version, + dependenciesForSettings(version, settings), + settings.isIncludeOptionalDependencies() + ))) { + return; + } + String status = "Installing " + project.title() + " " + version.versionNumber() + "..."; + runInstallWithOverlay(status, () -> { + accountController.ensureSignedIn(); + return installer.installAndRecord(project, version, settings, gameVersion); + }, this::finishInstall); + } + + public void installSelectedProjectVersion( + ProjectDetail project, + ProjectVersion version, + String gameVersion, + List selectedDependencies + ) { + settingsController.saveFromFields(false); + LauncherSettings settings = settingsController.settings(); + List dependencies = selectedDependencies == null ? List.of() : List.copyOf(selectedDependencies); + if (!confirmDuplicateInstall(InstallDuplicateWarning.forProject( + settings.getInstalledProjects(), + project, + version, + dependencies, + true + ))) { + return; + } + String status = "Installing " + project.title() + " " + version.versionNumber() + "..."; + runInstallWithOverlay(status, () -> { + accountController.ensureSignedIn(); + return installer.installAndRecord(project, version, settings, gameVersion, dependencies); + }, this::finishInstall); + } + + public void installWorldModList(String listId) { + String normalizedListId = value(listId, ""); + if (normalizedListId.isBlank()) { + feedback.showToast("Action failed", "The shared list link is missing its id."); + return; + } + + settingsController.saveFromFields(false); + feedback.runAsync("Preparing shared mod list...", () -> apiClient.getWorldModListForInstall(normalizedListId), list -> { + if (!confirmDuplicateInstall(InstallDuplicateWarning.forWorldModList( + settingsController.settings().getInstalledProjects(), + list + ))) { + return; + } + runInstallWithOverlay( + "Installing shared mod list...", + () -> worldModListInstaller.install(list, settingsController.settings()), + this::finishWorldModListInstall + ); + }); + } + + public void checkUpdates() { + settingsController.saveFromFields(false); + feedback.runAsync("Checking updates...", () -> { + accountController.ensureSignedIn(); + return updateService.checkForUpdates(settingsController.settings()); + }, updates -> { + currentUpdates = List.copyOf(updates); + availableUpdates.clear(); + updates.forEach(update -> availableUpdates.put(update.installedProject().projectId(), update)); + renderLibrary(); + renderUpdates(); + feedback.log(updates.isEmpty() ? "No updates available." : updates.size() + " updates available."); + }); + } + + private Node buildLibraryView() { + return new LibraryShellView(projectList, projectDetail, this::renderLibrary, this::checkUpdates) + .build(); + } + + private void runInstallWithOverlay(String status, Supplier work, Consumer onSuccess) { + showInstallLoadingOverlay( + value(status, "Installing...").replaceFirst("\\.\\.\\.$", ""), + "Downloading and installing files. World selection will appear next." + ); + feedback.runAsync(status, work, result -> { + try { + onSuccess.accept(result); + } catch (RuntimeException ex) { + hideInstallLoadingOverlay(); + throw ex; + } + }, ignored -> hideInstallLoadingOverlay()); + } + + private boolean confirmDuplicateInstall(InstallDuplicateWarning.Result warning) { + if (warning == null || !warning.hasDuplicates()) { + return true; + } + StatusModal.Result result = StatusModal.builder(overlayHost) + .type(StatusModal.Type.WARNING) + .title(warning.count() == 1 ? "Mod already installed" : "Mods already installed") + .message("Already installed: " + warning.summary() + + ". Continuing may replace existing files or add another copy if this install comes from a bundle or modpack.") + .actionLabel("Install Anyway") + .actionIcon(LauncherIcons.Glyph.DOWNLOAD) + .secondaryLabel("Cancel") + .showAndWait(); + return result == StatusModal.Result.PRIMARY; + } + + private List dependenciesForSettings(ProjectVersion version, LauncherSettings settings) { + if (version == null || settings == null || !settings.isIncludeDependencies()) { + return List.of(); + } + return version.dependencies(); + } + + private List dependenciesForExistingInstall( + InstalledProject installed, + ProjectVersion version, + LauncherSettings settings + ) { + if (installed != null && !installed.bundledProjects().isEmpty()) { + return installed.bundledProjects().stream() + .map(InstalledProjectReference::toDependency) + .toList(); + } + return dependenciesForSettings(version, settings); + } + + private void showInstallLoadingOverlay(String title, String subtitle) { + if (!Platform.isFxApplicationThread()) { + Platform.runLater(() -> showInstallLoadingOverlay(title, subtitle)); + return; + } + StackPane hostPane = overlayHost.get(); + if (hostPane == null) { + return; + } + if (installLoadingOverlay == null) { + installLoadingOverlay = installLoadingShell(); + hostPane.getChildren().add(installLoadingOverlay); + } else if (installLoadingOverlay.getParent() == null) { + hostPane.getChildren().add(installLoadingOverlay); + } + installLoadingTitle.setText(value(title, "Installing")); + installLoadingSubtitle.setText(value(subtitle, "Preparing the next step.")); + installLoadingOverlay.toFront(); + installLoadingOverlay.requestFocus(); + } + + private StackPane installLoadingShell() { + StackPane shell = new StackPane(); + shell.getStyleClass().add("install-loading-overlay"); + shell.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + shell.setFocusTraversable(true); + shell.setOnMouseClicked(event -> event.consume()); + + ProgressIndicator spinner = new ProgressIndicator(); + spinner.getStyleClass().add("install-loading-spinner"); + spinner.setMaxSize(54, 54); + spinner.setMinSize(54, 54); + + installLoadingTitle = new Label("Installing"); + installLoadingTitle.getStyleClass().add("install-loading-title"); + installLoadingSubtitle = new Label("Downloading and installing files. World selection will appear next."); + installLoadingSubtitle.getStyleClass().add("install-loading-subtitle"); + installLoadingSubtitle.setWrapText(true); + + VBox copy = new VBox(6, installLoadingTitle, installLoadingSubtitle); + copy.getStyleClass().add("install-loading-copy"); + copy.setAlignment(Pos.CENTER); + + VBox card = new VBox(18, spinner, copy); + card.getStyleClass().add("install-loading-card"); + card.setAlignment(Pos.CENTER); + card.setMaxWidth(420); + card.setMaxHeight(Region.USE_PREF_SIZE); + + shell.getChildren().add(card); + return shell; + } + + private void hideInstallLoadingOverlay() { + if (!Platform.isFxApplicationThread()) { + Platform.runLater(this::hideInstallLoadingOverlay); + return; + } + if (installLoadingOverlay == null) { + return; + } + Parent parent = installLoadingOverlay.getParent(); + if (parent instanceof StackPane stack) { + stack.getChildren().remove(installLoadingOverlay); + } + installLoadingOverlay = null; + installLoadingTitle = null; + installLoadingSubtitle = null; + } + + private void renderLibrary() { + try { + worlds = worldManager.loadWorlds(settingsController.settings()); + installedMods = worldManager.loadInstalledMods(settingsController.settings()); + } catch (RuntimeException ex) { + worlds = List.of(); + installedMods = List.of(); + feedback.log(ex.getMessage()); + } + recoverLocalInstalls(); + normalizeBundledDependencyInstalls(); + installedProjects = settingsController.settings().getInstalledProjects().stream() + .sorted(Comparator + .comparing(InstalledProject::updatedAt, Comparator.nullsLast(Comparator.reverseOrder())) + .thenComparing(project -> value(project.title(), project.projectId()), String.CASE_INSENSITIVE_ORDER)) + .toList(); + + if (selectedWorldKey.isBlank() && !worlds.isEmpty()) { + selectedWorldKey = worldKey(worlds.getFirst()); + } + if (!selectedWorldKey.isBlank() + && worlds.stream().noneMatch(world -> worldKey(world).equals(selectedWorldKey))) { + selectedWorldKey = worlds.isEmpty() ? "" : worldKey(worlds.getFirst()); + } + + renderWorldRows(); + renderWorldDetail(); + ensureProjectMetadataLoaded(); + } + + private void recoverLocalInstalls() { + LibraryLocalInstallRecovery.RecoveryResult recovery = LibraryLocalInstallRecovery.recover( + settingsController.settings(), + settingsController.settings().getInstalledProjects(), + installedMods + ); + if (recovery.recoveredCount() <= 0) { + return; + } + settingsController.settings().setInstalledProjects(recovery.projects()); + settingsController.saveCurrentSettings(); + feedback.log("Recovered " + recovery.recoveredCount() + " installed mod" + + LibraryProjectSupport.plural(recovery.recoveredCount()) + " from the Hytale Mods folder."); + } + + private void normalizeBundledDependencyInstalls() { + LibraryBundledInstallNormalizer.Result result = LibraryBundledInstallNormalizer.normalize( + settingsController.settings().getInstalledProjects(), + installedMods + ); + if (result.addedChildren() <= 0) { + return; + } + settingsController.settings().setInstalledProjects(result.projects()); + settingsController.saveCurrentSettings(); + feedback.log("Promoted " + result.addedChildren() + " bundled dependenc" + + (result.addedChildren() == 1 ? "y" : "ies") + " to installed mod records."); + } + + private void ensureProjectMetadataLoaded() { + if (executor == null || apiClient == null) { + return; + } + List missing = metadataProjectIds().stream() + .filter(id -> !projectMetadata.containsKey(id)) + .filter(loadingMetadataIds::add) + .toList(); + if (missing.isEmpty()) { + return; + } + CompletableFuture.supplyAsync(() -> apiClient.getProjectMetaBatch(missing), executor) + .whenComplete((result, error) -> Platform.runLater(() -> { + Map loaded = error == null && result != null ? result : Map.of(); + for (String id : missing) { + projectMetadata.put(id, loaded.getOrDefault(id, fallbackMeta())); + loadingMetadataIds.remove(id); + } + renderWorldDetail(); + })); + } + + private List metadataProjectIds() { + LinkedHashSet ids = new LinkedHashSet<>(); + for (InstalledProject project : installedProjects) { + if (!project.projectId().isBlank() + && (project.source().isBlank() || InstalledProject.SOURCE_MODTALE.equalsIgnoreCase(project.source()))) { + ids.add(project.projectId()); + } + for (InstalledProjectReference reference : bundledReferences(project)) { + if (reference.isModtaleProject()) { + ids.add(reference.projectId()); + } + } + } + return List.copyOf(ids); + } + + private ProjectMeta fallbackMeta() { + return new ProjectMeta("", "", "", "", "", 0, "", ""); + } + + private void renderWorldRows() { + projectList.getChildren().clear(); + if (worlds.isEmpty()) { + projectList.getChildren().add(emptyState("No worlds found", "Create a Hytale world, then refresh.")); + return; + } + worlds.forEach(world -> projectList.getChildren().add(worldListRenderer.worldRow( + worldListItem(world), + worldKey(world).equals(selectedWorldKey) + ))); + } + + private void selectWorld(HytaleWorld world) { + selectedWorldKey = worldKey(world); + renderWorldRows(); + renderWorldDetail(); + } + + private void renderWorldDetail() { + Optional selected = selectedWorld(); + if (selected.isEmpty()) { + if (worlds.isEmpty()) { + projectDetail.getChildren().setAll(emptyState("No worlds found", "Create a Hytale world, then refresh the launcher.")); + } else { + projectDetail.getChildren().setAll(worldRenderer.worldDetail(null)); + } + return; + } + projectDetail.getChildren().setAll(worldRenderer.worldDetail(worldModel(selected.get()))); + } + + private LibraryWorldModel worldModel(HytaleWorld world) { + HytaleWorldConfig config = worldManager.loadConfig(world.configPath()); + List projects = installedProjects.stream() + .flatMap(project -> worldProjectModels(project, config).stream()) + .toList(); + int enabledProjects = (int) projects.stream() + .filter(project -> project.enabledCount() > 0) + .count(); + return new LibraryWorldModel( + world, + LibraryProjectSupport.worldMeta(world), + enabledProjects, + projects.size(), + projects + ); + } + + private LibraryWorldListItem worldListItem(HytaleWorld world) { + HytaleWorldConfig config = worldManager.loadConfig(world.configPath()); + int enabledProjects = 0; + int totalProjects = 0; + for (InstalledProject project : installedProjects) { + for (LibraryWorldProjectModel model : worldProjectModels(project, config)) { + totalProjects++; + if (model.enabledCount() > 0) { + enabledProjects++; + } + } + } + return new LibraryWorldListItem( + world, + LibraryProjectSupport.worldMeta(world), + enabledProjects, + totalProjects + ); + } + + private List worldProjectModels(InstalledProject installed, HytaleWorldConfig config) { + return List.of(worldProjectModel(installed, config)); + } + + private LibraryWorldProjectModel worldProjectModel(InstalledProject installed, HytaleWorldConfig config) { + List modIds = worldModIds(installed); + return worldProjectModel( + installed, + config, + modIds, + installed.isModpack() ? contentItems(installed, config) : List.of(), + LibraryWorldProjectDisplay.root(installed, projectMetadata.get(installed.projectId())) + ); + } + + private LibraryWorldProjectModel worldProjectModel( + InstalledProject installed, + HytaleWorldConfig config, + List modIds, + List contents, + LibraryWorldProjectDisplay display + ) { + int enabled = enabledCount(config, modIds); + return new LibraryWorldProjectModel( + installed, + projectDetails.get(installed.projectId()), + projectMetadata.get(installed.projectId()), + availableUpdates.get(installed.projectId()), + loadingProjectIds.contains(installed.projectId()), + modIds, + enabled, + modIds.size(), + contents, + display, + isModpackContentsCollapsed(installed) + ); + } + + private List worldModIds(InstalledProject installed) { + Set manifestIds = new LinkedHashSet<>(); + Set files = installed.files().stream() + .map(file -> java.nio.file.Path.of(file).toAbsolutePath().normalize()) + .map(java.nio.file.Path::toString) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + for (HytaleInstalledMod mod : installedMods) { + String path = mod.file().toAbsolutePath().normalize().toString(); + if (files.contains(path) && mod.id() != null && !mod.id().isBlank()) { + manifestIds.add(mod.id()); + } + } + return manifestIds.isEmpty() + ? LibraryProjectSupport.projectWorldModIds(installed) + : List.copyOf(manifestIds); + } + + private Optional selectedWorld() { + if (selectedWorldKey == null || selectedWorldKey.isBlank()) { + return Optional.empty(); + } + return worlds.stream() + .filter(world -> worldKey(world).equals(selectedWorldKey)) + .findFirst(); + } + + private List contentItems(InstalledProject installed, HytaleWorldConfig config) { + if (!hasUnlockableContents(installed)) { + return List.of(); + } + + Map modsByFile = installedModsByFile(installedMods); + List references = bundledReferences(installed); + List items = new ArrayList<>(); + Set seenModIds = new LinkedHashSet<>(); + for (String file : installed.files()) { + HytaleInstalledMod mod = modsByFile.get(normalizedFileKey(file)); + if (mod == null || mod.id() == null || mod.id().isBlank() || !seenModIds.add(mod.id())) { + continue; + } + items.add(manifestContentItem(mod, matchingReference(mod, file, references), config)); + } + if (!items.isEmpty()) { + return items; + } + + for (InstalledProjectReference reference : references) { + LibraryWorldContentItem item = referenceContentItem(reference, config); + if (item != null) { + items.add(item); + } + } + return items; + } + + private LibraryWorldContentItem manifestContentItem( + HytaleInstalledMod mod, + InstalledProjectReference reference, + HytaleWorldConfig config + ) { + ProjectMeta meta = reference == null ? null : projectMetadata.get(reference.projectId()); + String author = value(meta == null ? "" : meta.author(), ""); + String title = first( + meta == null ? "" : meta.title(), + reference == null ? "" : reference.displayName(), + mod.name(), + mod.id() + ); + String classification = first( + meta == null ? "" : meta.classification(), + reference == null ? "" : reference.classification(), + "PLUGIN" + ); + String icon = first(meta == null ? "" : meta.icon(), reference == null ? "" : reference.icon()); + List modIds = List.of(mod.id()); + return new LibraryWorldContentItem( + mod.id(), + title, + contentMeta(author, value(mod.version(), ""), mod.id()), + classification, + icon, + author, + modIds, + enabledCount(config, modIds), + modIds.size(), + true + ); + } + + private LibraryWorldContentItem referenceContentItem(InstalledProjectReference reference, HytaleWorldConfig config) { + if (reference == null) { + return null; + } + ProjectMeta meta = projectMetadata.get(reference.projectId()); + String author = value(meta == null ? "" : meta.author(), ""); + String title = first(meta == null ? "" : meta.title(), reference.displayName()); + String classification = first(meta == null ? "" : meta.classification(), reference.classification(), "PLUGIN"); + String icon = first(meta == null ? "" : meta.icon(), reference.icon()); + List modIds = referenceModIds(reference, config); + return new LibraryWorldContentItem( + first(reference.projectId(), reference.externalId(), reference.id(), title), + title, + contentMeta(author, LibraryProjectSupport.childMeta(reference), modIds.isEmpty() ? "Included in pack" : ""), + classification, + icon, + author, + modIds, + enabledCount(config, modIds), + modIds.size(), + !modIds.isEmpty() + ); + } + + private List referenceModIds(InstalledProjectReference reference, HytaleWorldConfig config) { + if (reference.projectId() != null && !reference.projectId().isBlank()) { + Optional installedChild = installedProjects.stream() + .filter(project -> reference.projectId().equals(project.projectId())) + .findFirst(); + if (installedChild.isPresent()) { + return worldModIds(installedChild.get()); + } + } + String candidate = LibraryProjectSupport.referenceWorldModId(reference); + if (candidate.isBlank()) { + return List.of(); + } + boolean installed = installedMods.stream() + .anyMatch(mod -> candidate.equals(mod.id())); + if (installed || config.enabledByMod().containsKey(candidate)) { + return List.of(candidate); + } + return List.of(); + } + + private InstalledProjectReference matchingReference( + HytaleInstalledMod mod, + String file, + List references + ) { + if (mod == null || references == null || references.isEmpty()) { + return null; + } + Set modKeys = new LinkedHashSet<>(); + addNormalized(modKeys, mod.id()); + addNormalized(modKeys, mod.name()); + addNormalized(modKeys, fileName(file)); + for (InstalledProjectReference reference : references) { + Set referenceKeys = new LinkedHashSet<>(); + addNormalized(referenceKeys, LibraryProjectSupport.referenceWorldModId(reference)); + addNormalized(referenceKeys, reference.title()); + addNormalized(referenceKeys, reference.slug()); + addNormalized(referenceKeys, reference.projectId()); + addNormalized(referenceKeys, reference.externalId()); + addNormalized(referenceKeys, reference.externalFileName()); + addNormalized(referenceKeys, fileName(reference.externalFileUrl())); + addNormalized(referenceKeys, fileName(reference.cachedFileUrl())); + for (String key : modKeys) { + if (referenceKeys.contains(key)) { + return reference; + } + } + } + return null; + } + + private List bundledReferences(InstalledProject installed) { + if (!installed.bundledProjects().isEmpty()) { + return installed.bundledProjects(); + } + List references = new ArrayList<>(); + installed.dependencyProjectIds().forEach(id -> references.add(new InstalledProjectReference( + id, id, "", id, "", "", "", "MODTALE", "", "", "", "", "", "", null, null + ))); + installed.externalDependencies().forEach(id -> references.add(new InstalledProjectReference( + id, "", "", id, "", "", "", "EXTERNAL", id, "", "", "", "", "", null, null + ))); + return references; + } + + private int enabledCount(HytaleWorldConfig config, Collection modIds) { + if (config == null || modIds == null || modIds.isEmpty()) { + return 0; + } + return (int) modIds.stream() + .filter(id -> id != null && !id.isBlank()) + .filter(id -> config.enabledByMod().getOrDefault(id, false)) + .count(); + } + + private Map installedModsByFile(List mods) { + Map byFile = new LinkedHashMap<>(); + for (HytaleInstalledMod mod : mods) { + String key = normalizedFileKey(mod.file()); + if (!key.isBlank()) { + byFile.putIfAbsent(key, mod); + } + } + return byFile; + } + + private boolean hasUnlockableContents(InstalledProject installed) { + return installed.isModpack(); + } + + private void updateSelected(UpdateCandidate update) { + settingsController.saveFromFields(false); + LauncherSettings settings = settingsController.settings(); + if (!confirmDuplicateInstall(InstallDuplicateWarning.forProject( + installedProjectsExcept(settings.getInstalledProjects(), update.installedProject()), + update.project(), + update.newestVersion(), + dependenciesForExistingInstall(update.installedProject(), update.newestVersion(), settings), + true + ))) { + return; + } + runInstallWithOverlay("Updating " + update.title() + "...", () -> { + accountController.ensureSignedIn(); + return installer.switchVersionAndRecord( + update.installedProject(), + update.project(), + update.newestVersion(), + settings + ); + }, result -> { + availableUpdates.remove(update.installedProject().projectId()); + currentUpdates = List.copyOf(availableUpdates.values()); + finishInstall(result); + }); + } + + private void switchSelectedVersion(InstalledProject installed, ProjectDetail detail, ProjectVersion version) { + settingsController.saveFromFields(false); + LauncherSettings settings = settingsController.settings(); + String gameVersion = LibraryProjectSupport.installGameVersion(version, installed, settings.getGameVersion()); + if (!confirmDuplicateInstall(InstallDuplicateWarning.forProject( + installedProjectsExcept(settings.getInstalledProjects(), installed), + detail, + version, + dependenciesForExistingInstall(installed, version, settings), + true + ))) { + return; + } + runInstallWithOverlay("Switching " + installed.title() + " to " + version.versionNumber() + "...", () -> { + accountController.ensureSignedIn(); + return installer.switchVersionAndRecord(installed, detail, version, settings, gameVersion); + }, result -> { + availableUpdates.remove(installed.projectId()); + currentUpdates = List.copyOf(availableUpdates.values()); + finishInstall(result); + }); + } + + private void uninstallSelected(InstalledProject installed) { + StatusModal.Result result = StatusModal.builder(overlayHost) + .type(StatusModal.Type.WARNING) + .title("Remove Project") + .message("Remove " + value(installed.title(), "this project") + + " from the library and delete its recorded files?") + .actionLabel("Remove") + .actionIcon(LauncherIcons.Glyph.TRASH) + .secondaryLabel("Cancel") + .showAndWait(); + if (result != StatusModal.Result.PRIMARY) { + return; + } + feedback.runAsync("Removing " + installed.title() + "...", () -> { + installer.uninstallAndRecord(installed, settingsController.settings()); + return installed; + }, removed -> { + availableUpdates.remove(removed.projectId()); + projectDetails.remove(removed.projectId()); + projectMetadata.remove(removed.projectId()); + expandedModpackContents.remove(installedProjectKey(removed)); + settingsController.reloadFromStore(); + renderLibrary(); + renderUpdates(); + accountController.syncLocalSettings(); + feedback.showToast("Removed", removed.title() + " was removed from your library."); + }); + } + + private void unlockModpack(InstalledProject installed) { + if (installed == null || !installed.isModpack()) { + return; + } + int contentCount = Math.max(1, LibraryProjectSupport.contentCount(installed)); + StatusModal.Result confirmation = StatusModal.builder(overlayHost) + .type(StatusModal.Type.WARNING) + .title("Unlock Modpack") + .message("Split " + value(installed.title(), "this modpack") + " into " + + contentCount + " individually installed mod" + + LibraryProjectSupport.plural(contentCount) + + "? Updates and version changes will be per mod, not the pack.") + .actionLabel("Unlock") + .actionIcon(LauncherIcons.Glyph.EDIT) + .secondaryLabel("Cancel") + .showAndWait(); + if (confirmation != StatusModal.Result.PRIMARY) { + return; + } + + LibraryModpackUnlockConverter.Result result = LibraryModpackUnlockConverter.convert( + settingsController.settings().getInstalledProjects(), + installed, + installedMods + ); + if (result.convertedCount() <= 0) { + StatusModal.builder(overlayHost) + .type(StatusModal.Type.ERROR) + .title("Could Not Unlock") + .message("No installed mod files or modpack contents were found for " + + value(installed.title(), "this modpack") + ".") + .actionLabel("Close") + .showAndWait(); + return; + } + + settingsController.settings().setInstalledProjects(result.projects()); + settingsController.removeInstalledProjectRecord(installed.projectId()); + settingsController.saveCurrentSettings(); + availableUpdates.remove(installed.projectId()); + currentUpdates = List.copyOf(availableUpdates.values()); + projectDetails.remove(installed.projectId()); + projectMetadata.remove(installed.projectId()); + expandedModpackContents.remove(installedProjectKey(installed)); + accountController.syncLocalSettings(); + feedback.log("Unlocked " + installed.title() + " into " + result.convertedCount() + + " individual installed mod" + LibraryProjectSupport.plural(result.convertedCount()) + "."); + feedback.showToast("Modpack unlocked", "Converted " + value(installed.title(), "the modpack") + + " into individual installed mods."); + renderLibrary(); + renderUpdates(); + } + + private void toggleModpackContents(InstalledProject installed) { + if (installed == null || !installed.isModpack()) { + return; + } + String key = installedProjectKey(installed); + if (key.isBlank()) { + return; + } + if (!expandedModpackContents.add(key)) { + expandedModpackContents.remove(key); + } + renderWorldDetail(); + } + + private boolean isModpackContentsCollapsed(InstalledProject installed) { + return installed != null && !expandedModpackContents.contains(installedProjectKey(installed)); + } + + private void shareWorldSnapshot(HytaleWorld world) { + settingsController.saveFromFields(false); + feedback.runAsync("Creating " + world.name() + " share link...", () -> { + accountController.ensureSignedIn(); + return apiClient.createWorldModList(snapshotRequest(world)); + }, list -> { + copyShareUrl(list.shareUrl()); + String message = "Copied share link for " + list.title() + "."; + feedback.log(message + " " + list.shareUrl()); + feedback.showToast("Share link copied", message); + }); + } + + private void createModpackFromWorld(HytaleWorld world) { + settingsController.saveFromFields(false); + feedback.runAsync("Preparing " + world.name() + " modpack starter...", () -> { + accountController.ensureSignedIn(); + return apiClient.createWorldModList(snapshotRequest(world)); + }, list -> { + String target = "/upload?type=MODPACK&fromList=" + encodeQuery(list.id()); + LauncherExternalLinks.open(target, feedback::showToast); + feedback.log("Opening Modtale to start a modpack from " + world.name() + "."); + }); + } + + private void finishInstall(InstallResult result) { + settingsController.reloadFromStore(); + String message = "Installed " + result.installedProject().title() + " " + + result.installedProject().installedVersion() + " (" + result.installedFiles().size() + " files)."; + feedback.log(message); + feedback.showToast("Installed", result.warnings().isEmpty() + ? message + : message + " Warnings: " + String.join(" ", result.warnings())); + renderLibrary(); + renderUpdates(); + accountController.syncLocalSettings(); + showPostDownloadWorldModal( + value(result.installedProject().title(), "Installed project"), + modIdsForFiles(result.installedFiles()) + ); + } + + private void finishWorldModListInstall(WorldModListInstallResult result) { + WorldModList list = result.list(); + renderLibrary(); + String title = list.title().isBlank() ? "shared mod list" : list.title(); + String message = "Installed " + result.installedFiles().size() + " file" + + LibraryProjectSupport.plural(result.installedFiles().size()) + " from " + title + "."; + feedback.log(message); + feedback.showToast("Installed", message); + showPostDownloadWorldModal(title, modIdsForFiles(result.installedFiles())); + } + + private boolean showPostDownloadWorldModal(String title, List modIds) { + List ids = modIds == null + ? List.of() + : modIds.stream() + .filter(id -> id != null && !id.isBlank()) + .map(String::trim) + .distinct() + .toList(); + if (ids.isEmpty() || worlds.isEmpty()) { + hideInstallLoadingOverlay(); + return false; + } + hideInstallLoadingOverlay(); + return postDownloadWorldModal.show(title, ids, postDownloadWorldOptions(ids)); + } + + private List postDownloadWorldOptions(List modIds) { + return worlds.stream() + .map(world -> { + HytaleWorldConfig config = worldManager.loadConfig(world.configPath()); + int enabled = enabledCount(config, modIds); + return new PostDownloadWorldModal.WorldOption( + world, + LibraryProjectSupport.worldMeta(world), + enabled, + modIds.size(), + enabled > 0, + enabled > 0 && enabled < modIds.size() + ); + }) + .toList(); + } + + private void applyPostDownloadWorldSelection(PostDownloadWorldModal.Selection selection) { + if (selection == null || selection.worlds().isEmpty() || selection.modIds().isEmpty()) { + return; + } + feedback.runAsync("Enabling install in selected worlds...", () -> { + for (HytaleWorld world : selection.worlds()) { + worldManager.setModsEnabled(world.configPath(), selection.modIds(), true); + } + return worldManager.loadWorlds(settingsController.settings()); + }, loadedWorlds -> { + worlds = loadedWorlds; + renderWorldRows(); + renderWorldDetail(); + feedback.log("Enabled " + selection.modIds().size() + " mod" + LibraryProjectSupport.plural(selection.modIds().size()) + + " in " + selection.worlds().size() + " world" + LibraryProjectSupport.plural(selection.worlds().size()) + "."); + feedback.showToast("Worlds updated", "Enabled the install in selected worlds."); + }); + } + + private List modIdsForFiles(List files) { + if (files == null || files.isEmpty()) { + return List.of(); + } + Set fileKeys = files.stream() + .map(LauncherLibraryController::normalizedFileKey) + .filter(key -> !key.isBlank()) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + if (fileKeys.isEmpty()) { + return List.of(); + } + List mods = installedMods.isEmpty() + ? worldManager.loadInstalledMods(settingsController.settings()) + : installedMods; + return mods.stream() + .filter(mod -> fileKeys.contains(normalizedFileKey(mod.file()))) + .map(HytaleInstalledMod::id) + .filter(id -> id != null && !id.isBlank()) + .distinct() + .toList(); + } + + private void ensureProjectDetailLoaded(InstalledProject installed) { + if (installed == null + || !LibraryProjectSupport.isModtaleProject(installed) + || projectDetails.containsKey(installed.projectId()) + || loadingProjectIds.contains(installed.projectId())) { + return; + } + loadingProjectIds.add(installed.projectId()); + renderWorldDetail(); + feedback.runAsync("Loading " + installed.title() + " releases...", () -> { + accountController.ensureSignedIn(); + return detailWithVersions(LibraryProjectSupport.routeKey(installed)); + }, detail -> { + loadingProjectIds.remove(installed.projectId()); + projectDetails.put(installed.projectId(), detail); + renderWorldDetail(); + }, error -> { + loadingProjectIds.remove(installed.projectId()); + renderWorldDetail(); + }); + } + + private ProjectDetail detailWithVersions(String routeKey) { + ProjectDetail project = apiClient.getProject(routeKey); + try { + List versions = apiClient.getProjectVersions(project.routeKey()); + if (!versions.isEmpty() || project.versions().isEmpty()) { + project = project.withVersions(versions); + } + } catch (RuntimeException error) { + if (project.versions().isEmpty()) { + throw error; + } + } + return project; + } + + private void setModsEnabled(HytaleWorld world, Collection modIds, boolean enabled) { + List ids = modIds.stream() + .filter(id -> id != null && !id.isBlank()) + .distinct() + .toList(); + if (ids.isEmpty()) { + return; + } + feedback.runAsync("Updating " + world.name() + "...", () -> { + worldManager.setModsEnabled(world.configPath(), ids, enabled); + return worldManager.loadWorlds(settingsController.settings()); + }, loadedWorlds -> { + worlds = loadedWorlds; + renderWorldRows(); + renderWorldDetail(); + feedback.log((enabled ? "Enabled " : "Disabled ") + ids.size() + " mod" + LibraryProjectSupport.plural(ids.size()) + + " for " + world.name() + "."); + }); + } + + private CreateWorldModListRequest snapshotRequest(HytaleWorld world) { + HytaleWorldConfig config = worldManager.loadConfig(world.configPath()); + Set enabledModIds = config.enabledByMod().entrySet().stream() + .filter(Map.Entry::getValue) + .map(Map.Entry::getKey) + .filter(id -> id != null && !id.isBlank()) + .map(String::trim) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + if (enabledModIds.isEmpty()) { + throw new ModtaleApiException(world.name() + " does not have any enabled mods to share."); + } + + List availableMods = installedMods.isEmpty() + ? worldManager.loadInstalledMods(settingsController.settings()) + : installedMods; + List items = LibraryWorldSnapshotMapper.itemsFor( + enabledModIds, + installedProjects, + availableMods + ); + + return new CreateWorldModListRequest( + world.name() + " mod list", + world.name(), + settingsController.settings().getGameVersion(), + items + ); + } + + private void copyShareUrl(String shareUrl) { + if (shareUrl == null || shareUrl.isBlank()) { + return; + } + ClipboardContent content = new ClipboardContent(); + content.putString(shareUrl); + Clipboard.getSystemClipboard().setContent(content); + } + + private static String worldKey(HytaleWorld world) { + return world == null || world.directory() == null + ? "" + : world.directory().toAbsolutePath().normalize().toString(); + } + + private static String installedProjectKey(InstalledProject installed) { + return installed == null + ? "" + : first(installed.projectId(), installed.slug(), installed.title()); + } + + static List installedProjectsExcept( + List projects, + InstalledProject excluded + ) { + if (projects == null || projects.isEmpty() || excluded == null) { + return projects == null ? List.of() : projects; + } + return projects.stream() + .filter(project -> !sameInstalledProject(project, excluded)) + .toList(); + } + + private static boolean sameInstalledProject(InstalledProject left, InstalledProject right) { + if (left == null || right == null) { + return false; + } + if (!left.projectId().isBlank() && left.projectId().equals(right.projectId())) { + return true; + } + if (!left.slug().isBlank() && left.slug().equals(right.slug())) { + return true; + } + return left.equals(right); + } + + private static String contentMeta(String author, String... values) { + List parts = new ArrayList<>(); + if (author != null && !author.isBlank()) { + parts.add("by " + author.trim()); + } + if (values != null) { + for (String value : values) { + if (value != null && !value.isBlank()) { + String normalized = value.trim(); + if (!parts.contains(normalized)) { + parts.add(normalized); + } + } + } + } + return parts.isEmpty() ? "Included in pack" : String.join(" - ", parts); + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + private static void addNormalized(Set keys, String value) { + String normalized = normalizedNameKey(value); + if (!normalized.isBlank()) { + keys.add(normalized); + } + } + + private static String fileName(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().replace('\\', '/'); + int query = normalized.indexOf('?'); + if (query >= 0) { + normalized = normalized.substring(0, query); + } + int slash = normalized.lastIndexOf('/'); + return slash >= 0 ? normalized.substring(slash + 1) : normalized; + } + + private static String normalizedNameKey(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().toLowerCase(java.util.Locale.ROOT) + .replaceFirst("(?i)\\.(jar|zip|hytale)$", ""); + return normalized.replaceAll("[^a-z0-9]+", ""); + } + + private static String normalizedFileKey(String file) { + if (file == null || file.isBlank()) { + return ""; + } + return normalizedFileKey(Path.of(file)); + } + + private static String normalizedFileKey(Path file) { + if (file == null) { + return ""; + } + return file.toAbsolutePath().normalize().toString(); + } + + private static String encodeQuery(String value) { + return URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8).replace("+", "%20"); + } + + private void renderUpdates() { + updatesList.getChildren().clear(); + if (currentUpdates.isEmpty()) { + updatesList.getChildren().add(emptyState("No updates queued", "Run an update check to compare your library with the catalog.")); + return; + } + currentUpdates.forEach(update -> updatesList.getChildren().add(listRenderer.updateRow(update))); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryBundledInstallNormalizer.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryBundledInstallNormalizer.java new file mode 100644 index 00000000..3520d7bb --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryBundledInstallNormalizer.java @@ -0,0 +1,297 @@ +package net.modtale.launcher.ui.library; + +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleInstalledMod; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; + +final class LibraryBundledInstallNormalizer { + + private LibraryBundledInstallNormalizer() { + } + + static Result normalize(List projects, List installedMods) { + if (projects == null || projects.isEmpty()) { + return new Result(List.of(), 0); + } + Map modsByFile = installedModsByFile(installedMods); + List normalized = new ArrayList<>(); + int addedChildren = 0; + for (InstalledProject project : projects) { + if (!shouldSplit(project)) { + normalized.add(project); + continue; + } + SplitResult split = split(project, modsByFile); + normalized.add(split.parent()); + normalized.addAll(split.children()); + addedChildren += split.children().size(); + } + return new Result(dedupe(normalized), addedChildren); + } + + private static boolean shouldSplit(InstalledProject project) { + return project != null + && !project.isModpack() + && (!project.bundledProjects().isEmpty() + || !project.dependencyProjectIds().isEmpty() + || !project.externalDependencies().isEmpty()); + } + + private static SplitResult split(InstalledProject parent, Map modsByFile) { + List references = references(parent); + Map> filesByReference = new LinkedHashMap<>(); + Set dependencyFiles = new LinkedHashSet<>(); + + for (String file : parent.files()) { + HytaleInstalledMod mod = modsByFile.get(normalizedFileKey(file)); + InstalledProjectReference reference = matchingReference(mod, file, references); + if (reference == null) { + continue; + } + String key = referenceKey(reference); + filesByReference.computeIfAbsent(key, ignored -> new ArrayList<>()).add(file); + dependencyFiles.add(normalizedFileKey(file)); + } + + if (filesByReference.isEmpty()) { + return new SplitResult(parent, List.of()); + } + + List parentFiles = parent.files().stream() + .filter(file -> !dependencyFiles.contains(normalizedFileKey(file))) + .toList(); + InstalledProject strippedParent = new InstalledProject( + parent.projectId(), + parent.slug(), + parent.title(), + parent.classification(), + parent.installedVersion(), + parent.installedVersionId(), + parent.gameVersion(), + parent.installedAt(), + parent.updatedAt(), + parentFiles.isEmpty() ? parent.files() : parentFiles, + List.of(), + List.of(), + parent.source(), + InstalledProject.INSTALL_DIRECT, + false, + List.of() + ); + + List children = new ArrayList<>(); + for (InstalledProjectReference reference : references) { + List files = filesByReference.get(referenceKey(reference)); + if (files == null || files.isEmpty()) { + continue; + } + children.add(childProject(parent, reference, files)); + } + return new SplitResult(strippedParent, children); + } + + private static InstalledProject childProject( + InstalledProject parent, + InstalledProjectReference reference, + List files + ) { + String projectId = reference.isModtaleProject() + ? reference.projectId() + : externalProjectId(reference); + return new InstalledProject( + projectId, + first(reference.slug(), projectId), + reference.displayName(), + first(reference.classification(), "PLUGIN"), + first(reference.versionNumber(), parent.installedVersion()), + "", + parent.gameVersion(), + safeInstant(parent.installedAt()), + safeInstant(parent.updatedAt()), + files, + List.of(), + List.of(), + reference.isModtaleProject() ? InstalledProject.SOURCE_MODTALE : first(reference.source(), InstalledProject.SOURCE_LOCAL), + InstalledProject.INSTALL_DIRECT, + false, + List.of() + ); + } + + private static String externalProjectId(InstalledProjectReference reference) { + return "external:" + sanitize(first( + reference.externalId(), + reference.id(), + reference.externalFileName(), + reference.displayName() + )); + } + + private static List dedupe(List projects) { + Map byProjectId = new LinkedHashMap<>(); + for (InstalledProject project : projects) { + if (project != null && !project.projectId().isBlank()) { + byProjectId.putIfAbsent(project.projectId(), project); + } + } + return List.copyOf(byProjectId.values()); + } + + private static List references(InstalledProject installed) { + if (!installed.bundledProjects().isEmpty()) { + return installed.bundledProjects(); + } + List references = new ArrayList<>(); + installed.dependencyProjectIds().forEach(id -> references.add(new InstalledProjectReference( + id, id, "", id, "", "", "", "MODTALE", "", "", "", "", "", "", null, null + ))); + installed.externalDependencies().forEach(id -> references.add(new InstalledProjectReference( + id, "", "", id, "", "", "", "EXTERNAL", id, "", "", "", "", "", null, null + ))); + return references; + } + + private static InstalledProjectReference matchingReference( + HytaleInstalledMod mod, + String file, + List references + ) { + if (mod == null || references == null || references.isEmpty()) { + return null; + } + Set modKeys = new LinkedHashSet<>(); + addNormalized(modKeys, mod.id()); + addNormalized(modKeys, mod.name()); + addNormalized(modKeys, fileName(file)); + for (InstalledProjectReference reference : references) { + Set referenceKeys = new LinkedHashSet<>(); + addNormalized(referenceKeys, LibraryProjectSupport.referenceWorldModId(reference)); + addNormalized(referenceKeys, reference.title()); + addNormalized(referenceKeys, reference.slug()); + addNormalized(referenceKeys, reference.projectId()); + addNormalized(referenceKeys, reference.externalId()); + addNormalized(referenceKeys, reference.externalFileName()); + addNormalized(referenceKeys, fileName(reference.externalFileUrl())); + addNormalized(referenceKeys, fileName(reference.cachedFileUrl())); + for (String key : modKeys) { + if (referenceKeys.contains(key)) { + return reference; + } + } + } + return null; + } + + private static Map installedModsByFile(List mods) { + Map byFile = new LinkedHashMap<>(); + if (mods == null) { + return byFile; + } + for (HytaleInstalledMod mod : mods) { + String key = normalizedFileKey(mod.file()); + if (!key.isBlank()) { + byFile.putIfAbsent(key, mod); + } + } + return byFile; + } + + private static void addNormalized(Set keys, String value) { + String normalized = normalizedNameKey(value); + if (!normalized.isBlank()) { + keys.add(normalized); + } + } + + private static String referenceKey(InstalledProjectReference reference) { + return first( + reference.projectId(), + reference.externalId(), + reference.id(), + reference.slug(), + reference.displayName() + ); + } + + private static String fileName(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().replace('\\', '/'); + int query = normalized.indexOf('?'); + if (query >= 0) { + normalized = normalized.substring(0, query); + } + int slash = normalized.lastIndexOf('/'); + return slash >= 0 ? normalized.substring(slash + 1) : normalized; + } + + private static String normalizedNameKey(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().toLowerCase(Locale.ROOT) + .replaceFirst("(?i)\\.(jar|zip|hytale)$", ""); + return normalized.replaceAll("[^a-z0-9]+", ""); + } + + private static String normalizedFileKey(String file) { + if (file == null || file.isBlank()) { + return ""; + } + return normalizedFileKey(Path.of(file)); + } + + private static String normalizedFileKey(Path file) { + if (file == null) { + return ""; + } + return file.toAbsolutePath().normalize().toString(); + } + + private static String sanitize(String value) { + String normalized = value == null ? "" : value.trim(); + if (normalized.isBlank()) { + return "dependency"; + } + return normalized.replaceAll("[^A-Za-z0-9._:-]+", "-").toLowerCase(Locale.ROOT); + } + + private static Instant safeInstant(Instant instant) { + return instant == null ? Instant.EPOCH : instant; + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + record Result(List projects, int addedChildren) { + Result { + projects = projects == null ? List.of() : List.copyOf(projects); + addedChildren = Math.max(0, addedChildren); + } + } + + private record SplitResult(InstalledProject parent, List children) { + private SplitResult { + children = children == null ? List.of() : List.copyOf(children); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryDetailModel.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryDetailModel.java new file mode 100644 index 00000000..db4406f9 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryDetailModel.java @@ -0,0 +1,22 @@ +package net.modtale.launcher.ui.library; + +import java.util.List; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.UpdateCandidate; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.settings.LauncherSettings; + +record LibraryDetailModel( + InstalledProject installed, + ProjectDetail detail, + UpdateCandidate update, + boolean loading, + LauncherSettings settings, + List installedProjects, + List worldToggles +) { + LibraryDetailModel { + installedProjects = installedProjects == null ? List.of() : List.copyOf(installedProjects); + worldToggles = worldToggles == null ? List.of() : List.copyOf(worldToggles); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryLocalInstallRecovery.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryLocalInstallRecovery.java new file mode 100644 index 00000000..0441bd42 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryLocalInstallRecovery.java @@ -0,0 +1,215 @@ +package net.modtale.launcher.ui.library; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleInstalledMod; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.settings.LauncherSettings; + +final class LibraryLocalInstallRecovery { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private LibraryLocalInstallRecovery() { + } + + static RecoveryResult recover( + LauncherSettings settings, + List recordedProjects, + List installedMods + ) { + List recorded = recordedProjects == null ? List.of() : List.copyOf(recordedProjects); + if (installedMods == null || installedMods.isEmpty()) { + return new RecoveryResult(recorded, 0); + } + + Map byProjectId = new LinkedHashMap<>(); + Set recordedFiles = new LinkedHashSet<>(); + for (InstalledProject project : recorded) { + if (project == null || project.projectId().isBlank()) { + continue; + } + byProjectId.put(project.projectId(), project); + project.files().stream() + .map(LibraryLocalInstallRecovery::normalizedPath) + .filter(path -> !path.isBlank()) + .forEach(recordedFiles::add); + } + + int recovered = 0; + for (HytaleInstalledMod mod : installedMods) { + String fileKey = normalizedPath(mod.file()); + if (fileKey.isBlank() || recordedFiles.contains(fileKey)) { + continue; + } + InstalledProject project = fromInstalledMod(settings, mod, byProjectId.keySet()); + byProjectId.put(project.projectId(), project); + recordedFiles.add(fileKey); + recovered++; + } + return new RecoveryResult(List.copyOf(byProjectId.values()), recovered); + } + + private static InstalledProject fromInstalledMod( + LauncherSettings settings, + HytaleInstalledMod mod, + Set existingProjectIds + ) { + String title = first(mod.name(), fileBaseName(mod.file()), "Local Mod"); + String manifestId = first(mod.id(), title); + ManifestMetadata manifest = manifestMetadata(mod.file()); + String modtaleSlug = modtaleSlug(manifest.website()); + boolean modtaleProject = !modtaleSlug.isBlank(); + String projectId = uniqueProjectId(modtaleProject ? modtaleSlug : "local:" + sanitize(manifestId), existingProjectIds); + Instant modifiedAt = lastModified(mod.file()); + return new InstalledProject( + projectId, + modtaleProject ? modtaleSlug : manifestId, + title, + "PLUGIN", + first(mod.version(), "installed"), + "", + settings == null ? "" : settings.getGameVersion(), + modifiedAt, + modifiedAt, + List.of(mod.file().toString()), + List.of(), + List.of(), + modtaleProject ? InstalledProject.SOURCE_MODTALE : InstalledProject.SOURCE_LOCAL, + InstalledProject.INSTALL_DIRECT, + false, + List.of() + ); + } + + private static String uniqueProjectId(String base, Set existingProjectIds) { + String id = base == null || base.isBlank() ? "local:mod" : base; + if (!existingProjectIds.contains(id)) { + return id; + } + int suffix = 2; + while (existingProjectIds.contains(id + "-" + suffix)) { + suffix++; + } + return id + "-" + suffix; + } + + private static Instant lastModified(Path path) { + try { + return Files.getLastModifiedTime(path).toInstant(); + } catch (IOException ignored) { + return Instant.now(); + } + } + + private static ManifestMetadata manifestMetadata(Path jar) { + if (jar == null || !Files.isRegularFile(jar)) { + return new ManifestMetadata("", ""); + } + try (ZipFile zip = new ZipFile(jar.toFile())) { + ZipEntry manifest = zip.getEntry("manifest.json"); + if (manifest == null) { + return new ManifestMetadata("", ""); + } + try (InputStream input = zip.getInputStream(manifest)) { + JsonNode root = MAPPER.readTree(input); + String author = ""; + JsonNode authors = root.path("Authors"); + if (authors.isArray() && !authors.isEmpty()) { + author = authors.get(0).path("Name").asText(""); + } + return new ManifestMetadata(root.path("Website").asText(""), author); + } + } catch (IOException ignored) { + return new ManifestMetadata("", ""); + } + } + + private static String modtaleSlug(String website) { + if (website == null || website.isBlank()) { + return ""; + } + String value = website.trim(); + int marker = value.toLowerCase(Locale.ROOT).indexOf("modtale.net/mod/"); + if (marker < 0) { + return ""; + } + String slug = value.substring(marker + "modtale.net/mod/".length()); + for (String delimiter : new String[]{"/", "?", "#"}) { + int index = slug.indexOf(delimiter); + if (index >= 0) { + slug = slug.substring(0, index); + } + } + return sanitize(slug); + } + + private static String fileBaseName(Path path) { + if (path == null || path.getFileName() == null) { + return ""; + } + return path.getFileName().toString().replaceFirst("(?i)\\.jar$", ""); + } + + private static String normalizedPath(Path path) { + if (path == null) { + return ""; + } + return path.toAbsolutePath().normalize().toString(); + } + + private static String normalizedPath(String path) { + if (path == null || path.isBlank()) { + return ""; + } + return Path.of(path).toAbsolutePath().normalize().toString(); + } + + private static String sanitize(String value) { + String normalized = value == null ? "" : value.trim(); + if (normalized.isBlank()) { + return "mod"; + } + return normalized.replaceAll("[^A-Za-z0-9._:-]+", "-").toLowerCase(Locale.ROOT); + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + record RecoveryResult(List projects, int recoveredCount) { + RecoveryResult { + projects = projects == null ? List.of() : List.copyOf(projects); + recoveredCount = Math.max(0, recoveredCount); + } + } + + private record ManifestMetadata(String website, String author) { + private ManifestMetadata { + website = website == null ? "" : website.trim(); + author = author == null ? "" : author.trim(); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryModpackUnlockConverter.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryModpackUnlockConverter.java new file mode 100644 index 00000000..ee986a9f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryModpackUnlockConverter.java @@ -0,0 +1,363 @@ +package net.modtale.launcher.ui.library; + +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleInstalledMod; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; + +final class LibraryModpackUnlockConverter { + + private LibraryModpackUnlockConverter() { + } + + static Result convert( + List projects, + InstalledProject modpack, + List installedMods + ) { + if (modpack == null || !modpack.isModpack()) { + return new Result(projects == null ? List.of() : projects, 0); + } + + List children = childProjects(modpack, installedMods); + if (children.isEmpty()) { + return new Result(projects == null ? List.of() : projects, 0); + } + + Map converted = new LinkedHashMap<>(); + if (projects != null) { + for (InstalledProject project : projects) { + if (project == null || sameProject(project, modpack)) { + continue; + } + converted.put(project.projectId(), project); + } + } + for (InstalledProject child : children) { + converted.merge(child.projectId(), child, LibraryModpackUnlockConverter::mergeProject); + } + return new Result(List.copyOf(converted.values()), children.size()); + } + + private static List childProjects(InstalledProject modpack, List installedMods) { + Map modsByFile = installedModsByFile(installedMods); + List references = references(modpack); + Map> filesByReference = new LinkedHashMap<>(); + Set matchedFiles = new LinkedHashSet<>(); + + for (String file : modpack.files()) { + HytaleInstalledMod mod = modsByFile.get(normalizedFileKey(file)); + InstalledProjectReference reference = matchingReference(mod, file, references); + if (reference == null) { + continue; + } + filesByReference.computeIfAbsent(referenceKey(reference), ignored -> new ArrayList<>()).add(file); + matchedFiles.add(normalizedFileKey(file)); + } + + List children = new ArrayList<>(); + for (InstalledProjectReference reference : references) { + List files = filesByReference.get(referenceKey(reference)); + if (files != null && !files.isEmpty()) { + children.add(referenceProject(modpack, reference, files)); + } + } + + for (String file : modpack.files()) { + if (matchedFiles.contains(normalizedFileKey(file))) { + continue; + } + HytaleInstalledMod mod = modsByFile.get(normalizedFileKey(file)); + children.add(mod == null + ? fileProject(modpack, file) + : manifestProject(modpack, mod, file)); + } + + if (children.isEmpty()) { + for (InstalledProjectReference reference : references) { + children.add(referenceProject(modpack, reference, List.of())); + } + } + return dedupe(children); + } + + private static InstalledProject referenceProject( + InstalledProject parent, + InstalledProjectReference reference, + List files + ) { + String projectId = reference.isModtaleProject() + ? reference.projectId() + : externalProjectId(reference); + return new InstalledProject( + projectId, + first(reference.slug(), projectId), + reference.displayName(), + first(reference.classification(), "PLUGIN"), + first(reference.versionNumber(), parent.installedVersion()), + "", + parent.gameVersion(), + safeInstant(parent.installedAt()), + safeInstant(parent.updatedAt()), + files, + List.of(), + List.of(), + reference.isModtaleProject() ? InstalledProject.SOURCE_MODTALE : first(reference.source(), InstalledProject.SOURCE_LOCAL), + InstalledProject.INSTALL_DIRECT, + false, + List.of() + ); + } + + private static InstalledProject manifestProject(InstalledProject parent, HytaleInstalledMod mod, String file) { + String id = first(mod.id(), fileProjectId(file)); + return new InstalledProject( + id, + id, + first(mod.name(), id), + "PLUGIN", + first(mod.version(), parent.installedVersion()), + "", + parent.gameVersion(), + safeInstant(parent.installedAt()), + safeInstant(parent.updatedAt()), + List.of(file), + List.of(), + List.of(), + InstalledProject.SOURCE_LOCAL, + InstalledProject.INSTALL_DIRECT, + false, + List.of() + ); + } + + private static InstalledProject fileProject(InstalledProject parent, String file) { + String fileName = fileName(file); + String id = fileProjectId(file); + return new InstalledProject( + id, + id, + first(fileName.replaceFirst("(?i)\\.jar$", ""), "Installed mod"), + "PLUGIN", + parent.installedVersion(), + "", + parent.gameVersion(), + safeInstant(parent.installedAt()), + safeInstant(parent.updatedAt()), + List.of(file), + List.of(), + List.of(), + InstalledProject.SOURCE_LOCAL, + InstalledProject.INSTALL_DIRECT, + false, + List.of() + ); + } + + private static InstalledProject mergeProject(InstalledProject existing, InstalledProject child) { + LinkedHashSet files = new LinkedHashSet<>(existing.files()); + files.addAll(child.files()); + return new InstalledProject( + existing.projectId(), + first(existing.slug(), child.slug()), + first(existing.title(), child.title()), + first(existing.classification(), child.classification()), + first(existing.installedVersion(), child.installedVersion()), + first(existing.installedVersionId(), child.installedVersionId()), + first(existing.gameVersion(), child.gameVersion()), + safeInstant(existing.installedAt()), + later(existing.updatedAt(), child.updatedAt()), + List.copyOf(files), + List.of(), + List.of(), + first(existing.source(), child.source(), InstalledProject.SOURCE_MODTALE), + InstalledProject.INSTALL_DIRECT, + false, + List.of() + ); + } + + private static List dedupe(List projects) { + Map byProjectId = new LinkedHashMap<>(); + for (InstalledProject project : projects) { + if (project != null && !project.projectId().isBlank()) { + byProjectId.merge(project.projectId(), project, LibraryModpackUnlockConverter::mergeProject); + } + } + return List.copyOf(byProjectId.values()); + } + + private static List references(InstalledProject installed) { + if (!installed.bundledProjects().isEmpty()) { + return installed.bundledProjects(); + } + List references = new ArrayList<>(); + installed.dependencyProjectIds().forEach(id -> references.add(new InstalledProjectReference( + id, id, "", id, "", "", "", "MODTALE", "", "", "", "", "", "", null, null + ))); + installed.externalDependencies().forEach(id -> references.add(new InstalledProjectReference( + id, "", "", id, "", "", "", "EXTERNAL", id, "", "", "", "", "", null, null + ))); + return references; + } + + private static InstalledProjectReference matchingReference( + HytaleInstalledMod mod, + String file, + List references + ) { + if (mod == null || references == null || references.isEmpty()) { + return null; + } + Set modKeys = new LinkedHashSet<>(); + addNormalized(modKeys, mod.id()); + addNormalized(modKeys, mod.name()); + addNormalized(modKeys, fileName(file)); + for (InstalledProjectReference reference : references) { + Set referenceKeys = new LinkedHashSet<>(); + addNormalized(referenceKeys, LibraryProjectSupport.referenceWorldModId(reference)); + addNormalized(referenceKeys, reference.title()); + addNormalized(referenceKeys, reference.slug()); + addNormalized(referenceKeys, reference.projectId()); + addNormalized(referenceKeys, reference.externalId()); + addNormalized(referenceKeys, reference.externalFileName()); + addNormalized(referenceKeys, fileName(reference.externalFileUrl())); + addNormalized(referenceKeys, fileName(reference.cachedFileUrl())); + for (String key : modKeys) { + if (referenceKeys.contains(key)) { + return reference; + } + } + } + return null; + } + + private static Map installedModsByFile(List mods) { + Map byFile = new LinkedHashMap<>(); + if (mods == null) { + return byFile; + } + for (HytaleInstalledMod mod : mods) { + String key = normalizedFileKey(mod.file()); + if (!key.isBlank()) { + byFile.putIfAbsent(key, mod); + } + } + return byFile; + } + + private static boolean sameProject(InstalledProject left, InstalledProject right) { + return left != null && right != null && left.projectId().equals(right.projectId()); + } + + private static String externalProjectId(InstalledProjectReference reference) { + return "external:" + sanitize(first( + reference.externalId(), + reference.id(), + reference.externalFileName(), + reference.displayName() + )); + } + + private static String fileProjectId(String file) { + return "local:" + sanitize(fileName(file).replaceFirst("(?i)\\.jar$", "")); + } + + private static void addNormalized(Set keys, String value) { + String normalized = normalizedNameKey(value); + if (!normalized.isBlank()) { + keys.add(normalized); + } + } + + private static String referenceKey(InstalledProjectReference reference) { + return first( + reference.projectId(), + reference.externalId(), + reference.id(), + reference.slug(), + reference.displayName() + ); + } + + private static String fileName(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().replace('\\', '/'); + int query = normalized.indexOf('?'); + if (query >= 0) { + normalized = normalized.substring(0, query); + } + int slash = normalized.lastIndexOf('/'); + return slash >= 0 ? normalized.substring(slash + 1) : normalized; + } + + private static String normalizedNameKey(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().toLowerCase(Locale.ROOT) + .replaceFirst("(?i)\\.(jar|zip|hytale)$", ""); + return normalized.replaceAll("[^a-z0-9]+", ""); + } + + private static String normalizedFileKey(String file) { + if (file == null || file.isBlank()) { + return ""; + } + return normalizedFileKey(Path.of(file)); + } + + private static String normalizedFileKey(Path file) { + if (file == null) { + return ""; + } + return file.toAbsolutePath().normalize().toString(); + } + + private static String sanitize(String value) { + String normalized = value == null ? "" : value.trim(); + if (normalized.isBlank()) { + return "mod"; + } + return normalized.replaceAll("[^A-Za-z0-9._:-]+", "-").toLowerCase(Locale.ROOT); + } + + private static Instant safeInstant(Instant instant) { + return instant == null ? Instant.EPOCH : instant; + } + + private static Instant later(Instant left, Instant right) { + Instant safeLeft = safeInstant(left); + Instant safeRight = safeInstant(right); + return safeRight.isAfter(safeLeft) ? safeRight : safeLeft; + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + record Result(List projects, int convertedCount) { + Result { + projects = projects == null ? List.of() : List.copyOf(projects); + convertedCount = Math.max(0, convertedCount); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectListRenderer.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectListRenderer.java new file mode 100644 index 00000000..4c1230ec --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectListRenderer.java @@ -0,0 +1,87 @@ +package net.modtale.launcher.ui.library; + +import static net.modtale.launcher.ui.common.LauncherUi.classificationLabel; +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; +import static net.modtale.launcher.ui.common.LauncherUi.setVisibleManaged; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.util.function.Consumer; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.UpdateCandidate; +import net.modtale.launcher.model.project.ProjectClassification; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class LibraryProjectListRenderer { + + private final Consumer selectProject; + private final Consumer updateProject; + + LibraryProjectListRenderer(Consumer selectProject, Consumer updateProject) { + this.selectProject = selectProject; + this.updateProject = updateProject; + } + + Button projectRow(InstalledProject project, boolean selected, boolean hasUpdate) { + Button button = new Button(); + button.getStyleClass().add("library-project-row"); + button.setMaxWidth(Double.MAX_VALUE); + button.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + button.setGraphic(projectRowContent(project, hasUpdate)); + button.setOnAction(event -> selectProject.accept(project.projectId())); + pseudo(button, "selected", selected); + pseudo(button, "update", hasUpdate); + return button; + } + + Node updateRow(UpdateCandidate update) { + HBox row = net.modtale.launcher.ui.common.LauncherUi.rowCard(update.title(), + classificationLabel(update.installedProject().classification()) + " - " + + value(update.currentVersion(), "current") + " -> " + value(update.newestVersionNumber(), "latest")); + Button updateButton = primaryButton("Update"); + updateButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 14)); + updateButton.setOnAction(event -> updateProject.accept(update)); + row.getChildren().add(updateButton); + return row; + } + + private Node projectRowContent(InstalledProject project, boolean hasUpdate) { + HBox row = new HBox(12); + row.getStyleClass().add("library-project-row-content"); + StackPane icon = projectIcon(project.classification(), 18); + icon.getStyleClass().add("library-project-icon"); + VBox copy = new VBox(4); + Label title = new Label(value(project.title(), "Untitled Project")); + title.getStyleClass().add("library-project-title"); + Label meta = new Label(LibraryProjectSupport.projectRowMeta(project)); + meta.getStyleClass().add("library-project-meta"); + copy.getChildren().addAll(title, meta); + HBox.setHgrow(copy, Priority.ALWAYS); + VBox status = new VBox(5); + status.setAlignment(Pos.CENTER_RIGHT); + Label version = new Label(value(project.installedVersion(), "installed")); + version.getStyleClass().add("library-version-pill"); + Label update = new Label(hasUpdate ? "Update" : ""); + update.getStyleClass().add("library-update-pill"); + setVisibleManaged(update, hasUpdate); + status.getChildren().addAll(version, update); + row.getChildren().addAll(icon, copy, status); + return row; + } + + private StackPane projectIcon(String classification, double size) { + LauncherIcons.Glyph glyph = ProjectClassification.isModpack(classification) + ? LauncherIcons.Glyph.LAYERS + : LauncherIcons.Glyph.BOX; + return new StackPane(LauncherIcons.icon(glyph, size)); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectRenderer.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectRenderer.java new file mode 100644 index 00000000..16c891ce --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectRenderer.java @@ -0,0 +1,469 @@ +package net.modtale.launcher.ui.library; + +import static net.modtale.launcher.ui.common.LauncherUi.classificationLabel; +import static net.modtale.launcher.ui.common.LauncherUi.dangerButton; +import static net.modtale.launcher.ui.common.LauncherUi.emptyState; +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.secondaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.styleCombo; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import javafx.collections.FXCollections; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.geometry.Pos; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; +import net.modtale.launcher.model.install.UpdateCandidate; +import net.modtale.launcher.model.project.ProjectClassification; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.ui.common.LauncherExternalLinks; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class LibraryProjectRenderer { + + private final Consumer selectProject; + private final Consumer updateProject; + private final VersionSwitchHandler switchVersion; + private final Consumer uninstallProject; + private final UnlockHandler unlockProject; + private final WorldToggleHandler toggleWorldMods; + private final Consumer shareWorldSnapshot; + private final Consumer createModpackFromWorld; + private final BiConsumer toast; + + LibraryProjectRenderer( + Consumer selectProject, + Consumer updateProject, + VersionSwitchHandler switchVersion, + Consumer uninstallProject, + UnlockHandler unlockProject, + WorldToggleHandler toggleWorldMods, + Consumer shareWorldSnapshot, + Consumer createModpackFromWorld, + BiConsumer toast + ) { + this.selectProject = selectProject; + this.updateProject = updateProject; + this.switchVersion = switchVersion; + this.uninstallProject = uninstallProject; + this.unlockProject = unlockProject; + this.toggleWorldMods = toggleWorldMods; + this.shareWorldSnapshot = shareWorldSnapshot; + this.createModpackFromWorld = createModpackFromWorld; + this.toast = toast; + } + + List projectDetail(LibraryDetailModel model) { + if (model == null || model.installed() == null) { + return List.of(emptyState("No project selected", "Install a project from Browse.")); + } + InstalledProject installed = model.installed(); + List sections = new ArrayList<>(); + sections.add(detailHeader(installed, model.update())); + sections.add(versionSection(model)); + Node contents = bundledProjectsSection(model); + if (contents != null) { + sections.add(contents); + } + sections.add(worldsSection(model)); + sections.add(filesSection(installed)); + return sections; + } + + private Node detailHeader(InstalledProject installed, UpdateCandidate update) { + VBox section = new VBox(12); + section.getStyleClass().add("library-detail-hero"); + + HBox row = new HBox(14); + row.getStyleClass().add("library-detail-heading"); + StackPane icon = projectIcon(installed.classification(), 22); + icon.getStyleClass().add("library-detail-icon"); + VBox copy = new VBox(7); + Label title = new Label(value(installed.title(), "Untitled Project")); + title.getStyleClass().add("library-detail-title"); + HBox badges = new HBox(7); + badges.getStyleClass().add("library-badge-row"); + badges.getChildren().add(badge(classificationLabel(installed.classification()), "type")); + badges.getChildren().add(badge(value(installed.installedVersion(), "installed"), "version")); + if (!installed.gameVersion().isBlank()) { + badges.getChildren().add(badge(installed.gameVersion(), "game")); + } + if (installed.isModpack()) { + badges.getChildren().add(badge("Grouped", "locked")); + } + copy.getChildren().addAll(title, badges); + HBox.setHgrow(copy, Priority.ALWAYS); + + VBox actions = new VBox(8); + actions.getStyleClass().add("library-actions"); + HBox mainActions = new HBox(8); + if (update != null) { + Button updateButton = primaryButton("Update"); + updateButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 14)); + updateButton.setTooltip(new Tooltip("Install " + update.newestVersionNumber())); + updateButton.setOnAction(event -> updateProject.accept(update)); + mainActions.getChildren().add(updateButton); + } + Button uninstall = dangerButton("Remove"); + uninstall.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.TRASH, 14)); + uninstall.setMaxWidth(Double.MAX_VALUE); + uninstall.setOnAction(event -> uninstallProject.accept(installed)); + if (!mainActions.getChildren().isEmpty()) { + actions.getChildren().add(mainActions); + } + actions.getChildren().add(uninstall); + row.getChildren().addAll(icon, copy, actions); + + HBox facts = new HBox(10); + facts.getStyleClass().add("library-facts"); + facts.getChildren().addAll( + fact("Installed", LibraryProjectSupport.dateLabel(installed.installedAt())), + fact("Updated", LibraryProjectSupport.dateLabel(installed.updatedAt())), + fact("Files", Integer.toString(installed.files().size())), + fact("Contents", Integer.toString(LibraryProjectSupport.contentCount(installed))) + ); + section.getChildren().addAll(row, facts); + return section; + } + + private Node versionSection(LibraryDetailModel model) { + InstalledProject installed = model.installed(); + ProjectDetail detail = model.detail(); + VBox section = detailSection("Versions"); + if (detail == null) { + HBox loading = new HBox(10); + loading.getStyleClass().add("library-inline-panel"); + loading.setAlignment(Pos.CENTER_LEFT); + Label meta = new Label(model.loading() ? "Loading release metadata" : "Release metadata not loaded"); + meta.getStyleClass().add("library-muted-text"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Button load = secondaryButton(model.loading() ? "Loading" : "Load"); + load.setDisable(true); + loading.getChildren().addAll(meta, spacer, load); + section.getChildren().add(loading); + return section; + } + + List choices = LibraryProjectSupport.versionChoices( + detail.versions(), + installed, + model.settings().getGameVersion() + ); + ComboBox versions = new ComboBox<>(FXCollections.observableArrayList(choices)); + styleCombo(versions); + choices.stream() + .filter(choice -> LibraryProjectSupport.sameVersion(installed, choice.version())) + .findFirst() + .ifPresentOrElse(versions::setValue, () -> { + if (!choices.isEmpty()) { + versions.setValue(choices.getFirst()); + } + }); + + Button switchButton = primaryButton("Switch"); + switchButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 14)); + switchButton.setOnAction(event -> { + LibraryVersionChoice choice = versions.getValue(); + if (choice != null) { + switchVersion.switchVersion(installed, detail, choice.version()); + } + }); + Runnable updateSwitchState = () -> { + LibraryVersionChoice choice = versions.getValue(); + switchButton.setDisable(choice == null || LibraryProjectSupport.sameVersion(installed, choice.version())); + }; + versions.valueProperty().addListener((observable, previous, next) -> updateSwitchState.run()); + updateSwitchState.run(); + + HBox row = new HBox(10, versions, switchButton); + row.getStyleClass().add("library-version-control"); + HBox.setHgrow(versions, Priority.ALWAYS); + section.getChildren().add(row); + return section; + } + + private Node bundledProjectsSection(LibraryDetailModel model) { + InstalledProject installed = model.installed(); + if (!installed.isModpack() + && installed.bundledProjects().isEmpty() + && installed.dependencyProjectIds().isEmpty() + && installed.externalDependencies().isEmpty()) { + return null; + } + VBox section = detailSection(installed.isModpack() ? "Modpack Contents" : "Bundled Dependencies"); + HBox header = new HBox(10); + header.getStyleClass().add("library-inline-panel"); + header.setAlignment(Pos.CENTER_LEFT); + Label status = new Label("Grouped"); + status.getStyleClass().add("library-status-locked"); + int contentCount = LibraryProjectSupport.contentCount(installed); + Label count = new Label(contentCount + " item" + LibraryProjectSupport.plural(contentCount)); + count.getStyleClass().add("library-muted-text"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Button lock = secondaryButton("Unlock"); + lock.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.EDIT, 14)); + lock.setOnAction(event -> unlockProject.unlock(installed)); + header.getChildren().addAll(status, count, spacer, lock); + section.getChildren().add(header); + + VBox rows = new VBox(8); + rows.getStyleClass().add("library-bundled-list"); + if (!installed.bundledProjects().isEmpty()) { + installed.bundledProjects().forEach(reference -> + rows.getChildren().add(bundledProjectRow(model, reference))); + } else if (!installed.dependencyProjectIds().isEmpty() || !installed.externalDependencies().isEmpty()) { + installed.dependencyProjectIds().forEach(id -> rows.getChildren().add(legacyBundledRow(model, id, true))); + installed.externalDependencies().forEach(id -> rows.getChildren().add(legacyBundledRow(model, id, false))); + } else { + installed.files().forEach(file -> rows.getChildren().add(fileContentRow(installed, file))); + } + section.getChildren().add(rows); + return section; + } + + private Node bundledProjectRow(LibraryDetailModel model, InstalledProjectReference reference) { + InstalledProject parent = model.installed(); + HBox row = new HBox(10); + row.getStyleClass().add("library-bundled-row-locked"); + row.setAlignment(Pos.CENTER_LEFT); + StackPane icon = new StackPane(LauncherIcons.icon(reference.isModtaleProject() + ? LauncherIcons.Glyph.BOX + : LauncherIcons.Glyph.EXTERNAL_LINK, 15)); + icon.getStyleClass().add("library-child-icon"); + VBox copy = new VBox(3); + Label title = new Label(reference.displayName()); + title.getStyleClass().add("library-child-title"); + Label meta = new Label(LibraryProjectSupport.childMeta(reference)); + meta.getStyleClass().add("library-child-meta"); + copy.getChildren().addAll(title, meta); + HBox.setHgrow(copy, Priority.ALWAYS); + + InstalledProject installedChild = reference.projectId().isBlank() + ? null + : installedByProjectId(model.installedProjects(), reference.projectId()).orElse(null); + Button action = childActionButton(parent, reference, installedChild); + row.getChildren().addAll(icon, copy, action); + return row; + } + + private Node legacyBundledRow(LibraryDetailModel model, String id, boolean modtale) { + InstalledProjectReference reference = new InstalledProjectReference( + id, + modtale ? id : "", + "", + id, + "", + "", + "", + modtale ? "MODTALE" : "EXTERNAL", + modtale ? "" : id, + "", + "", + "", + "", + "", + null, + null + ); + return bundledProjectRow(model, reference); + } + + private Node fileContentRow(InstalledProject parent, String file) { + HBox row = new HBox(10); + row.getStyleClass().add("library-bundled-row-locked"); + row.setAlignment(Pos.CENTER_LEFT); + StackPane icon = new StackPane(LauncherIcons.icon(LauncherIcons.Glyph.FILE_CODE, 15)); + icon.getStyleClass().add("library-child-icon"); + VBox copy = new VBox(3); + Label title = new Label(Path.of(file).getFileName().toString()); + title.getStyleClass().add("library-child-title"); + Label meta = new Label("Installed file"); + meta.getStyleClass().add("library-child-meta"); + copy.getChildren().addAll(title, meta); + HBox.setHgrow(copy, Priority.ALWAYS); + Button action = secondaryButton("Grouped"); + action.setDisable(true); + row.getChildren().addAll(icon, copy, action); + return row; + } + + private Button childActionButton( + InstalledProject parent, + InstalledProjectReference reference, + InstalledProject installedChild + ) { + Button action; + if (installedChild != null) { + action = secondaryButton("Select"); + action.setOnAction(event -> selectProject.accept(installedChild.projectId())); + return action; + } + if (reference.isModtaleProject()) { + action = secondaryButton("Included"); + action.setDisable(true); + return action; + } + action = secondaryButton("Open"); + action.setOnAction(event -> LauncherExternalLinks.open( + value(reference.externalUrl(), reference.cachedFileUrl()), + toast + )); + action.setDisable(reference.externalUrl().isBlank() && reference.cachedFileUrl().isBlank()); + return action; + } + + private Node worldsSection(LibraryDetailModel model) { + VBox section = detailSection("Worlds"); + if (model.worldToggles().isEmpty()) { + section.getChildren().add(emptyState("No world controls", "Create a Hytale world or refresh this install record.")); + return section; + } + VBox rows = new VBox(8); + rows.getStyleClass().add("library-world-list"); + for (LibraryWorldToggle toggle : model.worldToggles()) { + rows.getChildren().add(worldToggleRow(toggle)); + } + section.getChildren().add(rows); + return section; + } + + private Node worldToggleRow(LibraryWorldToggle worldToggle) { + LibraryToggleBox toggle = new LibraryToggleBox(); + toggle.setSelected(worldToggle.selected()); + toggle.setIndeterminate(worldToggle.indeterminate()); + toggle.setOnAction(() -> toggleWorldMods.setEnabled( + worldToggle.world(), + worldToggle.modIds(), + toggle.isSelected() + )); + + VBox copy = new VBox(3); + Label title = new Label(worldToggle.world().name()); + title.getStyleClass().add("library-world-title"); + Label meta = new Label(worldToggle.enabledCount() + "/" + worldToggle.totalCount() + " enabled - " + worldToggle.meta()); + meta.getStyleClass().add("library-world-meta"); + copy.getChildren().addAll(title, meta); + HBox.setHgrow(copy, Priority.ALWAYS); + + Button share = secondaryButton("Share"); + share.getStyleClass().add("library-world-share"); + share.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.SHARE_2, 13)); + share.setTooltip(new Tooltip("Copy a share link for this world's enabled mods")); + share.setOnAction(event -> shareWorldSnapshot.accept(worldToggle.world())); + + Button pack = secondaryButton("Make Pack"); + pack.getStyleClass().add("library-world-pack"); + pack.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.PACKAGE_PLUS, 13)); + pack.setTooltip(new Tooltip("Start a Modtale modpack from this world's enabled mods")); + pack.setOnAction(event -> createModpackFromWorld.accept(worldToggle.world())); + + HBox row = new HBox(10, toggle, copy, share, pack); + row.getStyleClass().add("library-world-row"); + row.setAlignment(Pos.CENTER_LEFT); + return row; + } + + private Node filesSection(InstalledProject installed) { + VBox section = detailSection("Files"); + if (installed.files().isEmpty()) { + section.getChildren().add(emptyState("No files recorded", "Switching versions will refresh this install record.")); + return section; + } + VBox files = new VBox(6); + files.getStyleClass().add("library-file-list"); + installed.files().stream() + .limit(8) + .forEach(file -> files.getChildren().add(fileRow(file))); + if (installed.files().size() > 8) { + Label remaining = new Label("+" + (installed.files().size() - 8) + " more"); + remaining.getStyleClass().add("library-muted-text"); + files.getChildren().add(remaining); + } + section.getChildren().add(files); + return section; + } + + private Node fileRow(String file) { + HBox row = new HBox(8); + row.getStyleClass().add("library-file-row"); + row.setAlignment(Pos.CENTER_LEFT); + Label name = new Label(Path.of(file).getFileName().toString()); + name.getStyleClass().add("library-file-name"); + Label path = new Label(file); + path.getStyleClass().add("library-file-path"); + HBox.setHgrow(path, Priority.ALWAYS); + row.getChildren().addAll(LauncherIcons.icon(LauncherIcons.Glyph.FILE_CODE, 14), name, path); + return row; + } + + private VBox detailSection(String title) { + VBox section = new VBox(10); + section.getStyleClass().add("library-detail-section"); + Label label = new Label(title); + label.getStyleClass().add("library-section-title"); + section.getChildren().add(label); + return section; + } + + private Node fact(String label, String value) { + VBox fact = new VBox(3); + fact.getStyleClass().add("library-fact"); + Label title = new Label(label); + title.getStyleClass().add("library-fact-label"); + Label body = new Label(value); + body.getStyleClass().add("library-fact-value"); + fact.getChildren().addAll(title, body); + HBox.setHgrow(fact, Priority.ALWAYS); + return fact; + } + + private Node badge(String text, String tone) { + Label label = new Label(text); + label.getStyleClass().addAll("library-badge", "library-badge-" + tone); + return label; + } + + private StackPane projectIcon(String classification, double size) { + LauncherIcons.Glyph glyph = ProjectClassification.isModpack(classification) + ? LauncherIcons.Glyph.LAYERS + : LauncherIcons.Glyph.BOX; + return new StackPane(LauncherIcons.icon(glyph, size)); + } + + private Optional installedByProjectId(List installedProjects, String projectId) { + return installedProjects.stream() + .filter(project -> project.projectId().equals(projectId)) + .findFirst(); + } + + interface VersionSwitchHandler { + void switchVersion(InstalledProject installed, ProjectDetail detail, ProjectVersion version); + } + + interface UnlockHandler { + void unlock(InstalledProject installed); + } + + interface WorldToggleHandler { + void setEnabled(HytaleWorld world, List modIds, boolean enabled); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectSupport.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectSupport.java new file mode 100644 index 00000000..b1fbc9cb --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryProjectSupport.java @@ -0,0 +1,221 @@ +package net.modtale.launcher.ui.library; + +import static net.modtale.launcher.ui.common.LauncherUi.classificationLabel; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; +import net.modtale.launcher.install.UpdateService; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; +import net.modtale.launcher.model.project.ProjectVersion; + +final class LibraryProjectSupport { + + private static final DateTimeFormatter SHORT_TIME = DateTimeFormatter.ofPattern("MMM d, yyyy") + .withZone(ZoneId.systemDefault()); + + private LibraryProjectSupport() { + } + + static String projectRowMeta(InstalledProject project) { + List parts = new ArrayList<>(); + parts.add(classificationLabel(project.classification())); + if (!project.gameVersion().isBlank()) { + parts.add(project.gameVersion()); + } + if (project.isModpack()) { + parts.add("Grouped"); + } + return String.join(" - ", parts); + } + + static String childMeta(InstalledProjectReference reference) { + List parts = new ArrayList<>(); + parts.add(reference.isModtaleProject() ? "Modtale" : value(reference.source(), "External")); + if (!reference.versionNumber().isBlank()) { + parts.add(reference.versionNumber()); + } + if (Boolean.TRUE.equals(reference.optional())) { + parts.add("optional"); + } + return String.join(" - ", parts); + } + + static int contentCount(InstalledProject installed) { + if (!installed.bundledProjects().isEmpty()) { + return installed.bundledProjects().size(); + } + int metadataCount = installed.dependencyProjectIds().size() + installed.externalDependencies().size(); + if (metadataCount > 0) { + return metadataCount; + } + return installed.isModpack() ? installed.files().size() : 0; + } + + static List projectWorldModIds(InstalledProject installed) { + if (installed.isModpack()) { + return modpackChildren(installed); + } + String id = projectModId(installed); + return id.isBlank() ? List.of() : List.of(id); + } + + static List modpackChildren(InstalledProject modpack) { + LinkedHashSet children = new LinkedHashSet<>(); + if (!modpack.bundledProjects().isEmpty()) { + for (InstalledProjectReference reference : modpack.bundledProjects()) { + String id = referenceWorldModId(reference); + if (!id.isBlank()) { + children.add(id); + } + } + } else { + children.addAll(modpack.dependencyProjectIds()); + children.addAll(modpack.externalDependencies()); + } + if (children.isEmpty()) { + String fallback = projectModId(modpack); + if (!fallback.isBlank()) { + children.add(fallback); + } + } + return List.copyOf(children); + } + + static String routeKey(InstalledProject installed) { + return installed.slug() == null || installed.slug().isBlank() ? installed.projectId() : installed.slug(); + } + + static boolean isModtaleProject(InstalledProject installed) { + if (installed == null) { + return false; + } + String source = installed.source() == null ? "" : installed.source().trim(); + return source.isBlank() || InstalledProject.SOURCE_MODTALE.equalsIgnoreCase(source); + } + + static String dateLabel(Instant instant) { + if (instant == null || Instant.EPOCH.equals(instant)) { + return "Unknown"; + } + return SHORT_TIME.format(instant); + } + + static String worldMeta(HytaleWorld world) { + List parts = new ArrayList<>(); + if (!world.patchline().isBlank()) { + parts.add(world.patchline()); + } + if (!world.updatedAt().equals(Instant.EPOCH)) { + parts.add(SHORT_TIME.format(world.updatedAt())); + } + return parts.isEmpty() ? "World save" : String.join(" - ", parts); + } + + static List versionChoices( + List versions, + InstalledProject installed, + String fallbackGameVersion + ) { + String gameVersion = value(installed == null ? "" : installed.gameVersion(), fallbackGameVersion); + return versions.stream() + .sorted(Comparator + .comparing(LibraryProjectSupport::releaseInstant, Comparator.nullsLast(Comparator.reverseOrder())) + .thenComparing(ProjectVersion::versionNumber, Comparator.nullsLast(Comparator.reverseOrder()))) + .map(version -> new LibraryVersionChoice(version, versionLabel(version, installed, gameVersion))) + .toList(); + } + + static String installGameVersion(ProjectVersion version, InstalledProject installed, String fallbackGameVersion) { + String preferred = value(installed == null ? "" : installed.gameVersion(), fallbackGameVersion); + if (version == null) { + return preferred; + } + if (!preferred.isBlank() && version.supportsGameVersion(preferred)) { + return preferred; + } + return version.gameVersions().stream() + .filter(gameVersion -> gameVersion != null && !gameVersion.isBlank()) + .map(String::trim) + .findFirst() + .orElse(preferred); + } + + static boolean sameVersion(InstalledProject installed, ProjectVersion version) { + return installed != null && version != null && UpdateService.sameVersion(installed, version); + } + + static String plural(int count) { + return count == 1 ? "" : "s"; + } + + static String referenceWorldModId(InstalledProjectReference reference) { + if (reference.slug() != null && reference.slug().contains(":")) { + return reference.slug(); + } + if (reference.projectId() != null && reference.projectId().contains(":")) { + return reference.projectId(); + } + if (reference.externalId() != null && !reference.externalId().isBlank()) { + return reference.externalId(); + } + return value(reference.slug(), value(reference.projectId(), "")).trim(); + } + + private static String projectModId(InstalledProject project) { + if (project.slug() != null && project.slug().contains(":")) { + return project.slug(); + } + if (project.projectId() != null && project.projectId().contains(":")) { + return project.projectId(); + } + return value(project.slug(), value(project.projectId(), "")).trim(); + } + + private static String versionLabel(ProjectVersion version, InstalledProject installed, String gameVersion) { + List parts = new ArrayList<>(); + parts.add(value(version.versionNumber(), "Untitled")); + if (sameVersion(installed, version)) { + parts.add("installed"); + } + if (version.channel() != null && !version.channel().isBlank()) { + parts.add(version.channel().toLowerCase(java.util.Locale.ROOT)); + } + String supportedGameVersions = supportedGameVersions(version, gameVersion); + if (!supportedGameVersions.isBlank()) { + parts.add(supportedGameVersions); + } + return String.join(" - ", parts); + } + + private static String supportedGameVersions(ProjectVersion version, String preferredGameVersion) { + if (version == null || version.gameVersions().isEmpty()) { + return ""; + } + if (preferredGameVersion != null + && !preferredGameVersion.isBlank() + && version.supportsGameVersion(preferredGameVersion)) { + return preferredGameVersion; + } + return String.join(", ", version.gameVersions()); + } + + private static Instant releaseInstant(ProjectVersion version) { + if (version.releaseDate() == null || version.releaseDate().isBlank()) { + return null; + } + try { + return Instant.parse(version.releaseDate()); + } catch (DateTimeParseException ignored) { + return null; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryShellView.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryShellView.java new file mode 100644 index 00000000..7e28591d --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryShellView.java @@ -0,0 +1,76 @@ +package net.modtale.launcher.ui.library; + +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.secondaryButton; + +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherView; + +final class LibraryShellView { + + private final VBox projectList; + private final VBox projectDetail; + private final Runnable refresh; + private final Runnable checkUpdates; + + LibraryShellView( + VBox projectList, + VBox projectDetail, + Runnable refresh, + Runnable checkUpdates + ) { + this.projectList = projectList; + this.projectDetail = projectDetail; + this.refresh = refresh; + this.checkUpdates = checkUpdates; + } + + Node build() { + VBox root = new VBox(18); + root.setUserData(LauncherView.LIBRARY); + root.getStyleClass().addAll("view", "library-view"); + root.getChildren().addAll(header(), content()); + return root; + } + + private Node header() { + HBox header = new HBox(16); + header.getStyleClass().add("library-header"); + VBox copy = new VBox(5); + Label title = new Label("World Libraries"); + title.getStyleClass().add("library-title"); + copy.getChildren().add(title); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + Button refreshButton = secondaryButton("Refresh"); + refreshButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.REFRESH_CW, 15)); + refreshButton.setOnAction(event -> refresh.run()); + Button updatesButton = primaryButton("Check Updates"); + updatesButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.REFRESH_CW, 15)); + updatesButton.setOnAction(event -> checkUpdates.run()); + header.getChildren().addAll(copy, spacer, refreshButton, updatesButton); + return header; + } + + private Node content() { + HBox content = new HBox(18); + content.getStyleClass().add("library-content"); + VBox projectsPane = new VBox(14); + projectsPane.getStyleClass().add("library-projects-pane"); + projectsPane.getChildren().add(projectList); + VBox.setVgrow(projectList, Priority.ALWAYS); + + projectDetail.getStyleClass().add("library-detail-pane"); + HBox.setHgrow(projectDetail, Priority.ALWAYS); + content.getChildren().addAll(projectsPane, projectDetail); + return content; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryToggleBox.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryToggleBox.java new file mode 100644 index 00000000..63d6f127 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryToggleBox.java @@ -0,0 +1,80 @@ +package net.modtale.launcher.ui.library; + +import javafx.css.PseudoClass; +import javafx.scene.control.Tooltip; +import javafx.scene.input.KeyCode; +import javafx.scene.layout.StackPane; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class LibraryToggleBox extends StackPane { + + private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected"); + private static final PseudoClass INDETERMINATE = PseudoClass.getPseudoClass("indeterminate"); + + private boolean selected; + private boolean indeterminate; + private Runnable action = () -> { + }; + + LibraryToggleBox() { + getStyleClass().add("library-toggle-box"); + setFocusTraversable(true); + setOnMouseClicked(event -> { + activate(); + event.consume(); + }); + setOnKeyPressed(event -> { + if (event.getCode() == KeyCode.SPACE || event.getCode() == KeyCode.ENTER) { + activate(); + event.consume(); + } + }); + updateState(); + } + + boolean isSelected() { + return selected; + } + + void setSelected(boolean selected) { + this.selected = selected; + updateState(); + } + + void setIndeterminate(boolean indeterminate) { + this.indeterminate = indeterminate; + updateState(); + } + + void setTooltip(Tooltip tooltip) { + if (tooltip != null) { + Tooltip.install(this, tooltip); + } + } + + void setOnAction(Runnable action) { + this.action = action == null ? () -> { + } : action; + } + + private void activate() { + if (isDisabled()) { + return; + } + selected = !selected; + indeterminate = false; + updateState(); + action.run(); + } + + private void updateState() { + pseudoClassStateChanged(SELECTED, selected); + pseudoClassStateChanged(INDETERMINATE, indeterminate); + getChildren().clear(); + if (indeterminate) { + getChildren().add(LauncherIcons.icon(LauncherIcons.Glyph.MINUS, 13)); + } else if (selected) { + getChildren().add(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 13)); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryVersionChoice.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryVersionChoice.java new file mode 100644 index 00000000..9ebc1893 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryVersionChoice.java @@ -0,0 +1,10 @@ +package net.modtale.launcher.ui.library; + +import net.modtale.launcher.model.project.ProjectVersion; + +record LibraryVersionChoice(ProjectVersion version, String label) { + @Override + public String toString() { + return label; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldContentItem.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldContentItem.java new file mode 100644 index 00000000..755183f7 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldContentItem.java @@ -0,0 +1,52 @@ +package net.modtale.launcher.ui.library; + +import java.util.List; + +record LibraryWorldContentItem( + String id, + String title, + String meta, + String classification, + String icon, + String author, + List modIds, + int enabledCount, + int totalCount, + boolean toggleable +) { + LibraryWorldContentItem { + id = value(id); + title = value(title, "Installed content"); + meta = value(meta); + classification = value(classification); + icon = value(icon); + author = value(author); + modIds = modIds == null + ? List.of() + : modIds.stream() + .filter(modId -> modId != null && !modId.isBlank()) + .map(String::trim) + .distinct() + .toList(); + totalCount = Math.max(totalCount, modIds.size()); + enabledCount = Math.max(0, Math.min(enabledCount, totalCount)); + toggleable = toggleable && !modIds.isEmpty(); + } + + boolean selected() { + return toggleable && totalCount > 0 && enabledCount == totalCount; + } + + boolean indeterminate() { + return toggleable && enabledCount > 0 && enabledCount < totalCount; + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } + + private static String value(String value, String fallback) { + String normalized = value(value); + return normalized.isBlank() ? fallback : normalized; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListItem.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListItem.java new file mode 100644 index 00000000..5282657f --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListItem.java @@ -0,0 +1,16 @@ +package net.modtale.launcher.ui.library; + +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; + +record LibraryWorldListItem( + HytaleWorld world, + String meta, + int enabledProjectCount, + int totalProjectCount +) { + LibraryWorldListItem { + meta = meta == null ? "" : meta.trim(); + totalProjectCount = Math.max(0, totalProjectCount); + enabledProjectCount = Math.max(0, Math.min(enabledProjectCount, totalProjectCount)); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListRenderer.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListRenderer.java new file mode 100644 index 00000000..9060cd72 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldListRenderer.java @@ -0,0 +1,100 @@ +package net.modtale.launcher.ui.library; + +import static net.modtale.launcher.ui.common.LauncherUi.pseudo; + +import java.util.function.Consumer; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class LibraryWorldListRenderer { + + private static final double WORLD_ICON_SIZE = 42; + + private final CachedImageLoader imageLoader; + private final Consumer selectWorld; + + LibraryWorldListRenderer(CachedImageLoader imageLoader, Consumer selectWorld) { + this.imageLoader = imageLoader; + this.selectWorld = selectWorld; + } + + Button worldRow(LibraryWorldListItem item, boolean selected) { + Button button = new Button(); + button.getStyleClass().addAll("library-project-row", "library-world-tab"); + button.setMaxWidth(Double.MAX_VALUE); + button.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + button.setGraphic(worldRowContent(item)); + button.setOnAction(event -> selectWorld.accept(item.world())); + pseudo(button, "selected", selected); + return button; + } + + private Node worldRowContent(LibraryWorldListItem item) { + HytaleWorld world = item.world(); + HBox row = new HBox(12); + row.getStyleClass().add("library-project-row-content"); + StackPane icon = worldIcon(world); + + VBox copy = new VBox(4); + Label title = new Label(world.name()); + title.getStyleClass().add("library-project-title"); + Label meta = new Label(item.meta()); + meta.getStyleClass().add("library-project-meta"); + copy.getChildren().addAll(title, meta); + HBox.setHgrow(copy, Priority.ALWAYS); + + VBox status = new VBox(5); + status.setAlignment(Pos.CENTER_RIGHT); + Label enabled = new Label(item.enabledProjectCount() + "/" + item.totalProjectCount()); + enabled.getStyleClass().add("library-version-pill"); + Label label = new Label("Enabled"); + label.getStyleClass().add("library-world-tab-caption"); + status.getChildren().addAll(enabled, label); + + row.getChildren().addAll(icon, copy, status); + return row; + } + + private StackPane worldIcon(HytaleWorld world) { + StackPane shell = new StackPane(); + shell.getStyleClass().add("library-project-icon"); + shell.setMinSize(WORLD_ICON_SIZE, WORLD_ICON_SIZE); + shell.setPrefSize(WORLD_ICON_SIZE, WORLD_ICON_SIZE); + shell.setMaxSize(WORLD_ICON_SIZE, WORLD_ICON_SIZE); + + String preview = world.previewImage(); + if (!preview.isBlank() && imageLoader != null) { + ImageView image = new ImageView(); + image.setFitWidth(WORLD_ICON_SIZE); + image.setFitHeight(WORLD_ICON_SIZE); + image.setPreserveRatio(false); + image.setSmooth(true); + image.setMouseTransparent(true); + image.setClip(roundedClip(WORLD_ICON_SIZE, 8)); + imageLoader.loadInto(image, preview, WORLD_ICON_SIZE, WORLD_ICON_SIZE); + shell.getChildren().add(image); + } else { + shell.getChildren().add(LauncherIcons.icon(LauncherIcons.Glyph.GLOBE, 18)); + } + return shell; + } + + private Rectangle roundedClip(double size, double radius) { + Rectangle clip = new Rectangle(size, size); + clip.setArcWidth(radius * 2); + clip.setArcHeight(radius * 2); + return clip; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldModel.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldModel.java new file mode 100644 index 00000000..1ebedf0a --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldModel.java @@ -0,0 +1,19 @@ +package net.modtale.launcher.ui.library; + +import java.util.List; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; + +record LibraryWorldModel( + HytaleWorld world, + String meta, + int enabledProjectCount, + int totalProjectCount, + List projects +) { + LibraryWorldModel { + meta = meta == null ? "" : meta.trim(); + projects = projects == null ? List.of() : List.copyOf(projects); + totalProjectCount = Math.max(totalProjectCount, projects.size()); + enabledProjectCount = Math.max(0, Math.min(enabledProjectCount, totalProjectCount)); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectDisplay.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectDisplay.java new file mode 100644 index 00000000..bf612323 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectDisplay.java @@ -0,0 +1,60 @@ +package net.modtale.launcher.ui.library; + +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.project.ProjectMeta; + +record LibraryWorldProjectDisplay( + String title, + String author, + String classification, + String icon, + String version, + String metaNote, + boolean localFile, + boolean unlockVisible, + boolean contentsVisible +) { + LibraryWorldProjectDisplay { + title = value(title, "Untitled Project"); + author = value(author); + classification = value(classification, "PLUGIN"); + icon = value(icon); + version = value(version); + metaNote = value(metaNote); + } + + static LibraryWorldProjectDisplay root(InstalledProject installed, ProjectMeta meta) { + return new LibraryWorldProjectDisplay( + first(meta == null ? "" : meta.title(), installed == null ? "" : installed.title()), + meta == null ? "" : meta.author(), + first(meta == null ? "" : meta.classification(), installed == null ? "" : installed.classification()), + meta == null ? "" : meta.icon(), + installed == null ? "" : installed.installedVersion(), + "", + installed != null && !LibraryProjectSupport.isModtaleProject(installed), + installed != null && installed.isModpack(), + installed != null && installed.isModpack() + ); + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + private static String value(String value) { + return value == null ? "" : value.trim(); + } + + private static String value(String value, String fallback) { + String normalized = value(value); + return normalized.isBlank() ? fallback : normalized; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectModel.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectModel.java new file mode 100644 index 00000000..72b64c15 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldProjectModel.java @@ -0,0 +1,81 @@ +package net.modtale.launcher.ui.library; + +import java.util.List; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.UpdateCandidate; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectMeta; + +record LibraryWorldProjectModel( + InstalledProject installed, + ProjectDetail detail, + ProjectMeta meta, + UpdateCandidate update, + boolean loading, + List modIds, + int enabledCount, + int totalCount, + List contents, + LibraryWorldProjectDisplay display, + boolean contentsCollapsed +) { + LibraryWorldProjectModel( + InstalledProject installed, + ProjectDetail detail, + ProjectMeta meta, + UpdateCandidate update, + boolean loading, + List modIds, + int enabledCount, + int totalCount, + List contents + ) { + this(installed, detail, meta, update, loading, modIds, enabledCount, totalCount, contents, null, false); + } + + LibraryWorldProjectModel( + InstalledProject installed, + ProjectDetail detail, + ProjectMeta meta, + UpdateCandidate update, + boolean loading, + List modIds, + int enabledCount, + int totalCount, + List contents, + LibraryWorldProjectDisplay display + ) { + this(installed, detail, meta, update, loading, modIds, enabledCount, totalCount, contents, display, false); + } + + LibraryWorldProjectModel { + modIds = modIds == null + ? List.of() + : modIds.stream() + .filter(modId -> modId != null && !modId.isBlank()) + .map(String::trim) + .distinct() + .toList(); + totalCount = Math.max(totalCount, modIds.size()); + enabledCount = Math.max(0, Math.min(enabledCount, totalCount)); + contents = contents == null ? List.of() : List.copyOf(contents); + display = display == null ? LibraryWorldProjectDisplay.root(installed, meta) : display; + contentsCollapsed = contentsCollapsed && display.contentsVisible(); + } + + boolean toggleable() { + return !modIds.isEmpty(); + } + + boolean selected() { + return toggleable() && totalCount > 0 && enabledCount == totalCount; + } + + boolean indeterminate() { + return toggleable() && enabledCount > 0 && enabledCount < totalCount; + } + + boolean contentsExpanded() { + return display.contentsVisible() && !contentsCollapsed; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldRenderer.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldRenderer.java new file mode 100644 index 00000000..f05c9f81 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldRenderer.java @@ -0,0 +1,507 @@ +package net.modtale.launcher.ui.library; + +import static net.modtale.launcher.ui.common.LauncherUi.emptyState; +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.secondaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.styleCombo; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.function.Consumer; +import javafx.collections.FXCollections; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.UpdateCandidate; +import net.modtale.launcher.model.project.ProjectClassification; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectMeta; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class LibraryWorldRenderer { + + private static final double PROJECT_ICON_SIZE = 46; + private static final double CONTENT_ICON_SIZE = 34; + + private final CachedImageLoader imageLoader; + private final Consumer updateProject; + private final Consumer loadVersions; + private final LibraryProjectRenderer.VersionSwitchHandler switchVersion; + private final Consumer uninstallProject; + private final LibraryProjectRenderer.UnlockHandler unlockProject; + private final Consumer toggleModpackContents; + private final LibraryProjectRenderer.WorldToggleHandler toggleWorldMods; + private final Consumer shareWorldSnapshot; + private final Consumer createModpackFromWorld; + + LibraryWorldRenderer( + CachedImageLoader imageLoader, + Consumer updateProject, + Consumer loadVersions, + LibraryProjectRenderer.VersionSwitchHandler switchVersion, + Consumer uninstallProject, + LibraryProjectRenderer.UnlockHandler unlockProject, + Consumer toggleModpackContents, + LibraryProjectRenderer.WorldToggleHandler toggleWorldMods, + Consumer shareWorldSnapshot, + Consumer createModpackFromWorld + ) { + this.imageLoader = imageLoader; + this.updateProject = updateProject; + this.loadVersions = loadVersions; + this.switchVersion = switchVersion; + this.uninstallProject = uninstallProject; + this.unlockProject = unlockProject; + this.toggleModpackContents = toggleModpackContents; + this.toggleWorldMods = toggleWorldMods; + this.shareWorldSnapshot = shareWorldSnapshot; + this.createModpackFromWorld = createModpackFromWorld; + } + + List worldDetail(LibraryWorldModel model) { + if (model == null || model.world() == null) { + return List.of(emptyState("No world selected", "Create a Hytale world, then refresh the launcher.")); + } + List sections = new ArrayList<>(); + sections.add(worldHeader(model)); + sections.add(installedProjectsSection(model)); + return sections; + } + + private Node worldHeader(LibraryWorldModel model) { + VBox section = new VBox(12); + section.getStyleClass().addAll("library-detail-hero", "library-world-detail-hero"); + + HBox row = new HBox(12); + row.getStyleClass().add("library-detail-heading"); + StackPane icon = imageIcon( + model.world().previewImage(), + model.world().name(), + LauncherIcons.Glyph.GLOBE, + 44, + "library-detail-icon" + ); + icon.getStyleClass().add("library-world-detail-icon"); + + VBox copy = new VBox(); + copy.setAlignment(Pos.CENTER_LEFT); + Label title = new Label(model.world().name()); + title.getStyleClass().addAll("library-detail-title", "library-world-detail-title"); + title.setMaxWidth(Double.MAX_VALUE); + copy.getChildren().add(title); + HBox.setHgrow(copy, Priority.ALWAYS); + + HBox actions = new HBox(8); + actions.getStyleClass().add("library-actions"); + actions.setAlignment(Pos.CENTER_RIGHT); + Button share = secondaryButton("Share"); + share.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.SHARE_2, 14)); + share.setTooltip(new Tooltip("Copy a share link for this world's enabled mods")); + share.setOnAction(event -> shareWorldSnapshot.accept(model.world())); + Button pack = primaryButton("Make Pack"); + pack.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.PACKAGE_PLUS, 14)); + pack.setTooltip(new Tooltip("Start a Modtale modpack from this world's enabled mods")); + pack.setOnAction(event -> createModpackFromWorld.accept(model.world())); + actions.getChildren().addAll(share, pack); + + row.getChildren().addAll(icon, copy, actions); + section.getChildren().add(row); + return section; + } + + private Node installedProjectsSection(LibraryWorldModel model) { + return installedProjectsSection( + model.world(), + model.projects(), + "No installed projects", + "Install mods from Browse to manage them per world." + ); + } + + private Node installedProjectsSection( + HytaleWorld world, + List projects, + String emptyTitle, + String emptySubtitle + ) { + VBox section = detailSection("Installed Mods and Modpacks"); + if (projects.isEmpty()) { + section.getChildren().add(emptyState(emptyTitle, emptySubtitle)); + return section; + } + VBox rows = new VBox(10); + rows.getStyleClass().add("library-world-project-list"); + for (LibraryWorldProjectModel project : projects) { + rows.getChildren().add(projectRow(world, project)); + } + section.getChildren().add(rows); + return section; + } + + private Node projectRow(HytaleWorld world, LibraryWorldProjectModel model) { + VBox shell = new VBox(10); + shell.getStyleClass().add("library-world-project-row"); + + HBox row = new HBox(12); + row.getStyleClass().add("library-world-project-main"); + row.setAlignment(Pos.CENTER_LEFT); + + boolean hasWorld = world != null; + LibraryToggleBox toggle = new LibraryToggleBox(); + toggle.setSelected(hasWorld && model.selected()); + toggle.setIndeterminate(hasWorld && model.indeterminate()); + toggle.setDisable(!hasWorld || !model.toggleable()); + toggle.setTooltip(new Tooltip(!hasWorld + ? "Select or create a world to enable this install" + : model.toggleable() + ? "Enable or disable this installed project for " + world.name() + : "No Hytale manifest id was found for this install record")); + if (hasWorld) { + toggle.setOnAction(() -> toggleWorldMods.setEnabled(world, model.modIds(), toggle.isSelected())); + } + + StackPane icon = projectIcon(model, PROJECT_ICON_SIZE); + VBox copy = projectCopy(model); + HBox.setHgrow(copy, Priority.ALWAYS); + + HBox actions = projectActions(model); + row.getChildren().addAll(toggle, icon, copy, actions); + shell.getChildren().add(row); + + Node versionControls = versionControls(model); + if (versionControls != null) { + shell.getChildren().add(versionControls); + } + + Node contentsCard = contentsCard(model); + if (contentsCard != null) { + shell.getChildren().add(contentsCard); + } + return shell; + } + + private VBox projectCopy(LibraryWorldProjectModel model) { + InstalledProject installed = model.installed(); + LibraryWorldProjectDisplay display = model.display(); + VBox copy = new VBox(5); + Label title = new Label(display.title()); + title.getStyleClass().add("library-world-project-title"); + + String subtitleText = projectMetaLine(model); + Label subtitle = new Label(subtitleText); + subtitle.getStyleClass().add("library-world-project-meta"); + + HBox badges = new HBox(7); + badges.getStyleClass().add("library-badge-row"); + if (!display.version().isBlank()) { + badges.getChildren().add(badge(display.version(), "version")); + } + if (!installed.gameVersion().isBlank()) { + badges.getChildren().add(badge(installed.gameVersion(), "game")); + } + if (model.update() != null) { + badges.getChildren().add(badge("Update ready", "game")); + } + if (display.localFile()) { + badges.getChildren().add(badge("Local file", "locked")); + } + if (installed.isModpack()) { + badges.getChildren().add(badge("Modpack", "modpack")); + } + copy.getChildren().add(title); + if (!subtitleText.isBlank()) { + copy.getChildren().add(subtitle); + } + copy.getChildren().add(badges); + return copy; + } + + private HBox projectActions(LibraryWorldProjectModel model) { + InstalledProject installed = model.installed(); + boolean modtaleProject = LibraryProjectSupport.isModtaleProject(installed); + HBox actions = new HBox(6); + actions.getStyleClass().add("library-world-project-actions"); + actions.setAlignment(Pos.CENTER_RIGHT); + + if (modtaleProject && model.update() != null) { + Button update = primaryButton("Update"); + update.getStyleClass().add("small"); + update.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 13)); + update.setTooltip(new Tooltip("Install " + model.update().newestVersionNumber())); + update.setOnAction(event -> updateProject.accept(model.update())); + actions.getChildren().add(update); + } + + Button versions = iconAction( + LauncherIcons.Glyph.LAYERS, + !modtaleProject + ? "Local files do not have Modtale version history" + : model.loading() + ? "Loading release metadata" + : model.detail() == null ? "Load available versions" : "Version controls are ready below", + "neutral", + () -> { + if (modtaleProject) { + loadVersions.accept(installed); + } + } + ); + versions.setDisable(!modtaleProject || model.detail() != null || model.loading()); + + actions.getChildren().add(versions); + if (model.display().unlockVisible()) { + Button unlock = iconAction( + LauncherIcons.Glyph.EDIT, + "Unlock this pack into individual installed mods", + "neutral", + () -> unlockProject.unlock(installed) + ); + actions.getChildren().add(unlock); + } + Button remove = iconAction( + LauncherIcons.Glyph.TRASH, + "Remove this project", + "danger", + () -> uninstallProject.accept(installed) + ); + actions.getChildren().add(remove); + return actions; + } + + private Node versionControls(LibraryWorldProjectModel model) { + InstalledProject installed = model.installed(); + ProjectDetail detail = model.detail(); + if (detail == null) { + if (!model.loading()) { + return null; + } + HBox loading = new HBox(10); + loading.getStyleClass().add("library-world-version-row"); + loading.setAlignment(Pos.CENTER_LEFT); + Label label = new Label("Loading release metadata..."); + label.getStyleClass().add("library-muted-text"); + loading.getChildren().add(label); + return loading; + } + + List choices = LibraryProjectSupport.versionChoices( + detail.versions(), + installed, + installed.gameVersion() + ); + if (choices.isEmpty()) { + return null; + } + ComboBox versions = new ComboBox<>(FXCollections.observableArrayList(choices)); + styleCombo(versions); + choices.stream() + .filter(choice -> LibraryProjectSupport.sameVersion(installed, choice.version())) + .findFirst() + .ifPresentOrElse(versions::setValue, () -> versions.setValue(choices.getFirst())); + + Button switchButton = primaryButton("Switch"); + switchButton.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 13)); + switchButton.setOnAction(event -> { + LibraryVersionChoice choice = versions.getValue(); + if (choice != null) { + switchVersion.switchVersion(installed, detail, choice.version()); + } + }); + Runnable updateSwitchState = () -> { + LibraryVersionChoice choice = versions.getValue(); + switchButton.setDisable(choice == null || LibraryProjectSupport.sameVersion(installed, choice.version())); + }; + versions.valueProperty().addListener((observable, previous, next) -> updateSwitchState.run()); + updateSwitchState.run(); + + HBox controls = new HBox(10, versions, switchButton); + controls.getStyleClass().add("library-world-version-row"); + HBox.setHgrow(versions, Priority.ALWAYS); + return controls; + } + + private Node contentsCard(LibraryWorldProjectModel model) { + if (!model.display().contentsVisible()) { + return null; + } + int contentCount = model.contents().isEmpty() + ? LibraryProjectSupport.contentCount(model.installed()) + : model.contents().size(); + Button toggle = new Button(null, LauncherIcons.icon( + model.contentsCollapsed() ? LauncherIcons.Glyph.CHEVRON_DOWN : LauncherIcons.Glyph.CHEVRON_UP, + 13 + )); + toggle.getStyleClass().addAll("library-icon-action", "library-icon-action-neutral"); + toggle.setTooltip(new Tooltip(model.contentsCollapsed() ? "Show included mods" : "Collapse included mods")); + toggle.setAccessibleText(model.contentsCollapsed() ? "Show included mods" : "Collapse included mods"); + toggle.setOnAction(event -> toggleModpackContents.accept(model.installed())); + + Label title = new Label("Included mods"); + title.getStyleClass().add("library-child-title"); + Label count = new Label(contentCount + " item" + LibraryProjectSupport.plural(contentCount)); + count.getStyleClass().add("library-muted-text"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + HBox header = new HBox(8, title, count, spacer, toggle); + header.getStyleClass().add("library-world-content-header"); + header.setAlignment(Pos.CENTER_LEFT); + + VBox card = new VBox(8); + card.getStyleClass().add("library-world-content-card"); + card.getChildren().add(header); + if (!model.contentsExpanded()) { + return card; + } + + VBox contents = new VBox(8); + contents.getStyleClass().add("library-world-content-list"); + if (model.contents().isEmpty()) { + contents.getChildren().add(emptyState("No individual manifests found", "This pack is installed, but its files did not expose separate mod ids.")); + card.getChildren().add(contents); + return card; + } + for (LibraryWorldContentItem item : model.contents()) { + contents.getChildren().add(compactContentRow(item)); + } + card.getChildren().add(contents); + return card; + } + + private Node compactContentRow(LibraryWorldContentItem item) { + HBox row = new HBox(9); + row.getStyleClass().addAll("library-world-content-row", "library-world-content-row-compact"); + row.setAlignment(Pos.CENTER_LEFT); + + StackPane icon = contentIcon(item); + VBox copy = new VBox(2); + Label title = new Label(item.title()); + title.getStyleClass().add("library-child-title"); + Label meta = new Label(item.meta().isBlank() ? "Included in modpack" : item.meta()); + meta.getStyleClass().add("library-child-meta"); + copy.getChildren().addAll(title, meta); + HBox.setHgrow(copy, Priority.ALWAYS); + + Label status = new Label("Included"); + status.getStyleClass().add("library-version-pill"); + row.getChildren().addAll(icon, copy, status); + return row; + } + + private StackPane projectIcon(LibraryWorldProjectModel model, double size) { + ProjectMeta meta = model.meta(); + InstalledProject installed = model.installed(); + LibraryWorldProjectDisplay display = model.display(); + String iconUrl = display.icon(); + String title = first(display.title(), meta == null ? "" : meta.title(), installed.title(), "M"); + LauncherIcons.Glyph glyph = ProjectClassification.isModpack(display.classification()) + ? LauncherIcons.Glyph.LAYERS + : LauncherIcons.Glyph.BOX; + return imageIcon(iconUrl, title, glyph, size, "library-project-icon"); + } + + private StackPane contentIcon(LibraryWorldContentItem item) { + LauncherIcons.Glyph glyph = ProjectClassification.isModpack(item.classification()) + ? LauncherIcons.Glyph.LAYERS + : LauncherIcons.Glyph.FILE_CODE; + return imageIcon(item.icon(), item.title(), glyph, CONTENT_ICON_SIZE, "library-child-icon"); + } + + private StackPane imageIcon(String iconUrl, String title, LauncherIcons.Glyph fallbackGlyph, double size, String styleClass) { + StackPane shell = new StackPane(); + shell.getStyleClass().add(styleClass); + shell.setMinSize(size, size); + shell.setPrefSize(size, size); + shell.setMaxSize(size, size); + + if (iconUrl != null && !iconUrl.isBlank() && imageLoader != null) { + ImageView image = new ImageView(); + image.setFitWidth(size); + image.setFitHeight(size); + image.setSmooth(true); + image.setMouseTransparent(true); + image.setClip(roundedClip(size, size <= CONTENT_ICON_SIZE ? 8 : 10)); + imageLoader.loadInto(image, iconUrl, size, size); + shell.getChildren().add(image); + return shell; + } + + Node fallback = LauncherIcons.icon(fallbackGlyph, Math.max(15, size * 0.42)); + shell.getChildren().add(fallback); + if (fallbackGlyph == LauncherIcons.Glyph.BOX && title != null && !title.isBlank()) { + shell.setAccessibleText(title.substring(0, 1).toUpperCase(Locale.ROOT)); + } + return shell; + } + + private Rectangle roundedClip(double size, double radius) { + Rectangle clip = new Rectangle(size, size); + clip.setArcWidth(radius * 2); + clip.setArcHeight(radius * 2); + return clip; + } + + private String projectMetaLine(LibraryWorldProjectModel model) { + String author = model.display().author(); + return author.isBlank() ? "" : "by " + author; + } + + private boolean hasUnlockableContents(InstalledProject installed) { + return installed.isModpack() + || !installed.bundledProjects().isEmpty() + || !installed.dependencyProjectIds().isEmpty() + || !installed.externalDependencies().isEmpty(); + } + + private VBox detailSection(String title) { + VBox section = new VBox(10); + section.getStyleClass().add("library-detail-section"); + Label label = new Label(title); + label.getStyleClass().add("library-section-title"); + section.getChildren().add(label); + return section; + } + + private Node badge(String text, String tone) { + Label label = new Label(text); + label.getStyleClass().addAll("library-badge", "library-badge-" + tone); + return label; + } + + private Button iconAction(LauncherIcons.Glyph glyph, String tooltip, String tone, Runnable action) { + Button button = new Button(null, LauncherIcons.icon(glyph, 14)); + button.getStyleClass().addAll("library-icon-action", "library-icon-action-" + tone); + button.setTooltip(new Tooltip(tooltip)); + button.setAccessibleText(tooltip); + button.setOnAction(event -> action.run()); + return button; + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String candidate : values) { + if (candidate != null && !candidate.isBlank()) { + return candidate.trim(); + } + } + return ""; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldSnapshotMapper.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldSnapshotMapper.java new file mode 100644 index 00000000..42c86473 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldSnapshotMapper.java @@ -0,0 +1,330 @@ +package net.modtale.launcher.ui.library; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleInstalledMod; +import net.modtale.launcher.model.install.InstalledProject; +import net.modtale.launcher.model.install.InstalledProjectReference; +import net.modtale.launcher.model.worldlist.CreateWorldModListRequest; + +final class LibraryWorldSnapshotMapper { + + private final List installedProjects; + private final Map modsById; + private final Map projectsByFile; + + private LibraryWorldSnapshotMapper( + List installedProjects, + List installedMods + ) { + this.installedProjects = installedProjects == null ? List.of() : List.copyOf(installedProjects); + this.modsById = installedModsById(installedMods); + this.projectsByFile = installedProjectsByFile(this.installedProjects); + } + + static List itemsFor( + Set enabledModIds, + List installedProjects, + List installedMods + ) { + LibraryWorldSnapshotMapper mapper = new LibraryWorldSnapshotMapper(installedProjects, installedMods); + List items = new ArrayList<>(); + if (enabledModIds == null) { + return items; + } + for (String modId : enabledModIds) { + if (modId != null && !modId.isBlank()) { + items.add(mapper.itemFor(modId.trim())); + } + } + return items; + } + + private CreateWorldModListRequest.Item itemFor(String modId) { + HytaleInstalledMod localMod = modsById.get(modId); + SnapshotMatch match = matchFor(modId, localMod); + return match == null ? externalSnapshotItem(modId, localMod) : matchedSnapshotItem(modId, localMod, match); + } + + private SnapshotMatch matchFor(String modId, HytaleInstalledMod localMod) { + if (localMod != null) { + InstalledProject byFile = projectsByFile.get(normalizedFileKey(localMod.file())); + if (byFile != null) { + InstalledProjectReference reference = matchingReference(modId, localMod, byFile); + if (reference != null) { + return SnapshotMatch.fromReference(reference, byFile.installedVersion()); + } + return SnapshotMatch.fromProject(byFile); + } + } + + for (InstalledProject project : installedProjects) { + InstalledProjectReference reference = matchingReference(modId, localMod, project); + if (reference != null) { + return SnapshotMatch.fromReference(reference, project.installedVersion()); + } + } + + return installedProjects.stream() + .filter(project -> LibraryProjectSupport.projectWorldModIds(project).contains(modId)) + .findFirst() + .map(SnapshotMatch::fromProject) + .orElse(null); + } + + private InstalledProjectReference matchingReference( + String modId, + HytaleInstalledMod localMod, + InstalledProject project + ) { + if (project == null) { + return null; + } + List references = bundledReferences(project); + if (references.isEmpty()) { + return null; + } + Set modKeys = new LinkedHashSet<>(); + addNormalized(modKeys, modId); + if (localMod != null) { + addNormalized(modKeys, localMod.id()); + addNormalized(modKeys, localMod.name()); + addNormalized(modKeys, fileName(localMod.file())); + } + if (modKeys.isEmpty()) { + return null; + } + + for (InstalledProjectReference reference : references) { + Set referenceKeys = new LinkedHashSet<>(); + addNormalized(referenceKeys, LibraryProjectSupport.referenceWorldModId(reference)); + addNormalized(referenceKeys, reference.title()); + addNormalized(referenceKeys, reference.slug()); + addNormalized(referenceKeys, reference.projectId()); + addNormalized(referenceKeys, reference.externalId()); + addNormalized(referenceKeys, reference.externalFileName()); + addNormalized(referenceKeys, fileName(reference.externalFileUrl())); + addNormalized(referenceKeys, fileName(reference.cachedFileUrl())); + for (String key : modKeys) { + if (referenceKeys.contains(key)) { + return reference; + } + } + } + return null; + } + + private CreateWorldModListRequest.Item matchedSnapshotItem( + String modId, + HytaleInstalledMod localMod, + SnapshotMatch match + ) { + String localTitle = localMod == null ? modId : localMod.name(); + String localVersion = localMod == null ? "" : localMod.version(); + return new CreateWorldModListRequest.Item( + modId, + match.projectId(), + match.slug(), + first(match.title(), localTitle, modId), + first(match.versionNumber(), localVersion), + first(match.classification(), "PLUGIN"), + worldListSource(first(match.source(), match.projectId().isBlank() ? "OTHER" : InstalledProject.SOURCE_MODTALE)), + match.externalId(), + match.externalUrl(), + match.icon() + ); + } + + private CreateWorldModListRequest.Item externalSnapshotItem(String modId, HytaleInstalledMod localMod) { + String title = localMod == null ? modId : first(localMod.name(), modId); + String version = localMod == null ? "" : localMod.version(); + return new CreateWorldModListRequest.Item( + modId, + "", + "", + title, + version, + "PLUGIN", + "OTHER", + modId, + "", + "" + ); + } + + private static Map installedModsById(List mods) { + Map byId = new LinkedHashMap<>(); + if (mods == null) { + return byId; + } + for (HytaleInstalledMod mod : mods) { + if (mod != null && mod.id() != null && !mod.id().isBlank()) { + byId.put(mod.id(), mod); + } + } + return byId; + } + + private static Map installedProjectsByFile(List projects) { + Map byFile = new LinkedHashMap<>(); + if (projects == null) { + return byFile; + } + for (InstalledProject project : projects) { + if (project == null) { + continue; + } + for (String file : project.files()) { + String key = normalizedFileKey(file); + if (!key.isBlank()) { + byFile.putIfAbsent(key, project); + } + } + } + return byFile; + } + + private static List bundledReferences(InstalledProject installed) { + if (installed == null) { + return List.of(); + } + if (!installed.bundledProjects().isEmpty()) { + return installed.bundledProjects(); + } + List references = new ArrayList<>(); + installed.dependencyProjectIds().forEach(id -> references.add(new InstalledProjectReference( + id, id, "", id, "", "", "", InstalledProject.SOURCE_MODTALE, "", "", "", "", "", "", null, null + ))); + installed.externalDependencies().forEach(id -> references.add(new InstalledProjectReference( + id, "", "", id, "", "", "", "EXTERNAL", id, "", "", "", "", "", null, null + ))); + return references; + } + + private static void addNormalized(Set keys, String value) { + String normalized = normalizedNameKey(value); + if (!normalized.isBlank()) { + keys.add(normalized); + } + } + + private static String fileName(Path value) { + return value == null ? "" : value.getFileName().toString(); + } + + private static String fileName(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().replace('\\', '/'); + int query = normalized.indexOf('?'); + if (query >= 0) { + normalized = normalized.substring(0, query); + } + int slash = normalized.lastIndexOf('/'); + return slash >= 0 ? normalized.substring(slash + 1) : normalized; + } + + private static String normalizedNameKey(String value) { + if (value == null || value.isBlank()) { + return ""; + } + String normalized = value.trim().toLowerCase(Locale.ROOT) + .replaceFirst("(?i)\\.(jar|zip|hytale)$", ""); + return normalized.replaceAll("[^a-z0-9]+", ""); + } + + private static String normalizedFileKey(String file) { + if (file == null || file.isBlank()) { + return ""; + } + return normalizedFileKey(Path.of(file)); + } + + private static String normalizedFileKey(Path file) { + if (file == null) { + return ""; + } + return file.toAbsolutePath().normalize().toString(); + } + + private static String worldListSource(String source) { + String normalized = first(source).toUpperCase(Locale.ROOT); + return switch (normalized) { + case "MODTALE", "CURSEFORGE", "GITHUB", "WEBSITE", "OTHER" -> normalized; + default -> "OTHER"; + }; + } + + private static String first(String... values) { + if (values == null) { + return ""; + } + for (String value : values) { + if (value != null && !value.isBlank()) { + return value.trim(); + } + } + return ""; + } + + private record SnapshotMatch( + String projectId, + String slug, + String title, + String versionNumber, + String classification, + String source, + String externalId, + String externalUrl, + String icon + ) { + private SnapshotMatch { + projectId = first(projectId); + slug = first(slug); + title = first(title); + versionNumber = first(versionNumber); + classification = first(classification); + source = first(source); + externalId = first(externalId); + externalUrl = first(externalUrl); + icon = first(icon); + } + + private static SnapshotMatch fromProject(InstalledProject project) { + boolean modtaleProject = LibraryProjectSupport.isModtaleProject(project); + return new SnapshotMatch( + modtaleProject ? project.projectId() : "", + modtaleProject ? project.slug() : "", + project.title(), + project.installedVersion(), + project.classification(), + modtaleProject ? InstalledProject.SOURCE_MODTALE : first(project.source(), "OTHER"), + modtaleProject ? "" : first(project.projectId(), project.slug()), + "", + "" + ); + } + + private static SnapshotMatch fromReference(InstalledProjectReference reference, String fallbackVersion) { + boolean modtaleProject = reference.isModtaleProject(); + return new SnapshotMatch( + modtaleProject ? reference.projectId() : "", + modtaleProject ? reference.slug() : "", + reference.displayName(), + first(reference.versionNumber(), fallbackVersion), + first(reference.classification(), "PLUGIN"), + modtaleProject ? InstalledProject.SOURCE_MODTALE : first(reference.source(), "OTHER"), + modtaleProject ? "" : first(reference.externalId(), reference.id(), LibraryProjectSupport.referenceWorldModId(reference)), + reference.externalUrl(), + reference.icon() + ); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldToggle.java b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldToggle.java new file mode 100644 index 00000000..768a2bb3 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/LibraryWorldToggle.java @@ -0,0 +1,18 @@ +package net.modtale.launcher.ui.library; + +import java.util.List; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; + +record LibraryWorldToggle( + HytaleWorld world, + String meta, + int enabledCount, + int totalCount, + boolean selected, + boolean indeterminate, + List modIds +) { + LibraryWorldToggle { + modIds = modIds == null ? List.of() : List.copyOf(modIds); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/library/PostDownloadWorldModal.java b/launcher/src/main/java/net/modtale/launcher/ui/library/PostDownloadWorldModal.java new file mode 100644 index 00000000..8cfaffc7 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/library/PostDownloadWorldModal.java @@ -0,0 +1,414 @@ +package net.modtale.launcher.ui.library; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.css.PseudoClass; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.hytale.HytaleWorldManager.HytaleWorld; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class PostDownloadWorldModal { + + private static final double MODAL_WIDTH = 512; + private static final double MODAL_MAX_HEIGHT = 720; + private static final double WORLD_ICON_IMAGE_SIZE = 44; + private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected"); + private static final PseudoClass INDETERMINATE = PseudoClass.getPseudoClass("indeterminate"); + + private final Supplier host; + private final Consumer apply; + private final CachedImageLoader imageLoader; + private final Map worldChecks = new LinkedHashMap<>(); + private final Map worldRows = new LinkedHashMap<>(); + private final Set selectedWorldKeys = new LinkedHashSet<>(); + + private StackPane overlay; + private String title = ""; + private List modIds = List.of(); + private List worlds = List.of(); + private Button applyButton; + private Button toggleAllButton; + private Label selectedCount; + + PostDownloadWorldModal(Supplier host, Consumer apply, CachedImageLoader imageLoader) { + this.host = host == null ? () -> null : host; + this.apply = apply == null ? ignored -> { + } : apply; + this.imageLoader = imageLoader; + } + + boolean show(String title, List modIds, List worlds) { + if (modIds == null || modIds.isEmpty() || worlds == null || worlds.isEmpty()) { + return false; + } + hide(); + StackPane hostPane = host.get(); + if (hostPane == null) { + return false; + } + this.title = value(title, "Installed project"); + this.modIds = modIds.stream() + .filter(id -> id != null && !id.isBlank()) + .map(String::trim) + .distinct() + .toList(); + this.worlds = List.copyOf(worlds); + selectedWorldKeys.clear(); + this.worlds.stream() + .filter(WorldOption::selected) + .map(PostDownloadWorldModal::worldKey) + .forEach(selectedWorldKeys::add); + + overlay = overlayShell(); + hostPane.getChildren().add(overlay); + rebuildOverlay(); + return true; + } + + private void rebuildOverlay() { + if (overlay == null) { + return; + } + worldChecks.clear(); + worldRows.clear(); + overlay.getChildren().setAll(modal()); + updateActionState(); + Platform.runLater(overlay::requestFocus); + } + + private StackPane overlayShell() { + StackPane shell = new StackPane(); + shell.getStyleClass().add("post-download-modal-overlay"); + shell.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + shell.setFocusTraversable(true); + shell.addEventHandler(KeyEvent.KEY_PRESSED, event -> { + if (event.getCode() == KeyCode.ESCAPE) { + hide(); + event.consume(); + } + }); + shell.setOnMouseClicked(event -> { + if (event.getTarget() == shell) { + hide(); + } + }); + return shell; + } + + private VBox modal() { + VBox modal = new VBox(0); + modal.getStyleClass().add("post-download-modal"); + modal.setMaxWidth(MODAL_WIDTH); + modal.setPrefWidth(MODAL_WIDTH); + modal.setMaxHeight(MODAL_MAX_HEIGHT); + modal.setOnMouseClicked(event -> event.consume()); + + ScrollPane scroll = new ScrollPane(body()); + scroll.getStyleClass().add("post-download-modal-scroll"); + scroll.setFitToWidth(true); + scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + VBox.setVgrow(scroll, Priority.ALWAYS); + + modal.getChildren().addAll(header(), scroll, footer()); + return modal; + } + + private HBox header() { + HBox header = new HBox(16); + header.getStyleClass().add("post-download-modal-header"); + header.setAlignment(Pos.CENTER_LEFT); + + HBox titleRow = new HBox(8, LauncherIcons.icon(LauncherIcons.Glyph.GLOBE, 20), new Label("Enable in Worlds")); + titleRow.getStyleClass().add("post-download-modal-title"); + titleRow.setAlignment(Pos.CENTER_LEFT); + HBox.setHgrow(titleRow, Priority.ALWAYS); + + Button close = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.X, 18)); + close.getStyleClass().add("post-download-modal-close"); + close.setOnAction(event -> hide()); + header.getChildren().addAll(titleRow, close); + return header; + } + + private VBox body() { + VBox body = new VBox(16); + body.getStyleClass().add("post-download-modal-body"); + body.getChildren().add(summaryRow()); + + VBox list = new VBox(8); + list.getStyleClass().add("post-download-modal-world-list"); + for (WorldOption world : worlds) { + list.getChildren().add(worldRow(world)); + } + body.getChildren().add(list); + return body; + } + + private HBox summaryRow() { + HBox row = new HBox(12); + row.getStyleClass().add("post-download-modal-summary"); + row.setAlignment(Pos.TOP_LEFT); + + VBox copy = new VBox(3); + copy.setMinWidth(0); + HBox.setHgrow(copy, Priority.ALWAYS); + Label description = new Label(title + " installed. Choose where it should be enabled."); + description.getStyleClass().add("post-download-modal-description"); + description.setWrapText(true); + selectedCount = new Label(); + selectedCount.getStyleClass().add("post-download-modal-muted"); + copy.getChildren().addAll(description, selectedCount); + + toggleAllButton = new Button(); + toggleAllButton.getStyleClass().add("post-download-modal-toggle-all"); + toggleAllButton.setMinWidth(Region.USE_PREF_SIZE); + toggleAllButton.setMaxWidth(Region.USE_PREF_SIZE); + toggleAllButton.setOnAction(event -> toggleAll()); + row.getChildren().addAll(copy, toggleAllButton); + return row; + } + + private HBox worldRow(WorldOption option) { + HBox row = new HBox(10); + row.getStyleClass().add("post-download-modal-world-row"); + row.setAlignment(Pos.CENTER_LEFT); + + String key = worldKey(option); + row.pseudoClassStateChanged(SELECTED, selectedWorldKeys.contains(key)); + row.pseudoClassStateChanged(INDETERMINATE, option.indeterminate()); + worldRows.put(key, row); + + LibraryToggleBox check = new LibraryToggleBox(); + check.getStyleClass().add("post-download-modal-check"); + check.setSelected(selectedWorldKeys.contains(key)); + check.setIndeterminate(option.indeterminate()); + check.setOnAction(() -> setWorldSelected(key, check.isSelected())); + worldChecks.put(key, check); + + StackPane icon = worldIcon(option.world()); + + VBox copy = new VBox(3); + Label name = new Label(option.world().name()); + name.getStyleClass().add("post-download-modal-world-title"); + Label meta = new Label(option.enabledCount() + "/" + option.totalCount() + " already enabled - " + option.meta()); + meta.getStyleClass().add("post-download-modal-world-meta"); + copy.getChildren().addAll(name, meta); + HBox.setHgrow(copy, Priority.ALWAYS); + + row.setOnMouseClicked(event -> { + if (event.getTarget() != check) { + check.setIndeterminate(false); + check.setSelected(!check.isSelected()); + setWorldSelected(key, check.isSelected()); + } + }); + row.getChildren().addAll(check, icon, copy); + return row; + } + + private StackPane worldIcon(HytaleWorld world) { + StackPane shell = new StackPane(); + shell.getStyleClass().add("post-download-modal-world-icon"); + + String preview = world == null ? "" : world.previewImage(); + if (!preview.isBlank() && imageLoader != null) { + ImageView image = new ImageView(); + image.setFitWidth(WORLD_ICON_IMAGE_SIZE); + image.setFitHeight(WORLD_ICON_IMAGE_SIZE); + image.setPreserveRatio(false); + image.setSmooth(true); + image.setMouseTransparent(true); + image.setClip(roundedClip(WORLD_ICON_IMAGE_SIZE, 10)); + imageLoader.loadInto(image, preview, WORLD_ICON_IMAGE_SIZE, WORLD_ICON_IMAGE_SIZE); + shell.getChildren().add(image); + } else { + shell.getChildren().add(LauncherIcons.icon(LauncherIcons.Glyph.GLOBE, 16)); + } + return shell; + } + + private HBox footer() { + HBox footer = new HBox(10); + footer.getStyleClass().add("post-download-modal-footer"); + footer.setAlignment(Pos.CENTER); + + Button skip = new Button("Not Now"); + skip.getStyleClass().add("post-download-modal-secondary"); + skip.setOnAction(event -> hide()); + + applyButton = new Button(); + applyButton.getStyleClass().add("post-download-modal-primary"); + applyButton.setMaxWidth(Double.MAX_VALUE); + applyButton.setAlignment(Pos.CENTER); + applyButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + applyButton.setGraphic(applyButtonContent()); + applyButton.setOnAction(event -> { + List selected = selectedWorlds(); + hide(); + apply.accept(new Selection(selected, modIds)); + }); + HBox.setHgrow(applyButton, Priority.ALWAYS); + footer.getChildren().addAll(skip, applyButton); + return footer; + } + + private VBox applyButtonContent() { + VBox content = new VBox(0); + content.setAlignment(Pos.CENTER); + content.setMaxWidth(Double.MAX_VALUE); + + HBox title = new HBox(8, LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 18), new Label("Enable Selected")); + title.getStyleClass().add("post-download-modal-primary-title"); + title.setAlignment(Pos.CENTER); + title.setMaxWidth(Double.MAX_VALUE); + content.getChildren().add(title); + return content; + } + + private void toggleAll() { + selectAll(selectedWorldKeys.size() != worlds.size()); + } + + private void selectAll(boolean selected) { + selectedWorldKeys.clear(); + for (WorldOption option : worlds) { + String key = worldKey(option); + LibraryToggleBox check = worldChecks.get(key); + HBox row = worldRows.get(key); + if (selected) { + selectedWorldKeys.add(key); + } + if (check != null) { + check.setIndeterminate(false); + check.setSelected(selected); + } + if (row != null) { + row.pseudoClassStateChanged(SELECTED, selected); + row.pseudoClassStateChanged(INDETERMINATE, false); + } + } + rebuildOverlay(); + } + + private void setWorldSelected(String key, boolean selected) { + if (selected) { + selectedWorldKeys.add(key); + } else { + selectedWorldKeys.remove(key); + } + HBox row = worldRows.get(key); + if (row != null) { + row.pseudoClassStateChanged(SELECTED, selected); + row.pseudoClassStateChanged(INDETERMINATE, false); + } + updateActionState(); + } + + private List selectedWorlds() { + List selected = new ArrayList<>(); + for (WorldOption option : worlds) { + if (selectedWorldKeys.contains(worldKey(option))) { + selected.add(option.world()); + } + } + return selected; + } + + private void updateActionState() { + if (applyButton != null) { + applyButton.setDisable(selectedWorldKeys.isEmpty()); + applyButton.setGraphic(applyButtonContent()); + } + if (selectedCount != null) { + int count = selectedWorldKeys.size(); + selectedCount.setText(count + " world" + LibraryProjectSupport.plural(count) + " selected"); + } + if (toggleAllButton != null) { + toggleAllButton.setText(selectedWorldKeys.size() == worlds.size() ? "Deselect All" : "Select All"); + } + } + + private void hide() { + if (overlay == null) { + return; + } + Parent parent = overlay.getParent(); + if (parent instanceof StackPane stack) { + stack.getChildren().remove(overlay); + } + overlay = null; + } + + private static String worldKey(WorldOption option) { + return option == null ? "" : worldKey(option.world()); + } + + private static String worldKey(HytaleWorld world) { + return world == null || world.directory() == null + ? "" + : world.directory().toAbsolutePath().normalize().toString(); + } + + private static String value(String value, String fallback) { + return value == null || value.isBlank() ? fallback : value; + } + + private static Rectangle roundedClip(double size, double radius) { + Rectangle clip = new Rectangle(size, size); + clip.setArcWidth(radius * 2); + clip.setArcHeight(radius * 2); + return clip; + } + + record WorldOption( + HytaleWorld world, + String meta, + int enabledCount, + int totalCount, + boolean selected, + boolean indeterminate + ) { + WorldOption { + meta = value(meta, "World save"); + totalCount = Math.max(0, totalCount); + enabledCount = Math.max(0, Math.min(enabledCount, totalCount)); + } + } + + record Selection(List worlds, List modIds) { + Selection { + worlds = worlds == null ? List.of() : List.copyOf(worlds); + modIds = modIds == null + ? List.of() + : modIds.stream() + .filter(id -> id != null && !id.isBlank()) + .map(String::trim) + .distinct() + .toList(); + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/play/LauncherPlayController.java b/launcher/src/main/java/net/modtale/launcher/ui/play/LauncherPlayController.java new file mode 100644 index 00000000..a3d2b931 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/play/LauncherPlayController.java @@ -0,0 +1,1980 @@ +package net.modtale.launcher.ui.play; + +import static net.modtale.launcher.ui.common.LauncherUi.dangerButton; +import static net.modtale.launcher.ui.common.LauncherUi.setVisibleManaged; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.Year; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.binding.Bindings; +import javafx.collections.FXCollections; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.geometry.Side; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.CustomMenuItem; +import javafx.scene.control.Label; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.Tooltip; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; +import javafx.util.StringConverter; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.api.ProjectSearchQuery; +import net.modtale.launcher.discord.DiscordRichPresenceService; +import net.modtale.launcher.hytale.HytaleApiClient; +import net.modtale.launcher.hytale.HytaleBlogPost; +import net.modtale.launcher.hytale.HytaleApiException; +import net.modtale.launcher.hytale.HytaleAuthService; +import net.modtale.launcher.hytale.HytaleAuthSession; +import net.modtale.launcher.hytale.HytaleFriend; +import net.modtale.launcher.hytale.HytaleGameVersionResolver; +import net.modtale.launcher.hytale.HytaleGameLauncher; +import net.modtale.launcher.hytale.HytaleLaunchResult; +import net.modtale.launcher.hytale.HytalePlatform; +import net.modtale.launcher.hytale.HytaleProfile; +import net.modtale.launcher.hytale.HytaleVersion; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.settings.LauncherSettings; +import net.modtale.launcher.ui.browse.card.ProjectCardFactory; +import net.modtale.launcher.ui.browse.card.ProjectCardViewStyle; +import net.modtale.launcher.ui.browse.controls.ProjectBrowseSort; +import net.modtale.launcher.ui.common.LauncherExternalLinks; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherView; +import net.modtale.launcher.ui.feedback.LauncherFeedback; +import net.modtale.launcher.ui.settings.LauncherSettingsController; +import net.modtale.launcher.ui.settings.LauncherSettingsForm; + +public final class LauncherPlayController { + + private static final int BLOG_POST_PAGE_SIZE = 4; + private static final int FRIEND_LIMIT = 6; + private static final double SIDEBAR_WIDTH = 336; + private static final double SIDEBAR_PREF_HEIGHT = 672; + private static final double BLOG_POST_LOAD_THRESHOLD = 0.82; + private static final double BLOG_POST_FILL_PADDING = 96; + private static final double NEWS_THUMBNAIL_WIDTH = 264; + private static final double NEWS_THUMBNAIL_HEIGHT = 149; + private static final double FRIEND_AVATAR_SIZE = 34; + private static final double IDENTITY_AVATAR_SIZE = 40; + private static final double IDENTITY_MENU_AVATAR_SIZE = 28; + private static final double PROFILE_AVATAR_RADIUS = 8; + private static final double PLAY_BUTTON_FONT_SIZE = 22; + private static final int CATALOG_SHELF_LIMIT = 6; + private static final double CATALOG_CARD_WIDTH = 336; + private static final double CATALOG_GRID_GAP = 18; + private static final double CATALOG_GRID_CARD_BODY_HEIGHT = 178; + private static final double CATALOG_CARD_HEIGHT = Math.round(CATALOG_CARD_WIDTH / 3.0) + CATALOG_GRID_CARD_BODY_HEIGHT; + private static final double CATALOG_SCROLL_HEIGHT = CATALOG_CARD_HEIGHT + 18; + private static final double CATALOG_STAGE_TOP_MARGIN = 8; + private static final double CATALOG_STAGE_LEFT_OFFSET = -12; + private static final double CATALOG_STAGE_GAP = 14; + private static final double CATALOG_SECTION_GAP = 8; + private static final double CATALOG_HEADER_HEIGHT = 30; + private static final double PLAY_DOCK_BOTTOM_MARGIN = 96; + private static final double PLAY_DOCK_CLEARANCE = 24; + private static final int HYVATAR_RENDER_SIZE = 256; + private static final DateTimeFormatter BLOG_DATE = DateTimeFormatter.ofPattern("MMM d").withZone(ZoneId.systemDefault()); + private static final DateTimeFormatter BLOG_DATE_WITH_YEAR = DateTimeFormatter.ofPattern("MMM d, yyyy").withZone(ZoneId.systemDefault()); + + private final ModtaleApiClient apiClient; + private final ProjectCardFactory projectCardFactory; + private final HytaleAuthService hytaleAuthService; + private final HytaleGameLauncher hytaleGameLauncher; + private final DiscordRichPresenceService discordRichPresence; + private final LauncherSettingsController settingsController; + private final LauncherFeedback feedback; + private final Executor executor; + private final BooleanSupplier modtaleApiAvailable; + private final Function favoriteResolver; + private final Supplier gameVersion; + private final Consumer onInstall; + private final Consumer onOpenPage; + private final Consumer onOpenCreator; + private final Consumer onToggleFavorite; + private final Label hytaleStatus = new Label("Hytale signed out"); + private final Label buildMetric = new Label("Unset"); + private final Label patchlineMetric = new Label("Latest release"); + private final Label playtimeMetric = new Label("No playtime yet"); + private final Button identityButton = new Button(); + private final StackPane identityAvatar = new StackPane(); + private final Label identityTitle = new Label("Signed out"); + private final Label identitySubtitle = new Label("Add Hytale account"); + private final VBox friendsList = new VBox(9); + private final VBox newsList = new VBox(12); + private final CatalogShelf newReleasesShelf = new CatalogShelf(ProjectBrowseSort.NEWEST); + private final CatalogShelf trendingShelf = new CatalogShelf(ProjectBrowseSort.TRENDING); + private final Map imageCache = new ConcurrentHashMap<>(); + + private volatile Process hytaleProcess; + private boolean versionsLoading; + private boolean suppressBranchVersionLoad; + private boolean friendsLoading; + private boolean playtimeLoading; + private boolean blogPostsLoading; + private boolean blogPostsLoaded; + private boolean blogPostsComplete; + private boolean blogFillCheckScheduled; + private List blogPosts = List.of(); + private int renderedBlogPosts; + private long versionLoadRetryAfterMillis; + private long versionRetryScheduledAtMillis; + private String loadedVersionsKey = ""; + private String loadedFriendsKey = ""; + private String loadedPlaytimeKey = ""; + private Node view; + private Node newReleasesSection; + private VBox setupPopover; + private ScrollPane sidebarScroll; + private ContextMenu identityMenu; + private long identityMenuHiddenAtMillis; + private Runnable onHytaleAccountsChanged = () -> { + }; + private Consumer onBrowseCatalog = sort -> { + }; + + public LauncherPlayController( + ModtaleApiClient apiClient, + ProjectCardFactory projectCardFactory, + HytaleAuthService hytaleAuthService, + HytaleGameLauncher hytaleGameLauncher, + DiscordRichPresenceService discordRichPresence, + LauncherSettingsController settingsController, + LauncherFeedback feedback, + Executor executor, + BooleanSupplier modtaleApiAvailable, + Function favoriteResolver, + Supplier gameVersion, + Consumer onInstall, + Consumer onOpenPage, + Consumer onOpenCreator, + Consumer onToggleFavorite + ) { + this.apiClient = apiClient; + this.projectCardFactory = projectCardFactory; + this.hytaleAuthService = hytaleAuthService; + this.hytaleGameLauncher = hytaleGameLauncher; + this.discordRichPresence = discordRichPresence; + this.settingsController = settingsController; + this.feedback = feedback; + this.executor = executor; + this.modtaleApiAvailable = modtaleApiAvailable == null ? () -> true : modtaleApiAvailable; + this.favoriteResolver = favoriteResolver == null ? id -> false : favoriteResolver; + this.gameVersion = gameVersion == null ? () -> "" : gameVersion; + this.onInstall = onInstall == null ? project -> { + } : onInstall; + this.onOpenPage = onOpenPage == null ? project -> { + } : onOpenPage; + this.onOpenCreator = onOpenCreator == null ? project -> { + } : onOpenCreator; + this.onToggleFavorite = onToggleFavorite == null ? project -> { + } : onToggleFavorite; + } + + public Node view() { + if (view == null) { + view = buildView(); + } + return view; + } + + public void setOnHytaleAccountsChanged(Runnable onHytaleAccountsChanged) { + this.onHytaleAccountsChanged = onHytaleAccountsChanged == null ? () -> { + } : onHytaleAccountsChanged; + } + + public void setOnBrowseCatalog(Consumer onBrowseCatalog) { + this.onBrowseCatalog = onBrowseCatalog == null ? sort -> { + } : onBrowseCatalog; + } + + public void syncMetrics() { + LauncherSettings settings = settingsController.settings(); + HytaleAuthSession session = settings.getHytaleAuthSession(); + syncIdentitySummary(settings, session); + buildMetric.setText(selectedVersionLabel(settings)); + syncPatchlineMetric(settings.getHytaleBranch()); + syncPlaytimeMetric(session); + syncSidebarData(settings, session); + syncCatalogShelves(false); + maybeLoadHytaleVersions(); + maybeLoadHytalePlaytime(); + } + + public void refreshCatalogShelves() { + resetCatalogShelf(newReleasesShelf); + resetCatalogShelf(trendingShelf); + syncCatalogShelves(true); + } + + public void resetCatalogShelves() { + resetCatalogShelf(newReleasesShelf); + resetCatalogShelf(trendingShelf); + showCatalogSignInMessage(); + } + + public void loadHytaleVersions() { + loadHytaleVersions(false); + } + + private void loadHytaleVersions(boolean force) { + LauncherSettings settings = settingsController.settings(); + HytaleAuthSession session = settings.getHytaleAuthSession(); + if (session == null || !session.hasRefreshToken()) { + return; + } + String versionKey = versionsKey(settings, session); + LauncherSettingsForm form = settingsController.form(); + applyCachedHytaleVersions(settings, session, form); + if (versionsLoading || (!force && versionKey.equals(loadedVersionsKey) && !form.hytaleVersionCombo().getItems().isEmpty())) { + return; + } + long now = System.currentTimeMillis(); + if (versionLoadRetryAfterMillis > now) { + return; + } + + versionsLoading = true; + form.hytaleVersionCombo().setPromptText("Loading builds"); + settingsController.saveFromFields(false); + feedback.log("Loading Hytale builds..."); + CompletableFuture.supplyAsync(() -> { + LauncherSettings currentSettings = settingsController.settings(); + return loadAllHytaleVersions(currentSettings, session); + }, executor).whenComplete((payload, error) -> Platform.runLater(() -> { + versionsLoading = false; + if (error != null) { + long retryDelay = versionLoadRetryDelayMillis(error); + versionLoadRetryAfterMillis = System.currentTimeMillis() + retryDelay; + boolean cached = applyCachedHytaleVersions(settingsController.settings(), session, form); + if (!cached) { + form.hytaleVersionCombo().setPromptText("Build unavailable"); + } + scheduleHytaleVersionRetry(retryDelay); + feedback.log(hytaleBuildLoadErrorMessage(error) + (cached ? " Using cached builds." : "")); + return; + } + cacheHytaleVersions(settingsController.settings(), session, payload); + form.setHytalePatchlines(payload.patchlines(), payload.selectedPatchline()); + List versions = payload.versionsForSelectedPatchline(); + if (versions.isEmpty() && payload.rateLimit() != null) { + versions = settingsController.settings().cachedHytaleVersions( + LauncherSettings.hytaleAccountId(session), + hytaleVersionCachePlatform(), + payload.selectedPatchline() + ); + } + if (payload.rateLimit() == null) { + loadedVersionsKey = versionsKey(settingsController.settings(), session); + } else { + loadedVersionsKey = ""; + } + form.hytaleVersionCombo().setPromptText("Choose build"); + form.hytaleVersionCombo().setItems(FXCollections.observableArrayList(versions)); + settingsController.selectConfiguredHytaleBuild(); + settingsController.saveFromFields(false); + long labeledVersions = versions.stream().filter(version -> !version.gameVersion().isBlank()).count(); + feedback.log(hytaleVersionLoadMessage(payload, versions.size(), labeledVersions)); + if (payload.rateLimit() == null) { + versionLoadRetryAfterMillis = 0; + versionRetryScheduledAtMillis = 0; + } else { + long retryDelay = versionLoadRetryDelayMillis(payload.rateLimit()); + versionLoadRetryAfterMillis = System.currentTimeMillis() + retryDelay; + scheduleHytaleVersionRetry(retryDelay); + } + syncMetrics(); + })); + } + + private HytaleVersionsPayload loadAllHytaleVersions(LauncherSettings settings, HytaleAuthSession session) { + String accountId = LauncherSettings.hytaleAccountId(session); + String platform = hytaleVersionCachePlatform(); + List cachedPatchlines = settings.cachedHytalePatchlines(accountId, platform); + List patchlines; + try { + patchlines = hytaleAuthService.getAvailablePatchlines(settings); + } catch (HytaleApiException ex) { + if (ex.statusCode() != 429 || cachedPatchlines.isEmpty()) { + throw ex; + } + String selectedPatchline = selectedPatchline(settings.getHytaleBranch(), cachedPatchlines); + List pending = refreshPatchlineOrder(settings, accountId, platform, cachedPatchlines, selectedPatchline); + return new HytaleVersionsPayload(cachedPatchlines, selectedPatchline, Map.of(), pending, ex); + } + + String selectedPatchline = selectedPatchline(settings.getHytaleBranch(), patchlines); + List refreshOrder = refreshPatchlineOrder(settings, accountId, platform, patchlines, selectedPatchline); + Map> versionsByPatchline = new LinkedHashMap<>(); + for (int index = 0; index < refreshOrder.size(); index++) { + String patchline = refreshOrder.get(index); + try { + versionsByPatchline.put(patchline, hytaleAuthService.getAvailableVersions(settings, patchline)); + } catch (HytaleApiException ex) { + if (ex.statusCode() != 429) { + throw ex; + } + return new HytaleVersionsPayload( + patchlines, + selectedPatchline, + versionsByPatchline, + refreshOrder.subList(index, refreshOrder.size()), + ex + ); + } + } + return new HytaleVersionsPayload(patchlines, selectedPatchline, versionsByPatchline, List.of(), null); + } + + private List refreshPatchlineOrder( + LauncherSettings settings, + String accountId, + String platform, + List patchlines, + String selectedPatchline + ) { + LinkedHashSet available = new LinkedHashSet<>(orderedPatchlines(patchlines)); + LinkedHashSet ordered = new LinkedHashSet<>(); + settings.pendingHytalePatchlines(accountId, platform).stream() + .map(HytaleApiClient::normalizeBranch) + .filter(available::contains) + .forEach(ordered::add); + String selected = HytaleApiClient.normalizeBranch(selectedPatchline); + if (available.contains(selected)) { + ordered.add(selected); + } + ordered.addAll(available); + return List.copyOf(ordered); + } + + private boolean applyCachedHytaleVersions(LauncherSettings settings, HytaleAuthSession session, LauncherSettingsForm form) { + String accountId = LauncherSettings.hytaleAccountId(session); + if (accountId.isBlank()) { + return false; + } + String platform = hytaleVersionCachePlatform(); + List cachedPatchlines = settings.cachedHytalePatchlines(accountId, platform); + String selectedPatchline = cachedPatchlines.isEmpty() + ? HytaleApiClient.normalizeBranch(settings.getHytaleBranch()) + : selectedPatchline(settings.getHytaleBranch(), cachedPatchlines); + if (!cachedPatchlines.isEmpty()) { + suppressBranchVersionLoad = true; + try { + form.setHytalePatchlines(cachedPatchlines, selectedPatchline); + } finally { + suppressBranchVersionLoad = false; + } + settings.setHytaleBranch(form.hytaleBranchCombo().getValue()); + } + List cachedVersions = settings.cachedHytaleVersions(accountId, platform, selectedPatchline); + if (cachedVersions.isEmpty()) { + return false; + } + form.hytaleVersionCombo().setPromptText("Choose build"); + form.hytaleVersionCombo().setItems(FXCollections.observableArrayList(cachedVersions)); + settingsController.selectConfiguredHytaleBuild(); + settingsController.applyFromFields(); + buildMetric.setText(selectedVersionLabel(settings)); + return true; + } + + private void cacheHytaleVersions(LauncherSettings settings, HytaleAuthSession session, HytaleVersionsPayload payload) { + String accountId = LauncherSettings.hytaleAccountId(session); + if (accountId.isBlank() || payload == null) { + return; + } + String platform = hytaleVersionCachePlatform(); + settings.cacheHytalePatchlines(accountId, platform, payload.patchlines()); + settings.cachePendingHytalePatchlines(accountId, platform, payload.pendingPatchlines()); + payload.versionsByPatchline().forEach((patchline, versions) -> + settings.cacheHytaleVersions(accountId, platform, patchline, versions)); + settingsController.saveCurrentSettings(); + } + + private static String hytaleVersionCachePlatform() { + return HytalePlatform.os() + "/" + HytalePlatform.arch(); + } + + private String hytaleVersionLoadMessage(HytaleVersionsPayload payload, int selectedBuildCount, long labeledVersions) { + int loadedPatchlines = payload.versionsByPatchline().size(); + int totalPatchlines = payload.patchlines().size(); + String selectedLabel = LauncherSettingsForm.hytalePatchlineLabel(payload.selectedPatchline()); + if (payload.rateLimit() != null) { + String next = payload.pendingPatchlines().isEmpty() + ? "" + : " Next refresh will start with " + LauncherSettingsForm.hytalePatchlineLabel(payload.pendingPatchlines().getFirst()) + "."; + return "Cached Hytale builds for " + loadedPatchlines + "/" + totalPatchlines + + " patchlines before rate limiting." + next; + } + if (selectedBuildCount == 0) { + return "Hytale did not expose any " + selectedLabel + " builds for this platform."; + } + return "Cached Hytale builds for " + loadedPatchlines + "/" + totalPatchlines + + " patchlines. " + selectedLabel + " has " + selectedBuildCount + " build" + plural(selectedBuildCount) + + (labeledVersions == 0 ? "." : " with " + labeledVersions + " official version label" + plural((int) labeledVersions) + "."); + } + + private void scheduleHytaleVersionRetry(long delayMillis) { + if (delayMillis <= 0) { + return; + } + long scheduledAt = System.currentTimeMillis() + delayMillis; + if (versionRetryScheduledAtMillis >= scheduledAt - 500) { + return; + } + versionRetryScheduledAtMillis = scheduledAt; + CompletableFuture.delayedExecutor(delayMillis, java.util.concurrent.TimeUnit.MILLISECONDS, executor) + .execute(() -> Platform.runLater(() -> { + if (System.currentTimeMillis() + 500 >= versionLoadRetryAfterMillis) { + loadHytaleVersions(false); + } + })); + } + + public void launchHytale() { + if (isHytaleRunning()) { + feedback.showToast("Already running", "Hytale is already running."); + return; + } + settingsController.saveFromFields(false); + feedback.runAsync("Launching Hytale...", () -> hytaleGameLauncher.launch(settingsController.settings()), result -> { + hytaleProcess = result.process(); + long startedAtMillis = System.currentTimeMillis(); + discordRichPresence.showPlayingHytale(selectedVersionLabel(settingsController.settings()), startedAtMillis); + monitorHytaleProcess(result, startedAtMillis); + String build = settingsController.settings().getHytaleBuild() > 0 + ? " build " + settingsController.settings().getHytaleBuild() + : ""; + feedback.log("Launched Hytale" + build + " as " + result.username() + "."); + feedback.showToast("Hytale ready", "Launching as " + result.username() + "."); + syncMetrics(); + }); + } + + private Node buildView() { + configureSelectors(); + + StackPane root = new StackPane(); + root.setUserData(LauncherView.PLAY); + root.getStyleClass().addAll("view", "play-view"); + root.setMinHeight(720); + root.setPrefHeight(720); + root.setMaxHeight(Double.MAX_VALUE); + + HBox shell = new HBox(34); + shell.getStyleClass().add("play-shell"); + shell.setAlignment(Pos.CENTER_LEFT); + shell.setFillHeight(true); + shell.setMaxHeight(Double.MAX_VALUE); + StackPane.setAlignment(shell, Pos.CENTER); + + StackPane stage = new StackPane(); + stage.getStyleClass().add("play-stage"); + stage.setMinWidth(0); + stage.setMaxWidth(Double.MAX_VALUE); + stage.setMinHeight(0); + stage.setMaxHeight(Double.MAX_VALUE); + Node catalog = catalogStage(); + if (catalog instanceof Region catalogRegion) { + catalogRegion.prefWidthProperty().bind(stage.widthProperty()); + } + stage.getChildren().add(catalog); + HBox.setHgrow(stage, Priority.ALWAYS); + + VBox dock = new VBox(0); + dock.getStyleClass().add("play-dock"); + dock.setAlignment(Pos.CENTER); + dock.setFillWidth(false); + dock.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + dock.getChildren().add(launchControl()); + + setupPopover = setupPopover(); + setVisibleManaged(setupPopover, false); + + Node sidebar = sidebarFrame(); + HBox.setHgrow(sidebar, Priority.NEVER); + shell.getChildren().addAll(stage, sidebar); + root.getChildren().addAll(shell, dock, setupPopover); + StackPane.setAlignment(dock, Pos.BOTTOM_CENTER); + StackPane.setMargin(dock, new Insets(0, 0, PLAY_DOCK_BOTTOM_MARGIN, 0)); + StackPane.setAlignment(setupPopover, Pos.BOTTOM_CENTER); + StackPane.setMargin(setupPopover, new Insets(0, 0, 184, 0)); + bindNewReleasesVisibility(root, dock); + syncMetrics(); + return root; + } + + private Node catalogStage() { + VBox content = new VBox(CATALOG_STAGE_GAP); + content.getStyleClass().add("play-catalog-stage"); + content.setAlignment(Pos.TOP_LEFT); + content.setFillWidth(true); + content.setMinWidth(0); + content.setMaxWidth(Double.MAX_VALUE); + Node trendingSection = catalogShelf(trendingShelf, "Trending"); + newReleasesSection = catalogShelf(newReleasesShelf, "New Releases"); + content.getChildren().addAll(trendingSection, newReleasesSection); + StackPane.setAlignment(content, Pos.TOP_LEFT); + StackPane.setMargin(content, new Insets(CATALOG_STAGE_TOP_MARGIN, 0, 0, CATALOG_STAGE_LEFT_OFFSET)); + return content; + } + + private Node catalogShelf(CatalogShelf shelf, String title) { + VBox section = new VBox(CATALOG_SECTION_GAP); + section.getStyleClass().add("play-catalog-section"); + section.setMinWidth(0); + section.setMaxWidth(Double.MAX_VALUE); + section.setFillWidth(true); + section.setAlignment(Pos.TOP_LEFT); + section.getChildren().addAll(catalogHeader(shelf, title), catalogBody(shelf)); + return section; + } + + private Node catalogHeader(CatalogShelf shelf, String title) { + HBox header = new HBox(10); + header.getStyleClass().add("play-catalog-header"); + header.setAlignment(Pos.CENTER_LEFT); + header.setMinWidth(0); + header.setMaxWidth(Double.MAX_VALUE); + + Label label = new Label(title); + label.getStyleClass().add("play-catalog-title"); + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + Button browse = new Button("Browse All", LauncherIcons.icon(LauncherIcons.Glyph.EXTERNAL_LINK, 13)); + browse.getStyleClass().add("play-catalog-browse-all"); + browse.setTooltip(new Tooltip("Browse all " + title.toLowerCase())); + browse.setAccessibleText("Browse all " + title.toLowerCase()); + browse.setOnAction(event -> onBrowseCatalog.accept(shelf.sort)); + + header.getChildren().addAll(label, spacer, browse); + return header; + } + + private Node catalogBody(CatalogShelf shelf) { + StackPane body = new StackPane(); + body.getStyleClass().add("play-catalog-body"); + body.setAlignment(Pos.TOP_LEFT); + body.setMinWidth(0); + body.setMaxWidth(Double.MAX_VALUE); + + shelf.cardRow.getStyleClass().add("play-catalog-card-row"); + shelf.cardRow.setSpacing(CATALOG_GRID_GAP); + shelf.cardRow.setAlignment(Pos.TOP_LEFT); + + shelf.scroll.getStyleClass().add("play-catalog-scroll"); + shelf.scroll.setContent(shelf.cardRow); + shelf.scroll.setFitToHeight(true); + shelf.scroll.setFitToWidth(false); + shelf.scroll.setPannable(true); + shelf.scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + shelf.scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + shelf.scroll.setMinSize(0, CATALOG_SCROLL_HEIGHT); + shelf.scroll.setPrefSize(0, CATALOG_SCROLL_HEIGHT); + shelf.scroll.setMaxSize(Double.MAX_VALUE, CATALOG_SCROLL_HEIGHT); + + shelf.message.getStyleClass().add("play-catalog-message"); + shelf.message.setWrapText(true); + shelf.message.setAlignment(Pos.CENTER); + shelf.message.setMaxWidth(Double.MAX_VALUE); + + body.getChildren().addAll(shelf.scroll, shelf.message); + showCatalogMessage(shelf, "Loading projects..."); + return body; + } + + private void bindNewReleasesVisibility(StackPane root, Region dock) { + if (newReleasesSection == null) { + return; + } + BooleanBinding hasVerticalRoom = Bindings.createBooleanBinding( + () -> root.getHeight() >= newReleasesRequiredHeight(dockHeight(dock)), + root.heightProperty(), + dock.layoutBoundsProperty() + ); + newReleasesSection.visibleProperty().bind(hasVerticalRoom); + newReleasesSection.managedProperty().bind(hasVerticalRoom); + } + + private static double newReleasesRequiredHeight(double dockHeight) { + return CATALOG_STAGE_TOP_MARGIN + + (catalogShelfHeight() * 2) + + CATALOG_STAGE_GAP + + PLAY_DOCK_BOTTOM_MARGIN + + dockHeight + + PLAY_DOCK_CLEARANCE; + } + + private static double catalogShelfHeight() { + return CATALOG_HEADER_HEIGHT + CATALOG_SECTION_GAP + CATALOG_SCROLL_HEIGHT; + } + + private static double dockHeight(Region dock) { + double height = dock.getLayoutBounds().getHeight(); + if (height <= 0 || Double.isNaN(height)) { + height = dock.prefHeight(-1); + } + return height <= 0 || Double.isNaN(height) ? 80 : height; + } + + private Node launchControl() { + VBox control = new VBox(9); + control.getStyleClass().add("play-launch-control"); + control.setAlignment(Pos.CENTER); + control.setMaxWidth(Region.USE_PREF_SIZE); + + HBox split = new HBox(0); + split.getStyleClass().add("play-launch-split"); + split.setAlignment(Pos.CENTER); + split.setMaxWidth(Region.USE_PREF_SIZE); + + Button play = new Button("Play"); + play.getStyleClass().add("play-launch-main"); + play.setFont(Font.font("Inter", FontWeight.EXTRA_BOLD, PLAY_BUTTON_FONT_SIZE)); + play.setOnAction(event -> launchHytale()); + + Button setup = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_DOWN, 20)); + setup.getStyleClass().add("play-launch-arrow"); + setup.setTooltip(new Tooltip("Select launch build")); + setup.setOnAction(event -> showLaunchDropdown(setup)); + + split.getChildren().addAll(play, setup); + + HBox meta = new HBox(10); + meta.getStyleClass().add("play-launch-meta"); + meta.setAlignment(Pos.CENTER); + meta.getChildren().addAll( + launchMetaText("Version", buildMetric), + launchMetaText("Patchline", patchlineMetric), + launchMetaText("Playtime", playtimeMetric) + ); + + control.getChildren().addAll(split, meta); + return control; + } + + private Node launchMetaText(String label, Label valueLabel) { + HBox item = new HBox(5); + item.getStyleClass().add("play-launch-meta-item"); + item.setAlignment(Pos.CENTER_LEFT); + Label heading = new Label(label); + heading.getStyleClass().add("play-launch-meta-label"); + valueLabel.getStyleClass().add("play-launch-meta-value"); + item.getChildren().addAll(heading, valueLabel); + return item; + } + + private VBox setupPopover() { + VBox panel = new VBox(18); + panel.getStyleClass().add("play-setup-popover"); + panel.setAlignment(Pos.TOP_CENTER); + panel.setPrefWidth(430); + panel.setMaxWidth(430); + + Label title = new Label("Launch Setup"); + title.getStyleClass().add("play-panel-title"); + Label status = hytaleStatus; + status.getStyleClass().add("play-panel-status"); + + panel.getChildren().addAll(title, status, setupActions()); + return panel; + } + + private Node setupActions() { + Button stop = dangerButton("Stop"); + stop.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.X, 15)); + stop.setOnAction(event -> stopHytale()); + + FlowPane utilities = new FlowPane(10, 10, stop); + utilities.getStyleClass().add("play-utility-actions"); + utilities.setAlignment(Pos.CENTER); + return utilities; + } + + private Node sidebarFrame() { + StackPane frame = new StackPane(); + frame.getStyleClass().add("play-sidebar-frame"); + frame.setMinHeight(0); + frame.setMaxHeight(Double.MAX_VALUE); + Node scroll = sidebar(); + frame.getChildren().add(scroll); + return frame; + } + + private Node sidebar() { + VBox sidebar = new VBox(18); + sidebar.getStyleClass().add("play-sidebar"); + sidebar.getChildren().addAll( + identitySection(), + friendsSection(), + newsSection() + ); + + ScrollPane scroll = new ScrollPane(sidebar); + scroll.getStyleClass().add("play-sidebar-scroll"); + scroll.setFitToWidth(true); + scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + scroll.setPannable(true); + scroll.setPrefWidth(SIDEBAR_WIDTH); + scroll.setMinWidth(SIDEBAR_WIDTH); + scroll.setMaxWidth(SIDEBAR_WIDTH); + scroll.setMinHeight(0); + scroll.setPrefHeight(SIDEBAR_PREF_HEIGHT); + scroll.setMaxHeight(Double.MAX_VALUE); + scroll.vvalueProperty().addListener((observable, previous, value) -> maybeAppendBlogPosts(false)); + scroll.viewportBoundsProperty().addListener((observable, previous, value) -> scheduleBlogFillCheck()); + sidebar.heightProperty().addListener((observable, previous, value) -> scheduleBlogFillCheck()); + sidebarScroll = scroll; + return scroll; + } + + private Node identitySection() { + VBox section = sidebarSection("Playing as"); + configureIdentityButton(); + section.getChildren().add(identityButton); + return section; + } + + private Node friendsSection() { + VBox section = sidebarSection(); + section.getChildren().add(sectionHeader("Friends", LauncherIcons.Glyph.REFRESH_CW, "Refresh Hytale friends", + () -> loadHytaleFriends(true))); + friendsList.getStyleClass().add("play-friends-list"); + section.getChildren().add(friendsList); + return section; + } + + private Node newsSection() { + VBox section = sidebarSection(); + section.getStyleClass().add("last"); + section.getChildren().add(sectionHeader("News", LauncherIcons.Glyph.EXTERNAL_LINK, "Open Hytale blog", + () -> LauncherExternalLinks.open("https://hytale.com/news", feedback::showToast))); + newsList.getStyleClass().add("play-news-list"); + section.getChildren().add(newsList); + return section; + } + + private VBox sidebarSection(String title) { + VBox section = new VBox(11); + section.getStyleClass().add("play-sidebar-section"); + Label heading = new Label(title); + heading.getStyleClass().add("play-sidebar-section-title"); + section.getChildren().add(heading); + return section; + } + + private VBox sidebarSection() { + VBox section = new VBox(11); + section.getStyleClass().add("play-sidebar-section"); + return section; + } + + private Node sectionHeader(String title, LauncherIcons.Glyph glyph, String tooltip, Runnable action) { + HBox header = new HBox(10); + header.getStyleClass().add("play-sidebar-header"); + header.setAlignment(Pos.CENTER_LEFT); + Label label = new Label(title); + label.getStyleClass().add("play-sidebar-section-title"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Button button = new Button(null, LauncherIcons.icon(glyph, 15)); + button.getStyleClass().addAll("icon-btn", "play-sidebar-icon-button"); + button.setTooltip(new Tooltip(tooltip)); + button.setAccessibleText(tooltip); + button.setOnAction(event -> action.run()); + header.getChildren().addAll(label, spacer, button); + return header; + } + + private void configureIdentityButton() { + if (identityButton.getGraphic() != null) { + return; + } + identityButton.getStyleClass().add("play-identity-button"); + identityButton.setAccessibleText("Manage Hytale account and game profile"); + identityButton.setTooltip(new Tooltip("Manage Hytale account and game profile")); + identityButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + identityButton.setMaxWidth(Double.MAX_VALUE); + + HBox content = new HBox(11); + content.getStyleClass().add("play-identity-button-content"); + content.setAlignment(Pos.CENTER_LEFT); + identityAvatar.getStyleClass().add("play-identity-avatar"); + sizeSquare(identityAvatar, IDENTITY_AVATAR_SIZE); + updateImageAvatar(identityAvatar, "Hytale", IDENTITY_AVATAR_SIZE, PROFILE_AVATAR_RADIUS, ""); + + VBox copy = new VBox(3); + identityTitle.getStyleClass().add("play-identity-title"); + identitySubtitle.getStyleClass().add("play-identity-subtitle"); + identityTitle.setMaxWidth(Double.MAX_VALUE); + identitySubtitle.setMaxWidth(Double.MAX_VALUE); + copy.getChildren().addAll(identityTitle, identitySubtitle); + HBox.setHgrow(copy, Priority.ALWAYS); + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + StackPane chevron = new StackPane(LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_DOWN, 16)); + chevron.getStyleClass().add("play-identity-chevron"); + content.getChildren().addAll(identityAvatar, copy, spacer, chevron); + identityButton.setGraphic(content); + identityButton.setOnAction(event -> toggleIdentityMenu(identityButton)); + } + + private void configureSelectors() { + LauncherSettingsForm form = settingsController.form(); + form.hytaleBranchCombo().setPromptText("Channel"); + form.hytaleVersionCombo().setPromptText("Load builds"); + form.hytaleVersionCombo().setConverter(new StringConverter<>() { + @Override + public String toString(HytaleVersion version) { + return version == null ? "" : versionSwitchLabel(version); + } + + @Override + public HytaleVersion fromString(String value) { + return form.hytaleVersionCombo().getItems().stream() + .filter(version -> versionSwitchLabel(version).equals(value)) + .findFirst() + .orElse(null); + } + }); + form.hytaleVersionCombo().valueProperty().addListener((observable, previous, selected) -> { + if (selected != null) { + buildMetric.setText(versionSwitchLabel(selected)); + } else { + buildMetric.setText(selectedVersionLabel(settingsController.settings())); + } + }); + form.hytaleBranchCombo().valueProperty().addListener((observable, previous, selected) -> { + if (!suppressBranchVersionLoad && selected != null && !selected.equals(previous)) { + loadedVersionsKey = ""; + syncPatchlineMetric(selected); + maybeLoadHytaleVersions(); + } + }); + } + + private void syncSidebarData(LauncherSettings settings, HytaleAuthSession session) { + if (session == null) { + loadedFriendsKey = ""; + setFriendsMessage("Sign in with Hytale to see friends."); + } else { + String friendsKey = LauncherSettings.hytaleAccountId(session); + if (!friendsKey.equals(loadedFriendsKey) && !friendsLoading) { + loadHytaleFriends(false); + } + } + if (!blogPostsLoaded && !blogPostsLoading) { + loadBlogPosts(); + } + } + + private void syncCatalogShelves(boolean force) { + if (!modtaleApiAvailable.getAsBoolean()) { + showCatalogSignInMessage(); + return; + } + loadCatalogShelf(newReleasesShelf, force); + loadCatalogShelf(trendingShelf, force); + } + + private void loadCatalogShelf(CatalogShelf shelf, boolean force) { + if (!modtaleApiAvailable.getAsBoolean()) { + resetCatalogShelf(shelf); + showCatalogMessage(shelf, "Sign in with Modtale to see " + shelf.sort.title().toLowerCase() + "."); + return; + } + if (shelf.loading && !force) { + return; + } + if (shelf.loaded && !force) { + return; + } + shelf.loading = true; + long requestId = ++shelf.requestId; + showCatalogMessage(shelf, "Loading projects..."); + CompletableFuture.supplyAsync(() -> apiClient.searchProjects(catalogQuery(shelf.sort)), executor) + .whenComplete((page, error) -> Platform.runLater(() -> { + if (requestId != shelf.requestId) { + return; + } + shelf.loading = false; + if (error != null) { + Throwable cause = unwrap(error); + String detail = cause == null || cause.getMessage() == null || cause.getMessage().isBlank() + ? "Try refreshing in a moment." + : cause.getMessage(); + showCatalogMessage(shelf, "Could not load " + shelf.sort.title().toLowerCase() + ". " + detail); + return; + } + shelf.loaded = true; + renderCatalogShelf(shelf, page == null ? List.of() : page.content()); + })); + } + + private ProjectSearchQuery catalogQuery(ProjectBrowseSort sort) { + return new ProjectSearchQuery( + "", + null, + null, + sort.apiValue(), + 0, + CATALOG_SHELF_LIMIT, + null, + null, + null, + null, + null, + null + ); + } + + private void renderCatalogShelf(CatalogShelf shelf, List projects) { + shelf.cardRow.getChildren().clear(); + if (projects.isEmpty()) { + showCatalogMessage(shelf, "No " + shelf.sort.title().toLowerCase() + " found."); + return; + } + setVisibleManaged(shelf.message, false); + setVisibleManaged(shelf.scroll, true); + int cardCount = Math.min(projects.size(), CATALOG_SHELF_LIMIT); + String selectedGameVersion = gameVersion.get(); + for (int index = 0; index < cardCount; index++) { + ProjectSummary project = projects.get(index); + shelf.cardRow.getChildren().add(catalogProjectCard(project, selectedGameVersion)); + } + shelf.scroll.setHvalue(shelf.scroll.getHmin()); + } + + private Node catalogProjectCard(ProjectSummary project, String selectedGameVersion) { + return projectCardFactory.create( + project, + ProjectCardViewStyle.GRID, + selectedGameVersion, + Boolean.TRUE.equals(favoriteResolver.apply(project.id())), + onInstall, + onOpenPage, + onOpenCreator, + onToggleFavorite, + CATALOG_CARD_WIDTH, + CATALOG_CARD_HEIGHT + ); + } + + private void showCatalogSignInMessage() { + showCatalogMessage(newReleasesShelf, "Sign in with Modtale to see new releases."); + showCatalogMessage(trendingShelf, "Sign in with Modtale to see trending projects."); + } + + private void showCatalogMessage(CatalogShelf shelf, String message) { + shelf.cardRow.getChildren().clear(); + shelf.message.setText(message == null ? "" : message); + setVisibleManaged(shelf.scroll, false); + setVisibleManaged(shelf.message, true); + } + + private void resetCatalogShelf(CatalogShelf shelf) { + shelf.requestId++; + shelf.loading = false; + shelf.loaded = false; + shelf.cardRow.getChildren().clear(); + } + + private void syncIdentitySummary(LauncherSettings settings, HytaleAuthSession session) { + if (session == null) { + hytaleStatus.setText("Signed out"); + identityTitle.setText("Signed out"); + identitySubtitle.setText("Add Hytale account"); + updateImageAvatar(identityAvatar, "Hytale", IDENTITY_AVATAR_SIZE, PROFILE_AVATAR_RADIUS, ""); + return; + } + + List profiles = profilesFor(session); + HytaleProfile selectedProfile = selectedProfileFor(session); + String selectedProfileName = selectedProfile.displayName(); + updateHytaleProfileAvatar(identityAvatar, selectedProfileName, IDENTITY_AVATAR_SIZE); + hytaleStatus.setText("Ready as " + selectedProfileName); + identityTitle.setText(selectedProfileName); + String account = accountLabel(session); + String profileCount = profiles.size() <= 1 ? "Hytale account" : profiles.size() + " profiles"; + identitySubtitle.setText(account.equals(selectedProfileName) ? profileCount : account + " - " + profileCount); + } + + private String formatPlaytime(long seconds) { + if (seconds <= 0) { + return "No playtime yet"; + } + long minutes = Math.max(1, seconds / 60); + long hours = minutes / 60; + long days = hours / 24; + if (days > 0) { + return days + "d " + (hours % 24) + "h played"; + } + if (hours > 0) { + return hours + "h " + (minutes % 60) + "m played"; + } + return minutes + "m played"; + } + + private void syncPlaytimeMetric(HytaleAuthSession session) { + if (session == null || !session.hasRefreshToken()) { + loadedPlaytimeKey = ""; + playtimeMetric.setText("No playtime yet"); + return; + } + if (playtimeLoading) { + playtimeMetric.setText("Loading playtime..."); + return; + } + playtimeMetric.setText(formatPlaytime(selectedProfileFor(session).playtimeSeconds())); + } + + private void loadHytalePlaytime(boolean force) { + LauncherSettings settings = settingsController.settings(); + HytaleAuthSession session = settings.getHytaleAuthSession(); + if (session == null || !session.hasRefreshToken()) { + loadedPlaytimeKey = ""; + playtimeMetric.setText("No playtime yet"); + return; + } + String playtimeKey = playtimeKey(session); + if (playtimeLoading || (!force && playtimeKey.equals(loadedPlaytimeKey))) { + return; + } + + playtimeLoading = true; + playtimeMetric.setText("Loading playtime..."); + CompletableFuture.supplyAsync(() -> hytaleAuthService.getProfilePlaytimeSeconds(settingsController.settings()), executor) + .whenComplete((seconds, error) -> Platform.runLater(() -> { + playtimeLoading = false; + HytaleAuthSession activeSession = settingsController.settings().getHytaleAuthSession(); + String activeKey = activeSession == null ? "" : playtimeKey(activeSession); + if (error != null && requiresHytaleSignIn(error)) { + loadedPlaytimeKey = ""; + settingsController.reloadControls(); + syncMetrics(); + onHytaleAccountsChanged.run(); + return; + } + if (!playtimeKey.equals(activeKey)) { + return; + } + if (error != null) { + loadedPlaytimeKey = playtimeKey; + playtimeMetric.setText(playtimeErrorMessage(error)); + return; + } + loadedPlaytimeKey = playtimeKey; + playtimeMetric.setText(formatPlaytime(seconds == null ? 0 : seconds)); + })); + } + + private void loadHytaleFriends(boolean force) { + LauncherSettings settings = settingsController.settings(); + HytaleAuthSession session = settings.getHytaleAuthSession(); + if (session == null || !session.hasRefreshToken()) { + loadedFriendsKey = ""; + setFriendsMessage("Sign in with Hytale to see friends."); + return; + } + String friendsKey = LauncherSettings.hytaleAccountId(session); + if (friendsLoading || (!force && friendsKey.equals(loadedFriendsKey))) { + return; + } + friendsLoading = true; + setFriendsMessage("Loading Hytale friends..."); + CompletableFuture.supplyAsync(() -> hytaleAuthService.getFriends(settingsController.settings()), executor) + .whenComplete((friends, error) -> Platform.runLater(() -> { + friendsLoading = false; + HytaleAuthSession activeSession = settingsController.settings().getHytaleAuthSession(); + String activeKey = activeSession == null ? "" : LauncherSettings.hytaleAccountId(activeSession); + if (error != null && requiresHytaleSignIn(error)) { + loadedFriendsKey = ""; + settingsController.reloadControls(); + syncMetrics(); + onHytaleAccountsChanged.run(); + return; + } + if (!friendsKey.equals(activeKey)) { + return; + } + if (error != null) { + setFriendsMessage(friendsErrorMessage(error)); + return; + } + loadedFriendsKey = friendsKey; + renderFriends(friends == null ? List.of() : friends); + })); + } + + private void renderFriends(List friends) { + friendsList.getChildren().clear(); + if (friends.isEmpty()) { + friendsList.getChildren().add(messageRow("No Hytale friends were returned for this account.")); + return; + } + friends.stream() + .limit(FRIEND_LIMIT) + .map(this::friendRow) + .forEach(friendsList.getChildren()::add); + if (friends.size() > FRIEND_LIMIT) { + friendsList.getChildren().add(messageRow("+" + (friends.size() - FRIEND_LIMIT) + " more in-game.")); + } + } + + private Node friendRow(HytaleFriend friend) { + HBox row = new HBox(10); + row.getStyleClass().add("play-friend-row"); + row.setAlignment(Pos.CENTER_LEFT); + + StackPane avatar = friend.username().isBlank() + ? avatar(friend.displayName(), FRIEND_AVATAR_SIZE, "play-friend-avatar", friend.avatarUrl()) + : hytaleProfileAvatar(friend.username(), FRIEND_AVATAR_SIZE, "play-friend-avatar"); + Region presence = new Region(); + presence.getStyleClass().addAll("play-friend-presence", friend.online() ? "online" : "offline"); + StackPane.setAlignment(presence, Pos.BOTTOM_RIGHT); + avatar.getChildren().add(presence); + + VBox copy = new VBox(2); + Label name = new Label(friend.displayName()); + name.getStyleClass().add("play-friend-name"); + Label status = new Label(friend.displayStatus()); + status.getStyleClass().add("play-friend-status"); + copy.getChildren().addAll(name, status); + HBox.setHgrow(copy, Priority.ALWAYS); + + row.getChildren().addAll(avatar, copy); + return row; + } + + private void setFriendsMessage(String message) { + friendsList.getChildren().setAll(messageRow(message)); + } + + private static String friendsErrorMessage(Throwable error) { + Throwable cause = unwrap(error); + if (cause instanceof HytaleApiException hytaleEx && hytaleEx.requiresSignIn()) { + return "Sign in with Hytale to see friends."; + } + return "Friends are available in-game. Modtale could not read a launcher friend list yet."; + } + + private static String playtimeErrorMessage(Throwable error) { + Throwable cause = unwrap(error); + if (cause instanceof HytaleApiException hytaleEx && hytaleEx.requiresSignIn()) { + return "Sign in required"; + } + return "Playtime unavailable"; + } + + private static String hytaleBuildLoadErrorMessage(Throwable error) { + Throwable cause = unwrap(error); + if (cause instanceof HytaleApiException hytaleEx && hytaleEx.statusCode() == 429) { + long seconds = Math.max(1, versionLoadRetryDelayMillis(error) / 1000); + return "Hytale build API is rate limited. Waiting " + seconds + "s before refreshing builds again."; + } + String message = cause == null ? "" : cause.getMessage(); + return message == null || message.isBlank() + ? "Could not load Hytale builds." + : "Could not load Hytale builds: " + message; + } + + private static long versionLoadRetryDelayMillis(Throwable error) { + Throwable cause = unwrap(error); + if (cause instanceof HytaleApiException hytaleEx && hytaleEx.statusCode() == 429) { + return hytaleEx.retryAfterMillis() > 0 ? hytaleEx.retryAfterMillis() : 60_000; + } + return 15_000; + } + + private static boolean requiresHytaleSignIn(Throwable error) { + Throwable cause = unwrap(error); + return cause instanceof HytaleApiException hytaleEx && hytaleEx.requiresSignIn(); + } + + private static Throwable unwrap(Throwable error) { + Throwable cause = error; + while (cause instanceof CompletionException && cause.getCause() != null) { + cause = cause.getCause(); + } + return cause == null ? error : cause; + } + + private void loadBlogPosts() { + blogPostsLoading = true; + blogPostsComplete = false; + newsList.getChildren().setAll(messageRow("Loading Hytale posts...")); + CompletableFuture.supplyAsync(hytaleAuthService::getAllBlogPosts, executor) + .whenComplete((posts, error) -> Platform.runLater(() -> { + blogPostsLoading = false; + if (error != null) { + newsList.getChildren().setAll(messageRow("Could not load the Hytale blog.")); + return; + } + blogPostsLoaded = true; + renderInitialBlogPosts(posts == null ? List.of() : posts); + })); + } + + private void renderInitialBlogPosts(List posts) { + blogPosts = posts; + renderedBlogPosts = 0; + blogPostsComplete = posts.isEmpty(); + newsList.getChildren().clear(); + if (posts.isEmpty()) { + newsList.getChildren().add(messageRow("No Hytale blog posts found.")); + return; + } + appendNextBlogPosts(); + scheduleBlogFillCheck(); + } + + private void maybeAppendBlogPosts(boolean fillViewport) { + if (blogPostsLoading || !blogPostsLoaded || blogPostsComplete || sidebarScroll == null) { + return; + } + if (renderedBlogPosts >= blogPosts.size()) { + markBlogPostsComplete(); + return; + } + double viewportHeight = sidebarScroll.getViewportBounds().getHeight(); + double contentHeight = sidebarScroll.getContent() == null + ? 0 + : sidebarScroll.getContent().getBoundsInLocal().getHeight(); + boolean contentShort = viewportHeight <= 0 || contentHeight <= viewportHeight + BLOG_POST_FILL_PADDING; + boolean nearBottom = sidebarScroll.getVvalue() >= BLOG_POST_LOAD_THRESHOLD; + if (!fillViewport && !nearBottom) { + return; + } + if (fillViewport && !contentShort && !nearBottom) { + return; + } + appendNextBlogPosts(); + if (fillViewport) { + scheduleBlogFillCheck(); + } + } + + private void appendNextBlogPosts() { + int nextCount = Math.min(renderedBlogPosts + BLOG_POST_PAGE_SIZE, blogPosts.size()); + for (int index = renderedBlogPosts; index < nextCount; index++) { + newsList.getChildren().add(blogPostRow(blogPosts.get(index))); + } + renderedBlogPosts = nextCount; + if (renderedBlogPosts >= blogPosts.size()) { + markBlogPostsComplete(); + } + } + + private void markBlogPostsComplete() { + if (blogPostsComplete) { + return; + } + blogPostsComplete = true; + newsList.getChildren().add(messageRow("End of Hytale RSS feed.")); + } + + private void scheduleBlogFillCheck() { + if (blogFillCheckScheduled) { + return; + } + blogFillCheckScheduled = true; + Platform.runLater(() -> { + blogFillCheckScheduled = false; + maybeAppendBlogPosts(true); + }); + } + + private Node blogPostRow(HytaleBlogPost post) { + VBox row = new VBox(7); + row.getStyleClass().add("play-news-card"); + row.setAlignment(Pos.TOP_LEFT); + row.setOnMouseClicked(event -> LauncherExternalLinks.open(post.url(), feedback::showToast)); + + StackPane thumbnail = newsThumbnail(post); + + Label title = new Label(value(post.title(), "Hytale Blog")); + title.getStyleClass().add("play-news-title"); + title.setWrapText(true); + Label date = new Label(formatBlogDate(post.publishedAt())); + date.getStyleClass().add("play-news-date"); + + row.getChildren().addAll(thumbnail, title, date); + return row; + } + + private StackPane newsThumbnail(HytaleBlogPost post) { + Label initial = new Label(initialFor(post.title())); + initial.getStyleClass().add("play-news-initial"); + StackPane thumbnail = new StackPane(initial); + thumbnail.getStyleClass().add("play-news-thumbnail"); + thumbnail.setMinSize(NEWS_THUMBNAIL_WIDTH, NEWS_THUMBNAIL_HEIGHT); + thumbnail.setPrefSize(NEWS_THUMBNAIL_WIDTH, NEWS_THUMBNAIL_HEIGHT); + thumbnail.setMaxSize(NEWS_THUMBNAIL_WIDTH, NEWS_THUMBNAIL_HEIGHT); + if (post.imageUrl() != null && !post.imageUrl().isBlank()) { + ImageView image = containedImageView(post.imageUrl(), NEWS_THUMBNAIL_WIDTH, NEWS_THUMBNAIL_HEIGHT); + image.getStyleClass().add("play-news-image"); + Rectangle clip = new Rectangle(NEWS_THUMBNAIL_WIDTH, NEWS_THUMBNAIL_HEIGHT); + clip.setArcWidth(14); + clip.setArcHeight(14); + image.setClip(clip); + thumbnail.getChildren().add(image); + } + return thumbnail; + } + + private ImageView containedImageView(String imageUrl, double width, double height) { + Image image = cachedImage(imageUrl, 0, 0, true, false); + ImageView imageView = new ImageView(image); + imageView.setFitWidth(width); + imageView.setFitHeight(height); + imageView.setPreserveRatio(true); + imageView.setSmooth(true); + return imageView; + } + + private Node messageRow(String message) { + Label label = new Label(message == null ? "" : message); + label.getStyleClass().add("play-sidebar-message"); + label.setWrapText(true); + return label; + } + + private StackPane avatar(String name, double size, String styleClass, String imageUrl) { + StackPane avatar = new StackPane(); + avatar.getStyleClass().add(styleClass); + sizeSquare(avatar, size); + updateImageAvatar(avatar, name, size, size / 2.0, imageUrl); + return avatar; + } + + private StackPane hytaleProfileAvatar(String username, double size, String styleClass) { + StackPane avatar = new StackPane(); + avatar.getStyleClass().add(styleClass); + sizeSquare(avatar, size); + updateHytaleProfileAvatar(avatar, username, size); + return avatar; + } + + private void updateHytaleProfileAvatar(StackPane avatar, String username, double size) { + updateImageAvatar(avatar, username, size, PROFILE_AVATAR_RADIUS, hyvatarUrl(username)); + } + + private void updateImageAvatar(StackPane avatar, String name, double size, double radius, String imageUrl) { + avatar.getChildren().clear(); + Label initial = new Label(initialFor(name)); + initial.getStyleClass().add("play-avatar-initial"); + avatar.getChildren().add(initial); + if (imageUrl == null || imageUrl.isBlank()) { + return; + } + Image image = cachedImage(imageUrl, size, size, true, true); + ImageView imageView = new ImageView(image); + imageView.setFitWidth(size); + imageView.setFitHeight(size); + imageView.setSmooth(true); + Rectangle clip = new Rectangle(size, size); + double arc = Math.min(size, radius * 2.0); + clip.setArcWidth(arc); + clip.setArcHeight(arc); + imageView.setClip(clip); + avatar.getChildren().add(imageView); + } + + private void sizeSquare(Region node, double size) { + node.setMinSize(size, size); + node.setPrefSize(size, size); + node.setMaxSize(size, size); + } + + private void sizeRegion(Region node, double width, double height) { + node.setMinSize(width, height); + node.setPrefSize(width, height); + node.setMaxSize(width, height); + } + + private Image cachedImage(String imageUrl, double requestedWidth, double requestedHeight, boolean preserveRatio, boolean resize) { + if (imageUrl == null || imageUrl.isBlank()) { + return null; + } + String key = imageUrl + "|" + requestedWidth + "x" + requestedHeight + "|" + preserveRatio + "|" + resize; + return imageCache.computeIfAbsent(key, ignored -> { + Image image = resize + ? new Image(imageUrl, requestedWidth, requestedHeight, preserveRatio, true, true) + : new Image(imageUrl, true); + image.errorProperty().addListener((observable, previous, failed) -> { + if (Boolean.TRUE.equals(failed)) { + imageCache.remove(key, image); + } + }); + return image; + }); + } + + private String hyvatarUrl(String username) { + String encoded = URLEncoder.encode(value(username, "Hytale"), StandardCharsets.UTF_8).replace("+", "%20"); + return "https://hyvatar.io/render/" + encoded + "?size=" + HYVATAR_RENDER_SIZE; + } + + private String initialFor(String value) { + String text = value(value, "H"); + return text.substring(0, 1).toUpperCase(); + } + + private String formatBlogDate(Instant publishedAt) { + if (publishedAt == null || publishedAt.equals(Instant.EPOCH)) { + return "Hytale Blog"; + } + int postYear = publishedAt.atZone(ZoneId.systemDefault()).getYear(); + if (postYear == Year.now().getValue()) { + return BLOG_DATE.format(publishedAt); + } + return BLOG_DATE_WITH_YEAR.format(publishedAt); + } + + private void toggleIdentityMenu(Node owner) { + if (identityMenu != null && identityMenu.isShowing()) { + identityMenu.hide(); + return; + } + if (System.currentTimeMillis() - identityMenuHiddenAtMillis < 180) { + return; + } + showIdentityMenu(owner); + } + + private void showIdentityMenu(Node owner) { + if (identityMenu != null) { + identityMenu.hide(); + } + ContextMenu menu = new ContextMenu(); + identityMenu = menu; + menu.getStyleClass().add("play-identity-menu"); + menu.setOnHidden(event -> { + identityMenuHiddenAtMillis = System.currentTimeMillis(); + if (identityMenu == menu) { + identityMenu = null; + } + }); + + LauncherSettings settings = settingsController.settings(); + HytaleAuthSession activeSession = settings.getHytaleAuthSession(); + String activeAccountId = activeSession == null ? "" : LauncherSettings.hytaleAccountId(activeSession); + String activeProfileId = activeSession == null ? "" : value(activeSession.getUuid(), ""); + List sessions = settings.getHytaleAuthSessions(); + for (HytaleAuthSession session : sessions) { + CustomMenuItem header = new CustomMenuItem(identityMenuHeader(session, menu), false); + header.setHideOnClick(false); + menu.getItems().add(header); + + List profiles = profilesFor(session); + if (profiles.isEmpty()) { + CustomMenuItem empty = new CustomMenuItem(identityMenuMessage("No game profiles found"), false); + empty.setHideOnClick(false); + menu.getItems().add(empty); + continue; + } + String accountId = LauncherSettings.hytaleAccountId(session); + for (HytaleProfile profile : profiles) { + boolean selected = accountId.equals(activeAccountId) && profile.uuid().equals(activeProfileId); + CustomMenuItem item = new CustomMenuItem(identityMenuProfileRow(profile, selected), true); + item.setOnAction(event -> selectIdentity(session, profile)); + menu.getItems().add(item); + } + } + + CustomMenuItem addAccount = new CustomMenuItem(identityMenuActionRow( + LauncherIcons.Glyph.USER, + "Add Hytale account", + "Open browser sign-in", + false + ), true); + addAccount.setOnAction(event -> signInHytale()); + menu.getItems().add(addAccount); + + menu.show(owner, Side.BOTTOM, 0, 8); + } + + private Node identityMenuHeader(HytaleAuthSession session, ContextMenu menu) { + HBox row = new HBox(9); + row.getStyleClass().add("play-identity-menu-header"); + row.setAlignment(Pos.CENTER_LEFT); + HytaleProfile selectedProfile = selectedProfileFor(session); + StackPane icon = hytaleProfileAvatar(selectedProfile.displayName(), IDENTITY_MENU_AVATAR_SIZE, "play-identity-menu-avatar"); + + VBox copy = new VBox(2); + Label name = new Label(accountLabel(session)); + name.getStyleClass().add("play-identity-menu-title"); + int profileCount = profilesFor(session).size(); + Label detail = new Label(profileCount + " game profile" + plural(profileCount)); + detail.getStyleClass().add("play-identity-menu-subtitle"); + copy.getChildren().addAll(name, detail); + HBox.setHgrow(copy, Priority.ALWAYS); + + Button logout = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.TRASH, 13)); + logout.getStyleClass().addAll("icon-btn", "play-identity-menu-logout"); + logout.setTooltip(new Tooltip("Log out Hytale account")); + logout.setAccessibleText("Log out " + accountLabel(session)); + logout.setOnAction(event -> { + event.consume(); + menu.hide(); + logoutHytaleAccount(session); + }); + + row.getChildren().addAll(icon, copy, logout); + return row; + } + + private Node identityMenuProfileRow(HytaleProfile profile, boolean selected) { + HBox row = new HBox(9); + row.getStyleClass().add("play-identity-menu-profile"); + if (selected) { + row.getStyleClass().add("selected"); + } + row.setAlignment(Pos.CENTER_LEFT); + StackPane profileAvatar = hytaleProfileAvatar(profile.displayName(), IDENTITY_MENU_AVATAR_SIZE, "play-identity-menu-avatar"); + if (selected) { + StackPane badge = new StackPane(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 8)); + badge.getStyleClass().add("play-identity-menu-avatar-badge"); + StackPane.setAlignment(badge, Pos.BOTTOM_RIGHT); + StackPane.setMargin(badge, new Insets(0, -2, -2, 0)); + profileAvatar.getChildren().add(badge); + } + + VBox copy = new VBox(2); + Label name = new Label(value(profile.displayName(), "Game profile")); + name.getStyleClass().add("play-identity-menu-title"); + Label detail = new Label(selected ? "Selected game profile" : "Use this game profile"); + detail.getStyleClass().add("play-identity-menu-subtitle"); + copy.getChildren().addAll(name, detail); + HBox.setHgrow(copy, Priority.ALWAYS); + row.getChildren().addAll(profileAvatar, copy); + return row; + } + + private Node identityMenuActionRow(LauncherIcons.Glyph glyph, String title, String subtitle, boolean danger) { + HBox row = new HBox(9); + row.getStyleClass().add("play-identity-menu-action"); + if (danger) { + row.getStyleClass().add("danger"); + } + row.setAlignment(Pos.CENTER_LEFT); + StackPane icon = new StackPane(LauncherIcons.icon(glyph, 15)); + icon.getStyleClass().add("play-identity-menu-icon"); + VBox copy = new VBox(2); + Label titleLabel = new Label(title); + titleLabel.getStyleClass().add("play-identity-menu-title"); + Label subtitleLabel = new Label(subtitle); + subtitleLabel.getStyleClass().add("play-identity-menu-subtitle"); + copy.getChildren().addAll(titleLabel, subtitleLabel); + HBox.setHgrow(copy, Priority.ALWAYS); + row.getChildren().addAll(icon, copy); + return row; + } + + private Node identityMenuMessage(String message) { + Label label = new Label(message); + label.getStyleClass().add("play-identity-menu-message"); + return label; + } + + private void selectIdentity(HytaleAuthSession session, HytaleProfile profile) { + if (session == null || profile == null) { + return; + } + String accountId = LauncherSettings.hytaleAccountId(session); + boolean accountChanged = !accountId.equals(settingsController.settings().getActiveHytaleAccountId()); + if (accountChanged) { + hytaleAuthService.selectAccount(settingsController.settings(), accountId); + settingsController.reloadFromStore(); + } + HytaleAuthSession active = settingsController.settings().getHytaleAuthSession(); + if (active == null || !profile.uuid().equals(active.getUuid())) { + hytaleAuthService.selectProfile(settingsController.settings(), profile); + settingsController.reloadFromStore(); + } + feedback.log("Selected Hytale profile " + profile.displayName() + "."); + syncMetrics(); + } + + private List profilesFor(HytaleAuthSession session) { + if (session == null) { + return List.of(); + } + List profiles = session.getProfiles(); + if (!profiles.isEmpty()) { + return profiles; + } + if (session.getUuid() == null || session.getUuid().isBlank()) { + return List.of(); + } + return List.of(new HytaleProfile(session.getUsername(), session.getUuid(), session.getAccountOwnerId())); + } + + private HytaleProfile selectedProfileFor(HytaleAuthSession session) { + if (session == null) { + return new HytaleProfile("", "", ""); + } + List profiles = profilesFor(session); + if (profiles.isEmpty()) { + return new HytaleProfile(session.getUsername(), session.getUuid(), session.getAccountOwnerId()); + } + String selectedUuid = value(session.getUuid(), ""); + return profiles.stream() + .filter(profile -> profile.uuid().equals(selectedUuid)) + .findFirst() + .orElseGet(() -> profiles.get(0)); + } + + private String accountLabel(HytaleAuthSession session) { + return value(session == null ? "" : session.getUsername(), "Hytale account"); + } + + private String selectedVersionLabel(LauncherSettings settings) { + LauncherSettingsForm form = settingsController.form(); + HytaleVersion selected = form.hytaleVersionCombo().getValue(); + if (selected != null) { + return versionSwitchLabel(selected); + } + if (settings.getHytaleBuild() > 0) { + for (HytaleVersion version : form.hytaleVersionCombo().getItems()) { + if (version.build() == settings.getHytaleBuild()) { + return versionSwitchLabel(version); + } + } + Map labels = HytaleGameVersionResolver.resolveBuildVersions(settings); + String label = labels.get(settings.getHytaleBuild()); + return label == null || label.isBlank() ? "Build " + settings.getHytaleBuild() : label; + } + return "Unset"; + } + + private String versionSwitchLabel(HytaleVersion version) { + return version == null ? "" : version.displayVersion(); + } + + private void syncPatchlineMetric(String selectedPatchline) { + String patchline = HytaleApiClient.normalizeBranch(selectedPatchline); + boolean showPatchline = !"release".equals(patchline); + patchlineMetric.setText(launchPatchlineLabel(patchline)); + Node container = patchlineMetric.getParent(); + setVisibleManaged(container == null ? patchlineMetric : container, showPatchline); + } + + private String launchPatchlineLabel(String patchline) { + String normalized = HytaleApiClient.normalizeBranch(patchline); + return switch (normalized) { + case "release" -> "Latest release"; + case "pre-release" -> "Pre-release"; + default -> normalized; + }; + } + + private void signInHytale() { + settingsController.saveFromFields(false); + feedback.runAsync("Opening Hytale sign-in in your browser...", () -> + hytaleAuthService.loginAndSave(settingsController.settings()), session -> { + settingsController.reloadFromStore(); + loadedPlaytimeKey = ""; + feedback.log("Signed in with Hytale as " + session + "."); + feedback.showToast("Hytale ready", "Signed in as " + session + "."); + syncMetrics(); + onHytaleAccountsChanged.run(); + }); + } + + private void logoutHytaleAccount(HytaleAuthSession session) { + if (isHytaleRunning()) { + feedback.showToast("Hytale is running", "Stop Hytale before logging out of this account."); + return; + } + if (session == null) { + return; + } + LauncherSettings settings = settingsController.settings(); + String accountId = LauncherSettings.hytaleAccountId(session); + boolean activeAccount = accountId.equals(settings.getActiveHytaleAccountId()); + hytaleAuthService.logoutAccount(settings, accountId); + if (activeAccount) { + settingsController.form().hytaleVersionCombo().getItems().clear(); + loadedVersionsKey = ""; + loadedFriendsKey = ""; + loadedPlaytimeKey = ""; + } + settingsController.reloadFromStore(); + feedback.log("Logged out of Hytale account " + accountLabel(session) + "."); + syncMetrics(); + onHytaleAccountsChanged.run(); + } + + private void stopHytale() { + Process process = hytaleProcess; + if (process == null || !process.isAlive()) { + hytaleProcess = null; + feedback.showToast("Not running", "Hytale is not running."); + return; + } + process.destroy(); + feedback.log("Asked Hytale to stop."); + } + + private void monitorHytaleProcess(HytaleLaunchResult result, long startedAtMillis) { + Process process = result.process(); + CompletableFuture.runAsync(() -> { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + feedback.log("[Hytale] " + line); + } + } catch (IOException ex) { + feedback.log("Could not read Hytale output: " + ex.getMessage()); + } + try { + int exitCode = process.waitFor(); + if (hytaleProcess == process) { + hytaleProcess = null; + } + long elapsedSeconds = Math.max(0, (System.currentTimeMillis() - startedAtMillis) / 1000); + if (elapsedSeconds > 0) { + LauncherSettings settings = settingsController.settings(); + settings.addHytalePlaytimeSeconds(elapsedSeconds); + settingsController.saveCurrentSettings(); + } + feedback.log("Hytale exited with code " + exitCode + "."); + discordRichPresence.showLauncher(); + javafx.application.Platform.runLater(() -> { + loadedPlaytimeKey = ""; + syncMetrics(); + }); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + }, executor); + } + + private boolean isHytaleRunning() { + Process process = hytaleProcess; + return process != null && process.isAlive(); + } + + private void showLaunchDropdown(Node owner) { + LauncherSettingsForm form = settingsController.form(); + ContextMenu menu = new ContextMenu(); + menu.getStyleClass().add("play-launch-menu"); + + List patchlines = form.hytaleBranchCombo().getItems().isEmpty() + ? List.of("release", "pre-release") + : List.copyOf(form.hytaleBranchCombo().getItems()); + menu.getItems().add(patchlineMenu(patchlines, HytaleApiClient.normalizeBranch(form.hytaleBranchCombo().getValue()))); + menu.getItems().add(buildMenu(form)); + menu.show(owner, Side.BOTTOM, 0, 8); + } + + private Menu patchlineMenu(List patchlines, String selectedPatchline) { + String selected = HytaleApiClient.normalizeBranch(selectedPatchline); + Menu menu = new Menu("Patchline: " + LauncherSettingsForm.hytalePatchlineLabel(selected), + LauncherIcons.icon(LauncherIcons.Glyph.SLIDERS, 14)); + for (String patchline : dropdownPatchlines(patchlines)) { + String normalized = HytaleApiClient.normalizeBranch(patchline); + menu.getItems().add(launchMenuItem( + LauncherSettingsForm.hytalePatchlineLabel(normalized), + LauncherIcons.Glyph.SLIDERS, + normalized.equals(selected), + () -> selectLaunchPatchline(normalized) + )); + } + return menu; + } + + private List dropdownPatchlines(List patchlines) { + List normalized = patchlines == null ? List.of() : patchlines.stream() + .map(HytaleApiClient::normalizeBranch) + .distinct() + .toList(); + List ordered = new ArrayList<>(); + if (normalized.contains("pre-release")) { + ordered.add("pre-release"); + } + if (normalized.contains("release")) { + ordered.add("release"); + } + normalized.stream().filter(patchline -> patchline.startsWith("v")).forEach(ordered::add); + normalized.stream() + .filter(patchline -> !ordered.contains(patchline)) + .forEach(ordered::add); + return ordered; + } + + private List orderedPatchlines(List patchlines) { + List normalized = patchlines == null ? List.of() : patchlines.stream() + .map(HytaleApiClient::normalizeBranch) + .distinct() + .toList(); + List ordered = new ArrayList<>(); + normalized.stream().filter(patchline -> patchline.startsWith("v")).forEach(ordered::add); + if (normalized.contains("release")) { + ordered.add("release"); + } + if (normalized.contains("pre-release")) { + ordered.add("pre-release"); + } + normalized.stream() + .filter(patchline -> !ordered.contains(patchline)) + .forEach(ordered::add); + return ordered; + } + + private Menu buildMenu(LauncherSettingsForm form) { + String label = versionsLoading ? "Versions: loading" : "Version: " + selectedVersionLabel(settingsController.settings()); + Menu buildMenu = new Menu(label, LauncherIcons.icon(LauncherIcons.Glyph.ZAP, 14)); + List versions = List.copyOf(form.hytaleVersionCombo().getItems()); + if (versionsLoading || versions.isEmpty()) { + MenuItem message = new MenuItem(versionsLoading ? "Loading versions..." : "Waiting for version refresh"); + message.setDisable(true); + buildMenu.getItems().add(message); + return buildMenu; + } + + HytaleVersion selectedVersion = form.hytaleVersionCombo().getValue(); + for (HytaleVersion version : versions) { + boolean selected = selectedVersion != null && selectedVersion.build() == version.build(); + buildMenu.getItems().add(launchMenuItem(versionSwitchLabel(version), LauncherIcons.Glyph.ZAP, + selected, () -> selectLaunchBuild(version))); + } + return buildMenu; + } + + private MenuItem launchMenuItem(String label, LauncherIcons.Glyph glyph, boolean selected, Runnable action) { + MenuItem item = new MenuItem(label, LauncherIcons.icon(selected ? LauncherIcons.Glyph.CHECK : glyph, 14)); + item.setOnAction(event -> action.run()); + return item; + } + + private void selectLaunchPatchline(String patchline) { + LauncherSettingsForm form = settingsController.form(); + String normalized = HytaleApiClient.normalizeBranch(patchline); + if (normalized.equals(HytaleApiClient.normalizeBranch(form.hytaleBranchCombo().getValue()))) { + return; + } + form.hytaleVersionCombo().setValue(null); + form.hytaleVersionCombo().getItems().clear(); + suppressBranchVersionLoad = true; + try { + form.hytaleBranchCombo().setValue(normalized); + } finally { + suppressBranchVersionLoad = false; + } + settingsController.applyFromFields(); + settingsController.settings().setHytaleBuild(0); + settingsController.saveCurrentSettings(); + loadedVersionsKey = ""; + buildMetric.setText("Loading"); + loadHytaleVersions(false); + syncMetrics(); + } + + private void selectLaunchBuild(HytaleVersion version) { + if (version == null) { + return; + } + settingsController.form().hytaleVersionCombo().setValue(version); + settingsController.saveFromFields(false); + syncMetrics(); + } + + private void maybeLoadHytaleVersions() { + loadHytaleVersions(false); + } + + private void maybeLoadHytalePlaytime() { + loadHytalePlaytime(false); + } + + private String versionsKey(LauncherSettings settings, HytaleAuthSession session) { + return LauncherSettings.hytaleAccountId(session) + ":" + settings.getHytaleBranch(); + } + + private String selectedPatchline(String requestedPatchline, List availablePatchlines) { + String normalized = HytaleApiClient.normalizeBranch(requestedPatchline); + if (availablePatchlines != null && availablePatchlines.contains(normalized)) { + return normalized; + } + return "release"; + } + + private String playtimeKey(HytaleAuthSession session) { + return LauncherSettings.hytaleAccountId(session) + ":" + selectedProfileFor(session).uuid(); + } + + private String plural(int count) { + return count == 1 ? "" : "s"; + } + + private record HytaleVersionsPayload( + List patchlines, + String selectedPatchline, + Map> versionsByPatchline, + List pendingPatchlines, + HytaleApiException rateLimit + ) { + + private List versionsForSelectedPatchline() { + return versionsByPatchline.getOrDefault(selectedPatchline, List.of()); + } + } + + private static final class CatalogShelf { + private final ProjectBrowseSort sort; + private final HBox cardRow = new HBox(); + private final ScrollPane scroll = new ScrollPane(); + private final Label message = new Label(); + + private boolean loading; + private boolean loaded; + private long requestId; + + private CatalogShelf(ProjectBrowseSort sort) { + this.sort = sort; + } + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/FixedAspectPane.java b/launcher/src/main/java/net/modtale/launcher/ui/project/FixedAspectPane.java new file mode 100644 index 00000000..228c54fd --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/FixedAspectPane.java @@ -0,0 +1,56 @@ +package net.modtale.launcher.ui.project; + +import javafx.scene.layout.StackPane; + +final class FixedAspectPane extends StackPane { + + private static final double FALLBACK_WIDTH = 640; + + private final double aspectRatio; + + FixedAspectPane(double aspectRatio) { + if (!Double.isFinite(aspectRatio) || aspectRatio <= 0) { + throw new IllegalArgumentException("aspectRatio must be positive"); + } + this.aspectRatio = aspectRatio; + setMinWidth(0); + } + + @Override + protected double computeMinHeight(double width) { + return computePrefHeight(width); + } + + @Override + protected double computePrefHeight(double width) { + return effectiveWidth(width) / aspectRatio; + } + + @Override + protected double computeMaxHeight(double width) { + return computePrefHeight(width); + } + + @Override + protected double computePrefWidth(double height) { + if (Double.isFinite(height) && height > 0) { + return height * aspectRatio; + } + double prefWidth = getPrefWidth(); + if (Double.isFinite(prefWidth) && prefWidth > 0) { + return prefWidth; + } + return FALLBACK_WIDTH; + } + + private double effectiveWidth(double width) { + if (Double.isFinite(width) && width > 0) { + return width; + } + double prefWidth = getPrefWidth(); + if (Double.isFinite(prefWidth) && prefWidth > 0) { + return prefWidth; + } + return FALLBACK_WIDTH; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/LauncherProjectActions.java b/launcher/src/main/java/net/modtale/launcher/ui/project/LauncherProjectActions.java new file mode 100644 index 00000000..dcc4df07 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/LauncherProjectActions.java @@ -0,0 +1,234 @@ +package net.modtale.launcher.ui.project; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.scene.layout.StackPane; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.model.project.GameVersionCatalog; +import net.modtale.launcher.model.project.ProjectDependency; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.ui.account.LauncherAccountController; +import net.modtale.launcher.ui.browse.ProjectBrowseController; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.feedback.LauncherFeedback; +import net.modtale.launcher.ui.library.LauncherLibraryController; + +public final class LauncherProjectActions { + + private final ModtaleApiClient apiClient; + private final LauncherAccountController accountController; + private final LauncherLibraryController libraryController; + private final LauncherFeedback feedback; + private final Supplier gameVersion; + private final Executor executor; + private final CachedImageLoader imageLoader; + + private ProjectBrowseController browseController; + private NativeDownloadModal downloadModal; + private NativeDependencyModal dependencyModal; + private Consumer viewHistory = detail -> { + }; + + public LauncherProjectActions( + ModtaleApiClient apiClient, + LauncherAccountController accountController, + LauncherLibraryController libraryController, + LauncherFeedback feedback, + Supplier gameVersion, + Executor executor, + CachedImageLoader imageLoader + ) { + this.apiClient = apiClient; + this.accountController = accountController; + this.libraryController = libraryController; + this.feedback = feedback; + this.gameVersion = gameVersion == null ? () -> "" : gameVersion; + this.executor = executor; + this.imageLoader = imageLoader; + } + + public void attachBrowse(ProjectBrowseController browseController) { + this.browseController = browseController; + } + + public void attachOverlay(Supplier overlayHost) { + downloadModal = new NativeDownloadModal( + overlayHost, + gameVersion, + this::installSelectedProjectVersion, + detail -> viewHistory.accept(detail) + ); + dependencyModal = new NativeDependencyModal( + overlayHost, + apiClient, + executor, + imageLoader, + this::installSelectedProjectVersion + ); + } + + public void setViewHistoryAction(Consumer viewHistory) { + this.viewHistory = viewHistory == null ? detail -> { + } : viewHistory; + } + + public void installSelectedProject(ProjectSummary summary) { + if (summary == null) { + return; + } + if (downloadModal == null) { + libraryController.installSelectedProject(summary); + return; + } + ProjectDetail initialProject = detailFromSummary(summary); + GameVersionCatalog initialCatalog = catalogFromProject(initialProject); + if (initialProject.versions().isEmpty()) { + downloadModal.showLoading(initialProject, initialCatalog); + } else { + downloadModal.show(initialProject, initialCatalog); + } + refreshDownloadOptions(summary, initialProject); + } + + private void refreshDownloadOptions(ProjectSummary summary, ProjectDetail initialProject) { + feedback.log("Refreshing download options for " + summary + "..."); + CompletableFuture.supplyAsync(() -> { + ProjectDetail project = loadProjectWithVersions(summary); + return new DownloadOptions(project, loadGameVersions(project)); + }, executor).whenComplete((options, error) -> Platform.runLater(() -> { + if (error != null) { + Throwable cause = error.getCause() == null ? error : error.getCause(); + feedback.log("Could not refresh download options for " + summary + ": " + cause.getMessage()); + if (initialProject.versions().isEmpty() && downloadModal.isShowing(initialProject)) { + feedback.showToast("Download options unavailable", cause.getMessage()); + } + return; + } + downloadModal.refresh(options.project(), options.catalog()); + })); + } + + private void installSelectedProjectVersion(NativeDownloadModal.DownloadSelection selection) { + if (selection.selectedDependencies() != null) { + installExactDependencySelection( + selection.project(), + selection.version(), + selection.gameVersion(), + selection.selectedDependencies() + ); + return; + } + installSelectedProjectVersion(selection.project(), selection.version(), selection.gameVersion()); + } + + private void installSelectedProjectVersion(NativeDependencyModal.DependencySelection selection) { + installExactDependencySelection( + selection.project(), + selection.version(), + selection.gameVersion(), + selection.selectedDependencies() + ); + } + + public void installSelectedProjectVersion(ProjectDetail project, ProjectVersion version, String gameVersion) { + List dependencies = NativeDependencyModal.selectableDependencies(version); + if (dependencyModal != null && !dependencies.isEmpty()) { + dependencyModal.show(project, version, gameVersion); + return; + } + installExactDependencySelection(project, version, gameVersion, dependencies); + } + + private void installExactDependencySelection( + ProjectDetail project, + ProjectVersion version, + String gameVersion, + List selectedDependencies + ) { + libraryController.installSelectedProjectVersion(project, version, gameVersion, selectedDependencies); + } + + public void toggleFavorite(ProjectSummary project) { + feedback.runAsync((accountController.isSignedIn() ? "Updating like for " : "Signing in to like ") + project + "...", () -> { + CurrentUser user = accountController.ensureSignedIn(); + boolean wasFavorite = user.likesProject(project.id()); + apiClient.toggleFavorite(project.id()); + CurrentUser updatedUser = apiClient.currentUser(); + boolean isFavorite = updatedUser.likesProject(project.id()); + return new FavoriteToggleResult(project.id(), wasFavorite, isFavorite, updatedUser); + }, result -> { + accountController.setCurrentUser(result.user()); + int delta = (result.isFavorite() ? 1 : 0) - (result.wasFavorite() ? 1 : 0); + if (browseController != null) { + browseController.applyFavoriteDelta(result.projectId(), delta); + browseController.renderProjects(); + } + feedback.showToast(result.isFavorite() ? "Liked project" : "Removed like", "Updated your Modtale favorites."); + }); + } + + private record FavoriteToggleResult(String projectId, boolean wasFavorite, boolean isFavorite, CurrentUser user) { + } + + private GameVersionCatalog loadGameVersions(ProjectDetail project) { + try { + return apiClient.getGameVersionCatalog(); + } catch (RuntimeException ignored) { + return catalogFromProject(project); + } + } + + private ProjectDetail loadProjectWithVersions(ProjectSummary summary) { + ProjectDetail project = apiClient.getProject(summary.routeKey()); + return ProjectVersionHydrator.hydrateOrThrow(project, summary, apiClient::getProjectVersions); + } + + private static ProjectDetail detailFromSummary(ProjectSummary summary) { + return new ProjectDetail( + summary.id(), + summary.slug(), + summary.title(), + null, + summary.description(), + summary.authorId(), + summary.author(), + summary.imageUrl(), + summary.bannerUrl(), + summary.classification(), + summary.downloadCount(), + summary.favoriteCount(), + summary.updatedAt(), + null, + null, + Map.of(), + List.of(), + List.of(), + Map.of(), + null, + false, + null, + summary.versions() + ); + } + + private static GameVersionCatalog catalogFromProject(ProjectDetail project) { + List versions = project == null + ? List.of() + : project.versions().stream() + .flatMap(version -> version.gameVersions().stream()) + .distinct() + .toList(); + return GameVersionCatalog.fromVersions(versions); + } + + private record DownloadOptions(ProjectDetail project, GameVersionCatalog catalog) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/NativeBannerScrollEffect.java b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeBannerScrollEffect.java new file mode 100644 index 00000000..bd8c26f3 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeBannerScrollEffect.java @@ -0,0 +1,60 @@ +package net.modtale.launcher.ui.project; + +import javafx.beans.InvalidationListener; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import net.modtale.launcher.LauncherPerformanceProbe; + +final class NativeBannerScrollEffect { + + private static final double SCROLL_CAP = 1500; + private static final double PARALLAX_MAX_OFFSET = 500; + private static final double PARALLAX_DECAY = 600; + + private NativeBannerScrollEffect() { + } + + static void bind(Node media, Region fade, ReadOnlyDoubleProperty scrollPixels, double baseFadeHeight) { + fade.setMaxWidth(Double.MAX_VALUE); + fade.setMinHeight(baseFadeHeight); + fade.setPrefHeight(baseFadeHeight); + fade.setMaxHeight(baseFadeHeight); + StackPane.setAlignment(fade, Pos.BOTTOM_CENTER); + + InvalidationListener listener = ignored -> apply(media, fade, scrollPixels.get(), baseFadeHeight); + scrollPixels.addListener(listener); + media.sceneProperty().addListener((observable, previous, current) -> { + if (previous != null && current == null) { + scrollPixels.removeListener(listener); + } + }); + apply(media, fade, scrollPixels.get(), baseFadeHeight); + } + + private static void apply(Node media, Region fade, double scrollPixels, double baseFadeHeight) { + long operationStart = LauncherPerformanceProbe.operationStartNanos(); + try { + double offset = parallaxOffset(scrollPixels); + media.setTranslateY(offset); + fade.setTranslateY(offset / 2.0); + fade.setScaleY(fadeScale(offset, baseFadeHeight)); + } finally { + LauncherPerformanceProbe.recordOperation("banner.scrollEffect", operationStart); + } + } + + static double parallaxOffset(double scrollPixels) { + double scroll = Math.min(Math.max(0, scrollPixels), SCROLL_CAP); + return PARALLAX_MAX_OFFSET * (1 - Math.exp(-scroll / PARALLAX_DECAY)); + } + + static double fadeScale(double offset, double baseFadeHeight) { + if (!Double.isFinite(baseFadeHeight) || baseFadeHeight <= 0) { + return 1; + } + return (baseFadeHeight + Math.max(0, offset)) / baseFadeHeight; + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/NativeCommentSection.java b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeCommentSection.java new file mode 100644 index 00000000..7c3f4aa1 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeCommentSection.java @@ -0,0 +1,581 @@ +package net.modtale.launcher.ui.project; + +import static net.modtale.launcher.ui.browse.card.ProjectCardFormatter.timeAgo; +import static net.modtale.launcher.ui.common.LauncherUi.primaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.secondaryButton; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Supplier; +import javafx.css.PseudoClass; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.model.project.ProjectComment; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.model.user.UserSummary; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class NativeCommentSection { + + private static final String OWNER_ROLE_COLOR = "#f97316"; + private static final PseudoClass UPVOTED = PseudoClass.getPseudoClass("upvoted"); + private static final PseudoClass DOWNVOTED = PseudoClass.getPseudoClass("downvoted"); + + interface Actions { + void submitComment(String editingCommentId, String content); + + void deleteComment(ProjectComment comment); + + void submitReply(String commentId, String content); + + void vote(String commentId, boolean reply, boolean upvote); + + void report(String commentId); + } + + private final CachedImageLoader imageLoader; + private final NativeMarkdownRenderer markdownRenderer; + private final Supplier currentUser; + private final Runnable signIn; + private final BiConsumer openProfile; + private final Actions actions; + private final Runnable requestRender; + + private String composerText = ""; + private String editingCommentId; + private String replyingCommentId; + private String replyText = ""; + + NativeCommentSection( + CachedImageLoader imageLoader, + NativeMarkdownRenderer markdownRenderer, + Supplier currentUser, + Runnable signIn, + BiConsumer openProfile, + Actions actions, + Runnable requestRender + ) { + this.imageLoader = imageLoader; + this.markdownRenderer = markdownRenderer; + this.currentUser = currentUser == null ? () -> null : currentUser; + this.signIn = signIn == null ? () -> { + } : signIn; + this.openProfile = openProfile == null ? (id, username) -> { + } : openProfile; + this.actions = actions; + this.requestRender = requestRender == null ? () -> { + } : requestRender; + } + + Node render( + ProjectSummary summary, + ProjectDetail detail, + List comments, + Map userProfiles, + boolean loading, + boolean submitting + ) { + CurrentUser user = currentUser.get(); + boolean creator = isCreator(user, summary, detail); + boolean disabled = detail != null && Boolean.FALSE.equals(detail.allowComments()); + if (disabled && !creator) { + return null; + } + + List safeComments = comments == null ? List.of() : comments; + Map safeProfiles = userProfiles == null ? Map.of() : userProfiles; + + VBox section = new VBox(0); + section.setId("comments"); + section.getStyleClass().add("project-comments-section"); + section.setMaxWidth(Double.MAX_VALUE); + + HBox heading = new HBox(12); + heading.getStyleClass().add("project-comments-heading"); + heading.setAlignment(Pos.CENTER_LEFT); + Label title = new Label(safeComments.size() + " Comments"); + title.getStyleClass().add("project-comments-title"); + heading.getChildren().addAll(LauncherIcons.icon(LauncherIcons.Glyph.MESSAGE_SQUARE, 24), title); + section.getChildren().add(heading); + + if (disabled) { + section.getChildren().add(disabledNotice()); + } + + section.getChildren().add(user == null ? signInPrompt() : composer(user, submitting)); + + VBox list = new VBox(16); + list.getStyleClass().add("project-comments-list"); + if (loading) { + list.getChildren().add(stateCard(NativeSpinner.inline(20))); + } else if (safeComments.isEmpty()) { + list.getChildren().add(stateCard("No comments yet. Be the first to share your thoughts!")); + } else { + for (ProjectComment comment : safeComments) { + list.getChildren().add(commentCard(comment, summary, detail, safeProfiles, creator, submitting)); + } + } + section.getChildren().add(list); + return section; + } + + void clearComposer() { + composerText = ""; + editingCommentId = null; + } + + void clearReply() { + replyText = ""; + replyingCommentId = null; + } + + void clearState() { + clearComposer(); + clearReply(); + } + + private Node disabledNotice() { + HBox notice = new HBox(8); + notice.getStyleClass().add("project-comments-disabled-notice"); + notice.setAlignment(Pos.CENTER_LEFT); + Label label = new Label("Comments are currently disabled. Only you can see them."); + label.getStyleClass().add("project-comments-disabled-text"); + notice.getChildren().addAll(LauncherIcons.icon(LauncherIcons.Glyph.FLAG, 16), label); + return notice; + } + + private Node signInPrompt() { + Button signInButton = new Button("Log in to join the conversation."); + signInButton.getStyleClass().add("project-comments-signin"); + signInButton.setMaxWidth(Double.MAX_VALUE); + signInButton.setOnAction(event -> signIn.run()); + return signInButton; + } + + private Node composer(CurrentUser user, boolean submitting) { + VBox shell = new VBox(14); + shell.getStyleClass().add("project-comments-composer"); + shell.setMaxWidth(Double.MAX_VALUE); + + HBox top = new HBox(12); + top.setAlignment(Pos.CENTER_LEFT); + Label title = new Label(editingCommentId == null ? "Leave a comment" : "Edit your comment"); + title.getStyleClass().add("project-comments-composer-title"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + top.getChildren().addAll(title, spacer); + if (editingCommentId != null) { + Button cancel = new Button("Cancel"); + cancel.getStyleClass().add("project-comments-text-action-danger"); + cancel.setOnAction(event -> { + clearComposer(); + requestRender.run(); + }); + top.getChildren().add(cancel); + } + + HBox editRow = new HBox(12); + editRow.setAlignment(Pos.TOP_LEFT); + TextArea text = new TextArea(composerText); + text.getStyleClass().add("project-comments-textarea"); + text.setPromptText("What are your thoughts?"); + text.setWrapText(true); + text.setPrefRowCount(3); + text.setMinHeight(72); + text.setDisable(submitting); + text.textProperty().addListener((observable, previous, value) -> composerText = value == null ? "" : value); + HBox.setHgrow(text, Priority.ALWAYS); + editRow.getChildren().addAll(avatar(36, user.id(), user.username(), user.avatarUrl(), false), text); + + HBox footer = new HBox(); + footer.setAlignment(Pos.CENTER_RIGHT); + Button submit = primaryButton(editingCommentId == null ? "Post Comment" : "Update"); + submit.getStyleClass().add("project-comments-submit"); + submit.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.SEND, 14)); + submit.setDisable(submitting || composerText.isBlank()); + submit.setOnAction(event -> actions.submitComment(editingCommentId, composerText)); + footer.getChildren().add(submit); + + shell.getChildren().addAll(top, editRow, footer); + return shell; + } + + private Node commentCard( + ProjectComment comment, + ProjectSummary summary, + ProjectDetail detail, + Map profiles, + boolean creator, + boolean submitting + ) { + CurrentUser user = currentUser.get(); + String userId = value(comment.userId(), ""); + CommentIdentity identity = identity(userId, comment.user(), comment.author(), profiles, comment.date()); + boolean owner = user != null && (value(user.id(), "").equals(userId) + || value(user.username(), "").equalsIgnoreCase(identity.username())); + + HBox card = new HBox(16); + card.getStyleClass().add("project-comment-card"); + card.setAlignment(Pos.TOP_LEFT); + card.getChildren().add(voteWidget(comment.id(), false, comment.score(), comment.userVoteFor(user == null ? null : user.id()), submitting)); + + VBox body = new VBox(0); + body.setMinWidth(0); + HBox.setHgrow(body, Priority.ALWAYS); + body.getChildren().add(commentHeader(identity, roleBadge(userId, summary, detail), 40)); + Node markdown = markdown(comment.content()); + VBox.setMargin(markdown, new Insets(8, 0, 0, 0)); + body.getChildren().add(markdown); + body.getChildren().add(actionsRow(comment, creator, owner)); + + if (replyingCommentId != null && replyingCommentId.equals(comment.id())) { + body.getChildren().add(replyForm(comment.id(), submitting)); + } else if (comment.developerReply() != null) { + body.getChildren().add(developerReply(comment, profiles, summary, detail, submitting)); + } + + card.getChildren().add(body); + return card; + } + + private Node commentHeader(CommentIdentity identity, RoleBadge roleBadge, double avatarSize) { + HBox header = new HBox(12); + header.getStyleClass().add("project-comment-header"); + header.setAlignment(Pos.CENTER_LEFT); + Node avatar = avatar(avatarSize, identity.userId(), identity.username(), identity.avatarUrl(), true); + VBox meta = new VBox(2); + meta.getStyleClass().add("project-comment-meta"); + Label name = new Label(identity.username()); + name.getStyleClass().add("project-comment-author"); + if (!identity.userId().isBlank()) { + name.setCursor(Cursor.HAND); + name.setOnMouseClicked(event -> openProfile.accept(identity.userId(), identity.username())); + } + meta.getChildren().add(name); + if (roleBadge != null) { + meta.getChildren().add(roleBadge(roleBadge)); + } + Label date = new Label(timeAgo(identity.date())); + date.getStyleClass().add("project-comment-date"); + meta.getChildren().add(date); + header.getChildren().addAll(avatar, meta); + return header; + } + + private Node actionsRow(ProjectComment comment, boolean creator, boolean owner) { + HBox row = new HBox(16); + row.getStyleClass().add("project-comment-actions"); + row.setAlignment(Pos.CENTER_LEFT); + VBox.setMargin(row, new Insets(12, 0, 0, 0)); + if (creator && comment.developerReply() == null) { + row.getChildren().add(actionButton("Reply", LauncherIcons.Glyph.MESSAGE_SQUARE, () -> { + replyingCommentId = comment.id(); + replyText = ""; + requestRender.run(); + })); + } + if (creator && comment.developerReply() != null) { + row.getChildren().add(actionButton("Edit Reply", LauncherIcons.Glyph.MESSAGE_SQUARE, () -> { + replyingCommentId = comment.id(); + replyText = value(comment.developerReply().content(), ""); + requestRender.run(); + })); + } + CurrentUser user = currentUser.get(); + if (user != null && !owner) { + row.getChildren().add(actionButton("Report", LauncherIcons.Glyph.FLAG, () -> actions.report(comment.id()))); + } + if (owner) { + row.getChildren().add(actionButton("Edit", LauncherIcons.Glyph.EDIT, () -> { + composerText = value(comment.content(), ""); + editingCommentId = comment.id(); + replyingCommentId = null; + requestRender.run(); + })); + } + if (creator || owner) { + Button delete = actionButton("Delete", LauncherIcons.Glyph.TRASH, () -> actions.deleteComment(comment)); + delete.getStyleClass().add("danger"); + row.getChildren().add(delete); + } + return row; + } + + private Button actionButton(String text, LauncherIcons.Glyph glyph, Runnable action) { + Button button = new Button(text, LauncherIcons.icon(glyph, 15)); + button.getStyleClass().add("project-comment-action"); + button.setOnAction(event -> action.run()); + return button; + } + + private Node replyForm(String commentId, boolean submitting) { + VBox form = new VBox(10); + form.getStyleClass().add("project-comment-reply-form"); + VBox.setMargin(form, new Insets(16, 0, 0, 0)); + TextArea text = new TextArea(replyText); + text.getStyleClass().add("project-comment-reply-textarea"); + text.setPromptText("Write a reply..."); + text.setWrapText(true); + text.setPrefRowCount(3); + text.setDisable(submitting); + text.textProperty().addListener((observable, previous, value) -> replyText = value == null ? "" : value); + HBox footer = new HBox(8); + footer.setAlignment(Pos.CENTER_RIGHT); + Button cancel = secondaryButton("Cancel"); + cancel.getStyleClass().add("project-comment-reply-cancel"); + cancel.setOnAction(event -> { + clearReply(); + requestRender.run(); + }); + Button submit = primaryButton("Post Reply"); + submit.getStyleClass().add("project-comment-reply-submit"); + submit.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.CORNER_DOWN_RIGHT, 15)); + submit.setDisable(submitting || replyText.isBlank()); + submit.setOnAction(event -> actions.submitReply(commentId, replyText)); + footer.getChildren().addAll(cancel, submit); + form.getChildren().addAll(text, footer); + return form; + } + + private Node developerReply( + ProjectComment comment, + Map profiles, + ProjectSummary summary, + ProjectDetail detail, + boolean submitting + ) { + ProjectComment.Reply reply = comment.developerReply(); + String replyUserId = value(reply.userId(), ""); + CommentIdentity identity = identity(replyUserId, reply.user(), reply.author(), profiles, reply.date()); + + HBox row = new HBox(12); + row.getStyleClass().add("project-comment-developer-reply-row"); + VBox.setMargin(row, new Insets(12, 0, 0, 0)); + row.getChildren().add(replyConnector()); + row.getChildren().add(voteWidget(comment.id(), true, reply.score(), reply.userVoteFor(currentUserId()), submitting)); + + VBox card = new VBox(0); + card.getStyleClass().add("project-comment-developer-reply"); + card.setMinWidth(0); + HBox.setHgrow(card, Priority.ALWAYS); + card.getChildren().add(commentHeader(identity, roleBadge(replyUserId, summary, detail), 32)); + Node markdown = markdown(reply.content()); + VBox.setMargin(markdown, new Insets(8, 0, 0, 0)); + card.getChildren().add(markdown); + + HBox actionsRow = new HBox(16); + actionsRow.getStyleClass().add("project-comment-actions"); + actionsRow.setAlignment(Pos.CENTER_LEFT); + VBox.setMargin(actionsRow, new Insets(12, 0, 0, 0)); + CurrentUser user = currentUser.get(); + if (user != null && !value(user.id(), "").equals(replyUserId)) { + actionsRow.getChildren().add(actionButton("Report", LauncherIcons.Glyph.FLAG, () -> actions.report(comment.id()))); + } + card.getChildren().add(actionsRow); + row.getChildren().add(card); + return row; + } + + private Node replyConnector() { + StackPane connector = new StackPane(); + connector.getStyleClass().add("project-comment-reply-connector"); + connector.setMinWidth(28); + connector.setPrefWidth(28); + connector.setMaxWidth(28); + Region vertical = new Region(); + vertical.getStyleClass().add("project-comment-reply-line-vertical"); + Region horizontal = new Region(); + horizontal.getStyleClass().add("project-comment-reply-line-horizontal"); + StackPane.setAlignment(vertical, Pos.TOP_CENTER); + StackPane.setAlignment(horizontal, Pos.TOP_RIGHT); + StackPane.setMargin(horizontal, new Insets(17, 0, 0, 0)); + connector.getChildren().addAll(vertical, horizontal); + return connector; + } + + private Node voteWidget(String commentId, boolean reply, int score, String userVote, boolean submitting) { + VBox vote = new VBox(0); + vote.getStyleClass().add("project-comment-vote"); + vote.setAlignment(Pos.TOP_CENTER); + Button up = voteButton(LauncherIcons.Glyph.ARROW_BIG_UP, () -> actions.vote(commentId, reply, true)); + up.pseudoClassStateChanged(UPVOTED, "up".equals(userVote)); + Button down = voteButton(LauncherIcons.Glyph.ARROW_BIG_DOWN, () -> actions.vote(commentId, reply, false)); + down.pseudoClassStateChanged(DOWNVOTED, "down".equals(userVote)); + up.setDisable(submitting); + down.setDisable(submitting); + Label scoreLabel = new Label(score > 0 ? "+" + score : Integer.toString(score)); + scoreLabel.getStyleClass().add("project-comment-score"); + if ("up".equals(userVote)) { + scoreLabel.getStyleClass().add("upvoted"); + } else if ("down".equals(userVote)) { + scoreLabel.getStyleClass().add("downvoted"); + } + vote.getChildren().addAll(up, scoreLabel, down); + return vote; + } + + private Button voteButton(LauncherIcons.Glyph glyph, Runnable action) { + Button button = new Button(null, LauncherIcons.icon(glyph, 24)); + button.getStyleClass().add("project-comment-vote-button"); + button.setOnAction(event -> { + if (currentUser.get() == null) { + signIn.run(); + return; + } + action.run(); + }); + return button; + } + + private Node markdown(String content) { + Node rendered = markdownRenderer.render(value(content, "")); + rendered.getStyleClass().add("project-comment-markdown"); + return rendered; + } + + private Node stateCard(String message) { + Label state = new Label(message); + state.getStyleClass().add("project-comments-state-label"); + return stateCard(state); + } + + private Node stateCard(Node content) { + StackPane state = new StackPane(content); + state.getStyleClass().add("project-comments-state"); + state.setMaxWidth(Double.MAX_VALUE); + return state; + } + + private Node avatar(double size, String userId, String username, String avatarUrl, boolean clickable) { + StackPane avatar = new StackPane(); + avatar.getStyleClass().add("project-comment-avatar"); + avatar.setMinSize(size, size); + avatar.setPrefSize(size, size); + avatar.setMaxSize(size, size); + Rectangle clip = new Rectangle(size, size); + clip.setArcWidth(size); + clip.setArcHeight(size); + avatar.setClip(clip); + String resolvedAvatar = value(avatarUrl, ""); + if (!resolvedAvatar.isBlank() && !"null".equalsIgnoreCase(resolvedAvatar)) { + ImageView image = new ImageView(); + image.getStyleClass().add("project-comment-avatar-image"); + image.setFitWidth(size); + image.setFitHeight(size); + image.setPreserveRatio(false); + image.setSmooth(true); + imageLoader.loadInto(image, resolvedAvatar, size * 2, size * 2); + avatar.getChildren().add(image); + } else { + Label initial = new Label(initial(username)); + initial.getStyleClass().add("project-comment-avatar-initial"); + avatar.getChildren().add(initial); + } + if (clickable && !value(userId, "").isBlank()) { + avatar.setCursor(Cursor.HAND); + avatar.setOnMouseClicked(event -> openProfile.accept(userId, username)); + } + return avatar; + } + + private Node roleBadge(RoleBadge badge) { + Label label = new Label(badge.label()); + label.getStyleClass().add("project-comment-role-badge"); + String color = badge.color(); + label.setStyle("-fx-text-fill: " + color + ";" + + "-fx-background-color: " + color + "1A;" + + "-fx-border-color: " + color + "33;"); + return label; + } + + private RoleBadge roleBadge(String userId, ProjectSummary summary, ProjectDetail detail) { + String authorId = value(detail == null ? null : detail.authorId(), summary == null ? null : summary.authorId()); + if (!value(userId, "").isBlank() && userId.equals(authorId)) { + return new RoleBadge("Owner", OWNER_ROLE_COLOR); + } + return null; + } + + private CommentIdentity identity( + String userId, + String username, + ProjectComment.Author author, + Map profiles + ) { + return identity(userId, username, author, profiles, ""); + } + + private CommentIdentity identity( + String userId, + String username, + ProjectComment.Author author, + Map profiles, + String date + ) { + String id = value(userId, author == null ? "" : author.id()); + UserSummary profile = id.isBlank() ? null : profiles.get(id); + String resolvedName = first( + profile == null ? null : profile.username(), + author == null ? null : author.username(), + username, + "Unknown" + ); + String resolvedAvatar = first(profile == null ? null : profile.avatarUrl(), author == null ? null : author.avatarUrl(), ""); + return new CommentIdentity(id, resolvedName, resolvedAvatar, date); + } + + private static boolean isCreator(CurrentUser user, ProjectSummary summary, ProjectDetail detail) { + if (user == null) { + return false; + } + String userId = value(user.id(), ""); + String userName = value(user.username(), ""); + String authorId = value(detail == null ? null : detail.authorId(), summary == null ? null : summary.authorId()); + String authorName = value(detail == null ? null : detail.author(), summary == null ? null : summary.author()); + return (!userId.isBlank() && userId.equals(authorId)) + || (!userName.isBlank() && userName.equalsIgnoreCase(authorName)); + } + + private String currentUserId() { + CurrentUser user = currentUser.get(); + return user == null ? null : user.id(); + } + + private static String initial(String username) { + String normalized = value(username, "?").trim(); + return normalized.isBlank() ? "?" : normalized.substring(0, 1).toUpperCase(Locale.ROOT); + } + + private static String first(String... values) { + for (String candidate : values) { + if (candidate != null && !candidate.isBlank() && !"null".equalsIgnoreCase(candidate)) { + return candidate; + } + } + return ""; + } + + private record CommentIdentity(String userId, String username, String avatarUrl, String date) { + } + + private record RoleBadge(String label, String color) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/NativeCreatorProfileView.java b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeCreatorProfileView.java new file mode 100644 index 00000000..58ad99ef --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeCreatorProfileView.java @@ -0,0 +1,640 @@ +package net.modtale.launcher.ui.project; + +import static net.modtale.launcher.ui.browse.card.ProjectCardFormatter.number; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.util.List; +import java.util.Locale; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import javafx.beans.binding.Bindings; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.OverrunStyle; +import javafx.scene.image.ImageView; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.model.project.ProjectPage; +import net.modtale.launcher.model.project.ProjectSummary; +import net.modtale.launcher.model.user.CreatorProfile; +import net.modtale.launcher.model.user.CurrentUser; +import net.modtale.launcher.ui.browse.card.ProjectCardFactory; +import net.modtale.launcher.ui.browse.card.ProjectCardViewStyle; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; +import net.modtale.launcher.ui.common.LauncherLayout; + +final class NativeCreatorProfileView { + + private static final double CONTENT_MAX_WIDTH = 1568; + private static final double DESKTOP_NAV_OVERLAP = 91; + private static final double PROFILE_CARD_HEIGHT = 316; + private static final double PROFILE_CARD_LIFT = -32; + private static final double AVATAR_SIZE = 224; + private static final double PROJECT_GRID_GAP = 24; + private static final double BANNER_FADE_BASE_HEIGHT = 128; + private static final int DESKTOP_PROJECT_COLUMNS = 4; + + private final CachedImageLoader imageLoader; + private final ProjectCardFactory projectCardFactory; + private final Supplier gameVersion; + private final Supplier currentUser; + private final Function favoriteResolver; + private final Consumer installProject; + private final Consumer openProject; + private final Consumer openCreator; + private final Consumer toggleFavorite; + private final Runnable showDiscover; + private final Runnable toggleFollow; + private final Runnable copyCreatorId; + private final Consumer reportCreator; + private final Consumer openUrl; + private final ReadOnlyDoubleProperty scrollPixels; + + NativeCreatorProfileView( + CachedImageLoader imageLoader, + ProjectCardFactory projectCardFactory, + Supplier gameVersion, + Supplier currentUser, + Function favoriteResolver, + Consumer installProject, + Consumer openProject, + Consumer openCreator, + Consumer toggleFavorite, + Runnable showDiscover, + Runnable toggleFollow, + Runnable copyCreatorId, + Consumer reportCreator, + Consumer openUrl, + ReadOnlyDoubleProperty scrollPixels + ) { + this.imageLoader = imageLoader; + this.projectCardFactory = projectCardFactory; + this.gameVersion = gameVersion; + this.currentUser = currentUser; + this.favoriteResolver = favoriteResolver; + this.installProject = installProject; + this.openProject = openProject; + this.openCreator = openCreator; + this.toggleFavorite = toggleFavorite; + this.showDiscover = showDiscover; + this.toggleFollow = toggleFollow; + this.copyCreatorId = copyCreatorId; + this.reportCreator = reportCreator == null ? profile -> { + } : reportCreator; + this.openUrl = openUrl; + this.scrollPixels = scrollPixels; + } + + Node render(CreatorProfile profile, ProjectPage projects, List relatedProfiles, boolean loading, boolean compact) { + VBox page = new VBox(0); + page.getStyleClass().add("creator-profile-page"); + page.setAlignment(Pos.TOP_CENTER); + page.setFillWidth(true); + page.setMinWidth(0); + page.setMaxWidth(Double.MAX_VALUE); + + StackPane hero = hero(profile); + hero.prefHeightProperty().bind(Bindings.createDoubleBinding( + () -> Math.max(compact ? 280 : 360, page.getWidth() / 3.0 - (compact ? 0 : DESKTOP_NAV_OVERLAP)), + page.widthProperty() + )); + hero.minHeightProperty().bind(hero.prefHeightProperty()); + + Node card = loading ? loadingCard() : profileCard(profile, projects); + VBox.setMargin(card, LauncherLayout.launcherPageInsets(PROFILE_CARD_LIFT, 0)); + + VBox body = profileBody(profile, projects, relatedProfiles, loading, compact); + VBox.setMargin(body, compact + ? LauncherLayout.launcherPageInsets(36, 80) + : LauncherLayout.launcherPageInsets(64, 80)); + + page.getChildren().addAll(hero, card, body); + page.minHeightProperty().bind(Bindings.createDoubleBinding( + () -> hero.getPrefHeight() + PROFILE_CARD_LIFT + PROFILE_CARD_HEIGHT + + (compact ? 36 : 64) + body.prefHeight(-1) + 80, + hero.prefHeightProperty(), + body.heightProperty() + )); + page.prefHeightProperty().bind(page.minHeightProperty()); + return page; + } + + private StackPane hero(CreatorProfile profile) { + StackPane hero = new StackPane(); + hero.getStyleClass().add("creator-profile-hero"); + hero.setMaxWidth(Double.MAX_VALUE); + + StackPane media = new StackPane(); + media.getStyleClass().add("creator-profile-banner"); + media.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + String bannerUrl = profile == null ? "" : value(profile.bannerUrl(), ""); + if (bannerUrl.isBlank()) { + media.getChildren().add(fallbackBanner()); + } else { + media.getStyleClass().add("letterboxed"); + media.setClip(rectangleClip(media)); + ImageView image = containedImage(bannerUrl, media, 2400, 800); + image.getStyleClass().add("creator-profile-banner-image"); + media.getChildren().add(image); + } + + Region fade = new Region(); + fade.getStyleClass().add("creator-profile-banner-fade"); + fade.setMouseTransparent(true); + NativeBannerScrollEffect.bind(media, fade, scrollPixels, BANNER_FADE_BASE_HEIGHT); + + HBox backLayer = new HBox(); + backLayer.setAlignment(Pos.TOP_LEFT); + backLayer.setMaxWidth(Double.MAX_VALUE); + backLayer.setMouseTransparent(false); + StackPane.setAlignment(backLayer, Pos.TOP_CENTER); + StackPane.setMargin(backLayer, LauncherLayout.launcherPageInsets(25, 0)); + Button back = new Button("Back", LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_LEFT, 16)); + back.getStyleClass().add("creator-profile-back"); + back.setOnAction(event -> showDiscover.run()); + backLayer.getChildren().add(back); + + hero.getChildren().addAll(media, fade, backLayer); + return hero; + } + + private Region fallbackBanner() { + Region fallback = new Region(); + fallback.getStyleClass().add("creator-profile-banner-fallback"); + fallback.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + return fallback; + } + + private HBox loadingCard() { + HBox card = new HBox(40); + card.getStyleClass().addAll("creator-profile-card", "creator-profile-loading-card"); + card.setAlignment(Pos.TOP_LEFT); + card.setMaxWidth(Double.MAX_VALUE); + card.setMinHeight(PROFILE_CARD_HEIGHT); + card.setPrefHeight(PROFILE_CARD_HEIGHT); + card.getChildren().add(NativeSpinner.centered()); + return card; + } + + private HBox profileCard(CreatorProfile profile, ProjectPage projects) { + HBox card = new HBox(40); + card.getStyleClass().add("creator-profile-card"); + card.setAlignment(Pos.TOP_LEFT); + card.setMaxWidth(Double.MAX_VALUE); + card.setMinHeight(PROFILE_CARD_HEIGHT); + card.setPrefHeight(PROFILE_CARD_HEIGHT); + + StackPane avatar = avatar(profile); + HBox.setMargin(avatar, new Insets(-96, 0, 0, 8)); + + VBox copy = new VBox(0); + copy.getStyleClass().add("creator-profile-copy"); + copy.setTranslateY(-15); + copy.setMinWidth(0); + HBox.setHgrow(copy, Priority.ALWAYS); + copy.getChildren().addAll( + heading(profile), + actionRow(profile), + bio(profile), + statDivider(), + statRow(profile, projects) + ); + + card.getChildren().addAll(avatar, copy); + return card; + } + + private StackPane avatar(CreatorProfile profile) { + StackPane frame = new StackPane(); + frame.getStyleClass().add("creator-profile-avatar"); + lock(frame, AVATAR_SIZE, AVATAR_SIZE); + + StackPane media = new StackPane(); + media.getStyleClass().add("creator-profile-avatar-media"); + double mediaSize = AVATAR_SIZE - 16; + lock(media, mediaSize, mediaSize); + Rectangle clip = new Rectangle(mediaSize, mediaSize); + clip.setArcWidth(40); + clip.setArcHeight(40); + media.setClip(clip); + + String avatarUrl = profile == null ? "" : value(profile.avatarUrl(), ""); + if (!avatarUrl.isBlank()) { + ImageView image = coverImage(avatarUrl, media, AVATAR_SIZE, AVATAR_SIZE); + image.getStyleClass().add("creator-profile-avatar-image"); + media.getChildren().add(image); + } else { + Label initial = new Label(initial(profile == null ? "" : profile.username())); + initial.getStyleClass().add("creator-profile-avatar-initial"); + media.getChildren().add(initial); + } + frame.getChildren().add(media); + return frame; + } + + private HBox heading(CreatorProfile profile) { + HBox row = new HBox(10); + row.getStyleClass().add("creator-profile-heading-row"); + row.setAlignment(Pos.CENTER_LEFT); + Label title = new Label(value(profile.username(), "Creator")); + title.getStyleClass().add("creator-profile-title"); + title.setTextOverrun(OverrunStyle.ELLIPSIS); + row.getChildren().add(title); + + if (profile.organization()) { + row.getChildren().add(badge("Organization", "organization", LauncherIcons.Glyph.BOX)); + } + for (String badge : profile.badges()) { + String normalized = value(badge, "").toUpperCase(Locale.ROOT); + if (normalized.equals("OG") || normalized.equals("VERIFIED")) { + row.getChildren().add(badge(normalized.equals("OG") ? "OG" : "Verified", normalized.toLowerCase(Locale.ROOT), null)); + } + } + return row; + } + + private Node badge(String text, String style, LauncherIcons.Glyph glyph) { + HBox badge = new HBox(5); + badge.getStyleClass().addAll("creator-profile-badge", style); + badge.setAlignment(Pos.CENTER); + if (glyph != null) { + badge.getChildren().add(LauncherIcons.icon(glyph, 13)); + } + badge.getChildren().add(new Label(text)); + return badge; + } + + private HBox actionRow(CreatorProfile profile) { + HBox row = new HBox(10); + row.getStyleClass().add("creator-profile-action-row"); + row.setAlignment(Pos.CENTER_LEFT); + VBox.setMargin(row, new Insets(7, 0, 0, 0)); + + CurrentUser user = currentUser.get(); + boolean self = user != null && value(user.id(), "").equals(value(profile.id(), "")); + boolean signedIn = user != null; + boolean following = signedIn && user.followsUser(profile.id()); + + Button follow = new Button(self ? "Manage Profile" : signedIn ? following ? "Following" : "Follow" : "Sign in to follow"); + follow.getStyleClass().addAll("creator-profile-follow", following ? "following" : "primary"); + follow.setGraphic(LauncherIcons.icon(self ? LauncherIcons.Glyph.GEAR + : signedIn ? following ? LauncherIcons.Glyph.CHECK : LauncherIcons.Glyph.USER + : LauncherIcons.Glyph.LOG_OUT, 18)); + follow.setOnAction(event -> toggleFollow.run()); + + Button copy = iconAction(LauncherIcons.Glyph.COPY, "Copy ID"); + copy.setOnAction(event -> copyCreatorId.run()); + + Button report = iconAction(LauncherIcons.Glyph.FLAG, "Report User"); + report.getStyleClass().add("report"); + report.setOnAction(event -> reportCreator.accept(profile)); + + row.getChildren().addAll(follow, copy); + if (!self) { + row.getChildren().add(report); + } + return row; + } + + private Button iconAction(LauncherIcons.Glyph glyph, String accessibleText) { + Button button = new Button(null, LauncherIcons.icon(glyph, 20)); + button.getStyleClass().add("creator-profile-icon-action"); + button.setAccessibleText(accessibleText); + return button; + } + + private Label bio(CreatorProfile profile) { + Label bio = new Label(value(profile.bio(), "")); + bio.getStyleClass().add("creator-profile-bio"); + bio.setWrapText(true); + bio.setMinHeight(Region.USE_PREF_SIZE); + bio.setVisible(!bio.getText().isBlank()); + bio.setManaged(!bio.getText().isBlank()); + VBox.setMargin(bio, new Insets(20, 0, 0, 0)); + return bio; + } + + private Region statDivider() { + Region line = new Region(); + line.getStyleClass().add("creator-profile-divider"); + line.setMaxWidth(Double.MAX_VALUE); + line.setMinHeight(1); + line.setPrefHeight(1); + VBox.setMargin(line, new Insets(26, 0, 0, 0)); + return line; + } + + private HBox statRow(CreatorProfile profile, ProjectPage projects) { + HBox row = new HBox(0); + row.getStyleClass().add("creator-profile-stat-row"); + row.setAlignment(Pos.CENTER_LEFT); + VBox.setMargin(row, new Insets(23, 0, 0, 0)); + row.getChildren().add(stats(profile, projects)); + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + row.getChildren().add(spacer); + + HBox socials = socials(profile); + row.getChildren().add(socials); + return row; + } + + private HBox stats(CreatorProfile profile, ProjectPage projects) { + int downloads = 0; + int favorites = 0; + List content = projects == null ? List.of() : projects.content(); + for (ProjectSummary project : content) { + downloads += project.downloadCount(); + favorites += project.favoriteCount(); + } + HBox row = new HBox(34); + row.setAlignment(Pos.CENTER_LEFT); + row.getChildren().addAll( + stat(number(downloads), "Downloads"), + stat(number(favorites), "Favorites"), + stat(number(followerCount(profile)), "Followers"), + stat(number(projects == null ? content.size() : Math.toIntExact(Math.min(Integer.MAX_VALUE, projects.totalElements()))), "Projects") + ); + return row; + } + + private VBox stat(String value, String label) { + VBox stat = new VBox(1); + stat.getStyleClass().add("creator-profile-stat"); + Label number = new Label(value); + number.getStyleClass().add("creator-profile-stat-number"); + Label caption = new Label(label.toUpperCase(Locale.ROOT)); + caption.getStyleClass().add("creator-profile-stat-caption"); + stat.getChildren().addAll(number, caption); + return stat; + } + + private HBox socials(CreatorProfile profile) { + HBox row = new HBox(8); + row.getStyleClass().add("creator-profile-socials"); + row.setAlignment(Pos.CENTER_RIGHT); + for (CreatorProfile.ConnectedAccount account : profile.connectedAccounts()) { + if (account.isVisible()) { + row.getChildren().add(socialButton(account)); + } + } + return row; + } + + private Button socialButton(CreatorProfile.ConnectedAccount account) { + String provider = value(account.provider(), "website").toLowerCase(Locale.ROOT); + Button button = new Button(null, socialIcon(provider)); + button.getStyleClass().addAll("creator-profile-social-button", provider); + button.setAccessibleText(provider + " profile"); + String url = socialUrl(account); + button.setOnAction(event -> openUrl.accept(url)); + return button; + } + + private Node socialIcon(String provider) { + return switch (provider) { + case "discord" -> LauncherIcons.brandIcon(LauncherIcons.BrandGlyph.DISCORD, 18); + case "github" -> LauncherIcons.brandIcon(LauncherIcons.BrandGlyph.GITHUB, 18); + case "gitlab" -> LauncherIcons.brandIcon(LauncherIcons.BrandGlyph.GITLAB, 18); + default -> LauncherIcons.icon(LauncherIcons.Glyph.GLOBE, 18); + }; + } + + private String socialUrl(CreatorProfile.ConnectedAccount account) { + String provider = value(account.provider(), "").toLowerCase(Locale.ROOT); + if (provider.equals("discord") && !value(account.providerId(), "").isBlank()) { + return "https://discord.com/users/" + account.providerId(); + } + return value(account.profileUrl(), ""); + } + + private VBox profileBody( + CreatorProfile profile, + ProjectPage projects, + List relatedProfiles, + boolean loading, + boolean compact + ) { + VBox body = new VBox(0); + body.getStyleClass().add("creator-profile-body"); + body.setMaxWidth(Double.MAX_VALUE); + body.setMinWidth(0); + + if (!loading && relatedProfiles != null && !relatedProfiles.isEmpty()) { + body.getChildren().add(relatedProfiles(profile, relatedProfiles)); + } + + Label heading = new Label("Published Work"); + heading.getStyleClass().add("creator-profile-section-title"); + body.getChildren().add(heading); + + Node content = loading ? projectSkeletonGrid(compact) : projects(projects, compact); + VBox.setMargin(content, new Insets(24, 0, 0, 0)); + body.getChildren().add(content); + return body; + } + + private VBox relatedProfiles(CreatorProfile profile, List relatedProfiles) { + VBox section = new VBox(14); + section.getStyleClass().add("creator-profile-related-section"); + Label title = new Label(profile.organization() ? "Organization Members" : "Member Organizations"); + title.getStyleClass().add("creator-profile-section-title"); + FlowPane chips = new FlowPane(16, 12); + chips.getStyleClass().add("creator-profile-related-grid"); + for (CreatorProfile related : relatedProfiles) { + chips.getChildren().add(profileChip(related)); + } + section.getChildren().addAll(title, chips); + VBox.setMargin(section, new Insets(0, 0, 44, 0)); + return section; + } + + private HBox profileChip(CreatorProfile profile) { + HBox chip = new HBox(12); + chip.getStyleClass().add("creator-profile-related-chip"); + chip.setAlignment(Pos.CENTER_LEFT); + chip.setOnMouseClicked(event -> openUrl.accept("https://modtale.net/creator/" + value(profile.username(), profile.id()))); + chip.setCursor(Cursor.HAND); + StackPane avatar = smallAvatar(profile); + VBox copy = new VBox(1); + Label name = new Label(value(profile.username(), "Creator")); + name.getStyleClass().add("creator-profile-related-name"); + Label role = new Label(profile.organization() ? "Organization" : "Member"); + role.getStyleClass().add("creator-profile-related-role"); + copy.getChildren().addAll(name, role); + chip.getChildren().addAll(avatar, copy); + return chip; + } + + private StackPane smallAvatar(CreatorProfile profile) { + StackPane frame = new StackPane(); + frame.getStyleClass().add("creator-profile-related-avatar"); + lock(frame, 40, 40); + String avatarUrl = value(profile.avatarUrl(), ""); + if (!avatarUrl.isBlank()) { + frame.setClip(roundedClip(frame, 8)); + ImageView image = coverImage(avatarUrl, frame, 80, 80); + frame.getChildren().add(image); + } else { + Label initial = new Label(initial(profile.username())); + initial.getStyleClass().add("creator-profile-related-initial"); + frame.getChildren().add(initial); + } + return frame; + } + + private Node projectSkeletonGrid(boolean compact) { + FlowPane grid = projectGrid(); + int count = compact ? 3 : 8; + for (int i = 0; i < count; i++) { + Region skeleton = new Region(); + skeleton.getStyleClass().add("creator-profile-project-skeleton"); + lock(skeleton, compact ? 320 : projectCardWidth(), compact ? 160 : projectCardWidth()); + grid.getChildren().add(skeleton); + } + return grid; + } + + private Node projects(ProjectPage projects, boolean compact) { + List content = projects == null ? List.of() : projects.content(); + if (content.isEmpty()) { + VBox empty = new VBox(10); + empty.getStyleClass().add("creator-profile-empty"); + empty.setAlignment(Pos.CENTER); + empty.getChildren().addAll(LauncherIcons.icon(LauncherIcons.Glyph.BOX, 36), + new Label("No projects found"), + new Label("This user hasn't published any projects yet.")); + return empty; + } + + FlowPane grid = projectGrid(); + double width = compact ? 320 : projectCardWidth(); + for (ProjectSummary project : content) { + Node card = projectCardFactory.create( + project, + compact ? ProjectCardViewStyle.LIST : ProjectCardViewStyle.GRID, + gameVersion.get(), + Boolean.TRUE.equals(favoriteResolver.apply(project.id())), + installProject, + openProject, + openCreator, + toggleFavorite, + width, + compact ? 160 : width + ); + grid.getChildren().add(card); + } + return grid; + } + + private FlowPane projectGrid() { + FlowPane grid = new FlowPane(PROJECT_GRID_GAP, PROJECT_GRID_GAP); + grid.getStyleClass().add("creator-profile-project-grid"); + grid.setMaxWidth(CONTENT_MAX_WIDTH); + return grid; + } + + private double projectCardWidth() { + return Math.floor((CONTENT_MAX_WIDTH - PROJECT_GRID_GAP * (DESKTOP_PROJECT_COLUMNS - 1)) / DESKTOP_PROJECT_COLUMNS); + } + + private ImageView coverImage(String url, Region box, double requestedWidth, double requestedHeight) { + ImageView image = new ImageView(); + image.setSmooth(true); + image.setPreserveRatio(false); + imageLoader.loadInto(image, url, requestedWidth, requestedHeight, true); + Runnable update = () -> { + double width = box.getWidth(); + double height = box.getHeight(); + javafx.scene.image.Image loaded = image.getImage(); + if (!Double.isFinite(width) || width <= 1 || !Double.isFinite(height) || height <= 1 || loaded == null) { + image.setFitWidth(requestedWidth); + image.setFitHeight(requestedHeight); + return; + } + double imageWidth = loaded.getWidth(); + double imageHeight = loaded.getHeight(); + if (!Double.isFinite(imageWidth) || imageWidth <= 0 || !Double.isFinite(imageHeight) || imageHeight <= 0) { + return; + } + double imageRatio = imageWidth / imageHeight; + double boxRatio = width / height; + if (imageRatio > boxRatio) { + image.setFitWidth(height * imageRatio); + image.setFitHeight(height); + } else { + image.setFitWidth(width); + image.setFitHeight(width / imageRatio); + } + }; + box.widthProperty().addListener((observable, previous, current) -> update.run()); + box.heightProperty().addListener((observable, previous, current) -> update.run()); + image.imageProperty().addListener((observable, previous, current) -> update.run()); + return image; + } + + private ImageView containedImage(String url, Region box, double requestedWidth, double requestedHeight) { + ImageView image = new ImageView(); + image.setSmooth(true); + image.setPreserveRatio(true); + image.fitWidthProperty().bind(box.widthProperty()); + image.fitHeightProperty().bind(box.heightProperty()); + imageLoader.loadInto(image, url, requestedWidth, requestedHeight, true); + return image; + } + + private Rectangle rectangleClip(Region owner) { + Rectangle clip = new Rectangle(); + clip.widthProperty().bind(owner.widthProperty()); + clip.heightProperty().bind(owner.heightProperty()); + return clip; + } + + private Rectangle roundedClip(Region owner, double radius) { + Rectangle clip = rectangleClip(owner); + clip.setArcWidth(radius * 2); + clip.setArcHeight(radius * 2); + return clip; + } + + private int followerCount(CreatorProfile profile) { + CurrentUser user = currentUser.get(); + int count = profile.followerIds().size(); + if (user == null || value(user.id(), "").isBlank()) { + return count; + } + boolean actual = user.followsUser(profile.id()); + boolean recorded = profile.followerIds().contains(user.id()); + if (actual && !recorded) { + return count + 1; + } + if (!actual && recorded) { + return Math.max(0, count - 1); + } + return count; + } + + private static void lock(Region region, double width, double height) { + region.setMinSize(width, height); + region.setPrefSize(width, height); + region.setMaxSize(width, height); + } + + private static String initial(String value) { + String normalized = value(value, "C").trim(); + return normalized.isEmpty() ? "C" : normalized.substring(0, 1).toUpperCase(Locale.ROOT); + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/NativeDependencyModal.java b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeDependencyModal.java new file mode 100644 index 00000000..8f7cc80d --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeDependencyModal.java @@ -0,0 +1,512 @@ +package net.modtale.launcher.ui.project; + +import java.util.IdentityHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.css.PseudoClass; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.control.OverrunStyle; +import javafx.scene.control.ScrollPane; +import javafx.scene.effect.Effect; +import javafx.scene.effect.GaussianBlur; +import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import net.modtale.launcher.api.ModtaleApiClient; +import net.modtale.launcher.model.project.ProjectDependency; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectMeta; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class NativeDependencyModal { + + private static final double MODAL_WIDTH = 512; + private static final double MODAL_MAX_HEIGHT = 720; + private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected"); + private static final PseudoClass MISSING = PseudoClass.getPseudoClass("missing"); + + private final Supplier host; + private final ModtaleApiClient apiClient; + private final Executor executor; + private final CachedImageLoader imageLoader; + private final Consumer install; + private final Map backdropEffects = new IdentityHashMap<>(); + private final Map metadata = new ConcurrentHashMap<>(); + private final Set requestedMetadataIds = ConcurrentHashMap.newKeySet(); + private final Set selectedDependencyIds = new LinkedHashSet<>(); + + private StackPane overlay; + private ProjectDetail project; + private ProjectVersion version; + private String gameVersion; + private List dependencies = List.of(); + + NativeDependencyModal( + Supplier host, + ModtaleApiClient apiClient, + Executor executor, + CachedImageLoader imageLoader, + Consumer install + ) { + this.host = host == null ? () -> null : host; + this.apiClient = apiClient; + this.executor = executor; + this.imageLoader = imageLoader; + this.install = install == null ? ignored -> { + } : install; + } + + void show(ProjectDetail project, ProjectVersion version, String gameVersion) { + this.project = project; + this.version = version; + this.gameVersion = gameVersion; + this.dependencies = selectableDependencies(version); + this.selectedDependencyIds.clear(); + this.dependencies.stream() + .map(ProjectDependency::projectId) + .filter(id -> id != null && !id.isBlank()) + .forEach(selectedDependencyIds::add); + rebuildOverlay(); + requestDependencyMetadata(); + } + + void hide() { + if (overlay == null) { + return; + } + Parent parent = overlay.getParent(); + if (parent instanceof StackPane stack) { + stack.getChildren().remove(overlay); + } + overlay = null; + restoreBackdrop(); + } + + private void rebuildOverlay() { + StackPane hostPane = host.get(); + if (hostPane == null || project == null || version == null) { + return; + } + if (overlay == null) { + overlay = overlayShell(); + blurBackdrop(hostPane); + hostPane.getChildren().add(overlay); + } + overlay.getChildren().setAll(modal()); + Platform.runLater(overlay::requestFocus); + } + + private StackPane overlayShell() { + StackPane shell = new StackPane(); + shell.getStyleClass().add("dependency-modal-overlay"); + shell.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + shell.setFocusTraversable(true); + shell.addEventHandler(KeyEvent.KEY_PRESSED, event -> { + if (event.getCode() == KeyCode.ESCAPE) { + hide(); + event.consume(); + } + }); + shell.setOnMouseClicked(event -> { + if (event.getTarget() == shell) { + hide(); + } + }); + return shell; + } + + private VBox modal() { + VBox modal = new VBox(0); + modal.getStyleClass().add("dependency-modal"); + modal.setMaxWidth(MODAL_WIDTH); + modal.setPrefWidth(MODAL_WIDTH); + modal.setMaxHeight(MODAL_MAX_HEIGHT); + modal.setOnMouseClicked(event -> event.consume()); + + ScrollPane bodyScroll = new ScrollPane(body()); + bodyScroll.getStyleClass().add("dependency-modal-scroll"); + bodyScroll.setFitToWidth(true); + bodyScroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + bodyScroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + VBox.setVgrow(bodyScroll, Priority.ALWAYS); + + modal.getChildren().addAll(header(), bodyScroll, footer()); + return modal; + } + + private HBox header() { + HBox header = new HBox(16); + header.getStyleClass().add("dependency-modal-header"); + header.setAlignment(Pos.CENTER_LEFT); + + HBox title = new HBox(8, LauncherIcons.icon(LauncherIcons.Glyph.LINK, 20), new Label("Dependencies")); + title.getStyleClass().add("dependency-modal-title"); + title.setAlignment(Pos.CENTER_LEFT); + HBox.setHgrow(title, Priority.ALWAYS); + + Button close = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.X, 18)); + close.getStyleClass().add("dependency-modal-close"); + close.setOnAction(event -> hide()); + header.getChildren().addAll(title, close); + return header; + } + + private VBox body() { + VBox body = new VBox(16); + body.getStyleClass().add("dependency-modal-body"); + body.getChildren().addAll(summaryRow(), dependencyList()); + Node warning = missingRequiredWarning(); + if (warning != null) { + body.getChildren().add(warning); + } + return body; + } + + private HBox summaryRow() { + HBox row = new HBox(12); + row.setAlignment(Pos.TOP_LEFT); + VBox copy = new VBox(2); + HBox.setHgrow(copy, Priority.ALWAYS); + Label description = new Label("Select dependencies to include in your bundle download."); + description.getStyleClass().add("dependency-modal-description"); + description.setWrapText(true); + copy.getChildren().add(description); + + Button toggle = new Button(selectedDependencyIds.size() == dependencies.size() ? "Deselect All" : "Select All"); + toggle.getStyleClass().add("dependency-modal-toggle-all"); + toggle.setOnAction(event -> toggleAll()); + row.getChildren().addAll(copy, toggle); + return row; + } + + private VBox dependencyList() { + VBox list = new VBox(8); + list.getStyleClass().add("dependency-modal-list"); + for (ProjectDependency dependency : dependencies) { + list.getChildren().add(dependencyRow(dependency)); + } + return list; + } + + private Node dependencyRow(ProjectDependency dependency) { + boolean selected = selectedDependencyIds.contains(dependency.projectId()); + boolean missingRequired = !dependency.isOptional() && !selected; + + HBox row = new HBox(16); + row.getStyleClass().add("dependency-modal-row"); + row.pseudoClassStateChanged(SELECTED, selected); + row.pseudoClassStateChanged(MISSING, missingRequired); + row.setAlignment(Pos.CENTER_LEFT); + row.setOnMouseClicked(event -> toggleDependency(dependency)); + + HBox left = new HBox(16); + left.setAlignment(Pos.CENTER_LEFT); + left.setMinWidth(0); + HBox.setHgrow(left, Priority.ALWAYS); + left.getChildren().addAll(selectionState(selected, missingRequired), dependencyIcon(dependency), dependencyCopy(dependency)); + + Label badge = dependencyBadge(dependency, missingRequired); + row.getChildren().addAll(left, badge); + return row; + } + + private StackPane selectionState(boolean selected, boolean missingRequired) { + StackPane state = new StackPane(); + state.getStyleClass().add("dependency-modal-state"); + if (selected) { + state.getStyleClass().add("selected"); + state.getChildren().add(LauncherIcons.icon(LauncherIcons.Glyph.CHECK, 13)); + } else if (missingRequired) { + state.getStyleClass().add("missing"); + Label bang = new Label("!"); + bang.getStyleClass().add("dependency-modal-state-warning"); + state.getChildren().add(bang); + } + return state; + } + + private StackPane dependencyIcon(ProjectDependency dependency) { + StackPane icon = new StackPane(); + icon.getStyleClass().add("dependency-modal-icon"); + String iconUrl = dependencyIconUrl(dependency); + if (imageLoader != null && iconUrl != null && !iconUrl.isBlank()) { + ImageView image = new ImageView(); + image.setFitWidth(44); + image.setFitHeight(44); + image.setPreserveRatio(false); + image.setSmooth(true); + Rectangle clip = new Rectangle(44, 44); + clip.setArcWidth(8); + clip.setArcHeight(8); + image.setClip(clip); + imageLoader.loadInto(image, iconUrl, 88, 88); + icon.getChildren().add(image); + } else { + icon.getChildren().add(LauncherIcons.icon(LauncherIcons.Glyph.BOX, 20)); + } + return icon; + } + + private VBox dependencyCopy(ProjectDependency dependency) { + VBox copy = new VBox(4); + copy.setMinWidth(0); + HBox.setHgrow(copy, Priority.ALWAYS); + + Label title = new Label(dependencyTitle(dependency)); + title.getStyleClass().add("dependency-modal-dependency-title"); + title.setTextOverrun(OverrunStyle.ELLIPSIS); + title.setMaxWidth(Double.MAX_VALUE); + + HBox meta = new HBox(7); + meta.getStyleClass().add("dependency-modal-meta"); + meta.setAlignment(Pos.CENTER_LEFT); + Label author = new Label("by " + dependencyAuthor(dependency)); + author.getStyleClass().add("dependency-modal-author"); + meta.getChildren().add(author); + if (!isBlank(dependency.versionNumber())) { + Region dot = new Region(); + dot.getStyleClass().add("dependency-modal-dot"); + Label versionLabel = new Label("v" + dependency.versionNumber()); + versionLabel.getStyleClass().add("dependency-modal-version"); + meta.getChildren().addAll(dot, versionLabel); + } + + copy.getChildren().addAll(title, meta); + return copy; + } + + private Label dependencyBadge(ProjectDependency dependency, boolean missingRequired) { + Label badge = new Label(dependency.isOptional() ? "OPTIONAL" : "REQUIRED"); + badge.getStyleClass().add("dependency-modal-badge"); + if (missingRequired) { + badge.getStyleClass().add("missing"); + badge.setGraphic(LauncherIcons.icon(LauncherIcons.Glyph.ALERT_CIRCLE, 12)); + } else if (dependency.isOptional()) { + badge.getStyleClass().add("optional"); + } else { + badge.getStyleClass().add("required"); + } + return badge; + } + + private Node missingRequiredWarning() { + if (!missingRequired()) { + return null; + } + HBox warning = new HBox(8); + warning.getStyleClass().add("dependency-modal-warning"); + warning.setAlignment(Pos.TOP_LEFT); + Label copy = new Label("You have unselected Required dependencies. The project may not function correctly without them."); + copy.getStyleClass().add("dependency-modal-warning-copy"); + copy.setWrapText(true); + HBox.setHgrow(copy, Priority.ALWAYS); + warning.getChildren().addAll(LauncherIcons.icon(LauncherIcons.Glyph.ALERT_CIRCLE, 16), copy); + return warning; + } + + private HBox footer() { + HBox footer = new HBox(); + footer.getStyleClass().add("dependency-modal-footer"); + footer.setAlignment(Pos.CENTER); + Button download = new Button(); + download.getStyleClass().add("dependency-modal-download"); + download.setMaxWidth(Double.MAX_VALUE); + download.setAlignment(Pos.CENTER); + download.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + download.setGraphic(downloadButtonContent()); + download.setOnAction(event -> installSelected()); + HBox.setHgrow(download, Priority.ALWAYS); + footer.getChildren().add(download); + return footer; + } + + private VBox downloadButtonContent() { + VBox content = new VBox(3); + content.setAlignment(Pos.CENTER); + content.setMaxWidth(Double.MAX_VALUE); + HBox title = new HBox(8, LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 20), + new Label(selectedDependencyIds.isEmpty() ? "Download Project Only" : "Download Bundle")); + title.getStyleClass().add("dependency-modal-download-title"); + title.setAlignment(Pos.CENTER); + title.setMaxWidth(Double.MAX_VALUE); + content.getChildren().add(title); + if (!selectedDependencyIds.isEmpty()) { + Label subtitle = new Label("Includes project + " + selectedDependencyIds.size() + + " dependenc" + (selectedDependencyIds.size() == 1 ? "y" : "ies")); + subtitle.getStyleClass().add("dependency-modal-download-subtitle"); + subtitle.setAlignment(Pos.CENTER); + subtitle.setMaxWidth(Double.MAX_VALUE); + content.getChildren().add(subtitle); + } + return content; + } + + private void toggleDependency(ProjectDependency dependency) { + String id = dependency.projectId(); + if (id == null || id.isBlank()) { + return; + } + if (selectedDependencyIds.contains(id)) { + selectedDependencyIds.remove(id); + } else { + selectedDependencyIds.add(id); + } + rebuildOverlay(); + } + + private void toggleAll() { + if (selectedDependencyIds.size() == dependencies.size()) { + selectedDependencyIds.clear(); + } else { + selectedDependencyIds.clear(); + dependencies.stream() + .map(ProjectDependency::projectId) + .filter(id -> id != null && !id.isBlank()) + .forEach(selectedDependencyIds::add); + } + rebuildOverlay(); + } + + private boolean missingRequired() { + return dependencies.stream() + .anyMatch(dependency -> !dependency.isOptional() && !selectedDependencyIds.contains(dependency.projectId())); + } + + private void installSelected() { + ProjectDetail selectedProject = project; + ProjectVersion selectedVersion = version; + String selectedGameVersion = gameVersion; + List selectedDependencies = dependencies.stream() + .filter(dependency -> selectedDependencyIds.contains(dependency.projectId())) + .toList(); + hide(); + install.accept(new DependencySelection(selectedProject, selectedVersion, selectedGameVersion, selectedDependencies)); + } + + private void requestDependencyMetadata() { + if (apiClient == null || executor == null || dependencies.isEmpty()) { + return; + } + List missing = dependencies.stream() + .map(ProjectDependency::projectId) + .filter(id -> id != null && !id.isBlank()) + .filter(id -> !metadata.containsKey(id) && requestedMetadataIds.add(id)) + .distinct() + .toList(); + if (missing.isEmpty()) { + return; + } + ProjectDetail expectedProject = project; + ProjectVersion expectedVersion = version; + CompletableFuture.supplyAsync(() -> apiClient.getProjectMetaBatch(missing), executor) + .whenComplete((result, error) -> Platform.runLater(() -> { + Map next = error == null && result != null ? result : Map.of(); + for (String id : missing) { + metadata.put(id, next.getOrDefault(id, fallbackMeta(id))); + } + if (project == expectedProject && version == expectedVersion && overlay != null) { + rebuildOverlay(); + } + })); + } + + private void blurBackdrop(StackPane hostPane) { + restoreBackdrop(); + for (Node child : hostPane.getChildren()) { + backdropEffects.put(child, child.getEffect()); + child.setEffect(new GaussianBlur(6)); + } + } + + private void restoreBackdrop() { + backdropEffects.forEach(Node::setEffect); + backdropEffects.clear(); + } + + static List selectableDependencies(ProjectVersion version) { + if (version == null || version.dependencies() == null) { + return List.of(); + } + return version.dependencies().stream() + .filter(dependency -> dependency != null + && !dependency.isEmbedded() + && !dependency.isExternal() + && !isBlank(dependency.projectId())) + .toList(); + } + + private String dependencyTitle(ProjectDependency dependency) { + ProjectMeta meta = dependencyMeta(dependency); + return firstNonBlank( + meta == null ? null : meta.title(), + dependency.title(), + dependency.projectTitle(), + dependency.projectId(), + dependency.id(), + "Dependency" + ); + } + + private String dependencyAuthor(ProjectDependency dependency) { + ProjectMeta meta = dependencyMeta(dependency); + return firstNonBlank(meta == null ? null : meta.author(), "..."); + } + + private String dependencyIconUrl(ProjectDependency dependency) { + ProjectMeta meta = dependencyMeta(dependency); + return firstNonBlank(meta == null ? null : meta.icon(), dependency.icon()); + } + + private ProjectMeta dependencyMeta(ProjectDependency dependency) { + if (dependency == null || isBlank(dependency.projectId())) { + return null; + } + return metadata.get(dependency.projectId()); + } + + private static ProjectMeta fallbackMeta(String projectId) { + return new ProjectMeta("", "", "", "...", "", 0, "", ""); + } + + private static String firstNonBlank(String... values) { + for (String candidate : values) { + if (!isBlank(candidate)) { + return candidate; + } + } + return ""; + } + + private static boolean isBlank(String value) { + return value == null || value.isBlank(); + } + + record DependencySelection( + ProjectDetail project, + ProjectVersion version, + String gameVersion, + List selectedDependencies + ) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/NativeDownloadModal.java b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeDownloadModal.java new file mode 100644 index 00000000..acb0ffa2 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeDownloadModal.java @@ -0,0 +1,844 @@ +package net.modtale.launcher.ui.project; + +import static net.modtale.launcher.ui.browse.card.ProjectCardFormatter.timeAgo; +import static net.modtale.launcher.ui.common.LauncherUi.value; + +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javafx.application.Platform; +import javafx.css.PseudoClass; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import net.modtale.launcher.model.project.GameVersionCatalog; +import net.modtale.launcher.model.project.ProjectClassification; +import net.modtale.launcher.model.project.ProjectDetail; +import net.modtale.launcher.model.project.ProjectDependency; +import net.modtale.launcher.model.project.ProjectVersion; +import net.modtale.launcher.ui.common.GameVersionDropdown; +import net.modtale.launcher.ui.common.GameVersionGroups; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class NativeDownloadModal { + + private static final double MODAL_WIDTH = 672; + private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected"); + + private final Supplier host; + private final Supplier preferredGameVersion; + private final Consumer install; + private final Consumer viewHistory; + + private StackPane overlay; + private ProjectDetail project; + private GameVersionCatalog catalog; + private List selectedGameVersions = List.of(); + private boolean showExperimental; + private boolean showPreReleaseGameVersions; + private boolean listExpanded; + private boolean loading; + private boolean gameVersionDropdownOpen; + + NativeDownloadModal( + Supplier host, + Supplier preferredGameVersion, + Consumer install, + Consumer viewHistory + ) { + this.host = host == null ? () -> null : host; + this.preferredGameVersion = preferredGameVersion == null ? () -> "" : preferredGameVersion; + this.install = install == null ? selection -> { + } : install; + this.viewHistory = viewHistory == null ? ignored -> { + } : viewHistory; + } + + void show(ProjectDetail project, GameVersionCatalog catalog) { + this.project = project; + this.catalog = catalog == null ? GameVersionCatalog.fromVersions(List.of()) : catalog; + this.showExperimental = false; + this.showPreReleaseGameVersions = forceShowPreReleaseGameVersions(); + this.listExpanded = false; + this.loading = false; + this.gameVersionDropdownOpen = false; + this.selectedGameVersions = preferredVisibleGameVersions(); + rebuildOverlay(); + } + + void showLoading(ProjectDetail project, GameVersionCatalog catalog) { + this.project = project; + this.catalog = catalog == null ? GameVersionCatalog.fromVersions(List.of()) : catalog; + this.showExperimental = false; + this.showPreReleaseGameVersions = forceShowPreReleaseGameVersions(); + this.listExpanded = false; + this.loading = true; + this.gameVersionDropdownOpen = false; + this.selectedGameVersions = preferredVisibleGameVersions(); + rebuildOverlay(); + } + + void refresh(ProjectDetail project, GameVersionCatalog catalog) { + if (overlay == null || project == null || !sameProject(this.project, project)) { + return; + } + this.project = project; + this.catalog = catalog == null ? GameVersionCatalog.fromVersions(List.of()) : catalog; + this.loading = false; + if (!selectedGameVersions.isEmpty() && !gameVersions().containsAll(selectedGameVersions)) { + List validSelections = selectedGameVersions.stream() + .filter(gameVersions()::contains) + .toList(); + selectedGameVersions = validSelections.isEmpty() ? preferredVisibleGameVersions() : validSelections; + listExpanded = false; + } + rebuildOverlay(); + } + + boolean isShowing(ProjectDetail project) { + return overlay != null && project != null && sameProject(this.project, project); + } + + void hide() { + if (overlay == null) { + return; + } + Parent parent = overlay.getParent(); + if (parent instanceof StackPane stack) { + stack.getChildren().remove(overlay); + } + overlay = null; + } + + private void rebuildOverlay() { + StackPane hostPane = host.get(); + if (hostPane == null || project == null) { + return; + } + if (overlay == null) { + overlay = overlayShell(); + hostPane.getChildren().add(overlay); + } + overlay.getChildren().setAll(modal(hostPane)); + Platform.runLater(overlay::requestFocus); + } + + private StackPane overlayShell() { + StackPane shell = new StackPane(); + shell.getStyleClass().add("download-modal-overlay"); + shell.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + shell.setFocusTraversable(true); + shell.addEventHandler(KeyEvent.KEY_PRESSED, event -> { + if (event.getCode() == KeyCode.ESCAPE) { + hide(); + event.consume(); + } + }); + shell.setOnMouseClicked(event -> { + if (event.getTarget() == shell) { + hide(); + } + }); + return shell; + } + + private VBox modal(StackPane hostPane) { + VBox modal = new VBox(0); + modal.getStyleClass().add("download-modal"); + modal.setMaxWidth(MODAL_WIDTH); + modal.setPrefWidth(MODAL_WIDTH); + modal.setMaxHeight(Region.USE_PREF_SIZE); + modal.setOnMouseClicked(event -> event.consume()); + + ScrollPane bodyScroll = new ScrollPane(body()); + bodyScroll.getStyleClass().add("download-modal-scroll"); + bodyScroll.setFitToWidth(true); + bodyScroll.setFitToHeight(false); + bodyScroll.setMaxHeight(Region.USE_PREF_SIZE); + bodyScroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + bodyScroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + VBox.setVgrow(bodyScroll, Priority.NEVER); + + modal.getChildren().addAll(header(), bodyScroll, footer()); + return modal; + } + + private HBox header() { + HBox header = new HBox(16); + header.getStyleClass().add("download-modal-header"); + header.setAlignment(Pos.CENTER_LEFT); + + VBox copy = new VBox(4); + copy.setMinWidth(0); + HBox.setHgrow(copy, Priority.ALWAYS); + HBox title = new HBox(9); + title.getStyleClass().add("download-modal-title-row"); + title.setAlignment(Pos.CENTER_LEFT); + Label label = new Label("Download"); + label.getStyleClass().add("download-modal-title"); + title.getChildren().addAll(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 20), label); + copy.getChildren().add(title); + + if (showPreReleaseToggle()) { + copy.getChildren().add(toggleRow( + "Show Pre-Release Game Versions", + effectiveShowPreReleaseGameVersions(), + () -> { + showPreReleaseGameVersions = !showPreReleaseGameVersions; + selectedGameVersions = preferredVisibleGameVersions(); + listExpanded = false; + gameVersionDropdownOpen = false; + rebuildOverlay(); + } + )); + } + if (showAlphaBetaToggle()) { + copy.getChildren().add(toggleRow( + "Show Beta/Alpha", + effectiveShowExperimental(), + () -> { + showExperimental = !showExperimental; + selectedGameVersions = preferredVisibleGameVersions(); + listExpanded = false; + gameVersionDropdownOpen = false; + rebuildOverlay(); + } + )); + } + + Button close = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.X, 18)); + close.getStyleClass().add("download-modal-close"); + close.setOnAction(event -> hide()); + header.getChildren().addAll(copy, close); + return header; + } + + private HBox toggleRow(String text, boolean selected, Runnable action) { + HBox row = new HBox(8); + row.getStyleClass().add("download-modal-toggle-row"); + row.setAlignment(Pos.CENTER_LEFT); + row.setOnMouseClicked(event -> action.run()); + StackPane switchTrack = new StackPane(); + switchTrack.getStyleClass().add("download-modal-toggle"); + switchTrack.pseudoClassStateChanged(SELECTED, selected); + Region knob = new Region(); + knob.getStyleClass().add("download-modal-toggle-knob"); + switchTrack.getChildren().add(knob); + StackPane.setAlignment(knob, selected ? Pos.CENTER_RIGHT : Pos.CENTER_LEFT); + Label label = new Label(text.toUpperCase(Locale.ROOT)); + label.getStyleClass().add("download-modal-toggle-label"); + row.getChildren().addAll(switchTrack, label); + return row; + } + + private VBox body() { + VBox body = new VBox(0); + body.getStyleClass().add("download-modal-body"); + + if (loading && project.versions().isEmpty()) { + body.getChildren().add(loadingState()); + return body; + } + + VBox versionBlock = new VBox(8); + versionBlock.getStyleClass().add("download-modal-version-block"); + Label versionLabel = new Label("GAME VERSION"); + versionLabel.getStyleClass().add("download-modal-field-label"); + GameVersionDropdown versions = GameVersionDropdown.multiSelect(); + versions.getStyleClass().add("download-game-version-dropdown"); + versions.setAnyLabel("Any"); + versions.setEmptyText("No compatible game versions"); + versions.setMaxListHeight(224); + versions.setVersions(gameVersions()); + versions.setSelectedVersions(selectedGameVersions); + versions.setOnOpenChange(open -> gameVersionDropdownOpen = open); + versions.setOnSelectionChange(next -> { + selectedGameVersions = List.copyOf(next); + listExpanded = false; + rebuildOverlay(); + }); + versions.setOpen(gameVersionDropdownOpen); + versionBlock.getChildren().addAll(versionLabel, versions); + body.getChildren().add(versionBlock); + + List sortedVersions = sortedVisibleVersions(); + VersionEntry latest = sortedVersions.isEmpty() ? null : sortedVersions.getFirst(); + if (latest == null) { + body.getChildren().add(emptyState()); + return body; + } + + Button latestButton = latestButton(latest); + Node latestExternalNotice = externalDependencyNotice(latest.version()); + VBox.setMargin(latestButton, new Insets(0, 0, latestExternalNotice == null ? 24 : 12, 0)); + body.getChildren().add(latestButton); + if (latestExternalNotice != null) { + VBox.setMargin(latestExternalNotice, new Insets(0, 0, 24, 0)); + body.getChildren().add(latestExternalNotice); + } + + body.getChildren().add(otherVersionsDivider()); + body.getChildren().add(expandVersionsButton()); + if (listExpanded) { + VBox list = new VBox(8); + list.getStyleClass().add("download-modal-version-list"); + for (VersionEntry entry : sortedVersions) { + list.getChildren().add(versionRow(entry)); + } + body.getChildren().add(list); + } + return body; + } + + private Node loadingState() { + VBox state = new VBox(12); + state.getStyleClass().add("download-modal-empty"); + state.setAlignment(Pos.CENTER); + state.getChildren().addAll( + NativeSpinner.inline("Loading download options", 20), + new Label("Fetching files and compatible game versions.") + ); + return state; + } + + private Button latestButton(VersionEntry entry) { + Button button = new Button(); + button.getStyleClass().addAll("download-modal-latest", channelStyle(entry.version().channel())); + button.setMaxWidth(Double.MAX_VALUE); + button.setGraphic(latestButtonContent(entry)); + button.setOnAction(event -> install(entry)); + return button; + } + + private VBox latestButtonContent(VersionEntry entry) { + ProjectVersion version = entry.version(); + VBox box = new VBox(6); + box.setAlignment(Pos.CENTER); + box.setFillWidth(false); + HBox headline = new HBox(8); + headline.setAlignment(Pos.CENTER); + Label text = new Label("Download Latest"); + text.getStyleClass().add("download-modal-latest-title"); + headline.getChildren().addAll(LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 24), text); + HBox badge = versionBadge(version); + badge.setMaxWidth(Region.USE_PREF_SIZE); + box.getChildren().addAll(headline, badge); + if (shouldShowEntryGameVersion()) { + Label forVersion = new Label("For " + entry.gameVersion()); + forVersion.getStyleClass().add("download-modal-file-date"); + box.getChildren().add(forVersion); + } + List others = otherCompatibleVersions(version, entry.gameVersion()); + if (!others.isEmpty()) { + Label supports = new Label("Also supports: " + String.join(", ", others)); + supports.getStyleClass().add("download-modal-also-supports"); + box.getChildren().add(supports); + } + return box; + } + + private HBox versionBadge(ProjectVersion version) { + HBox badge = new HBox(8); + badge.getStyleClass().addAll("download-modal-version-badge", channelStyle(version.channel())); + badge.setAlignment(Pos.CENTER); + Label number = new Label("v" + value(version.versionNumber(), "unknown")); + number.getStyleClass().add("download-modal-version-number"); + badge.getChildren().add(number); + if (!isRelease(version.channel())) { + Label channel = new Label(value(version.channel(), "RELEASE").toUpperCase(Locale.ROOT)); + channel.getStyleClass().add("download-modal-version-channel"); + badge.getChildren().add(channel); + } + return badge; + } + + private Node otherVersionsDivider() { + StackPane divider = new StackPane(); + divider.getStyleClass().add("download-modal-divider-wrap"); + Region line = new Region(); + line.getStyleClass().add("download-modal-divider-line"); + Label label = new Label("OTHER VERSIONS"); + label.getStyleClass().add("download-modal-divider-label"); + divider.getChildren().addAll(line, label); + return divider; + } + + private Button expandVersionsButton() { + Button button = new Button(); + button.getStyleClass().add("download-modal-expand"); + button.setMaxWidth(Double.MAX_VALUE); + + HBox content = new HBox(8); + content.getStyleClass().add("download-modal-expand-content"); + content.setAlignment(Pos.CENTER_LEFT); + content.setMinWidth(0); + content.prefWidthProperty().bind(button.widthProperty().subtract(24)); + Label text = new Label("View all files for " + selectedGameVersionLabel()); + text.getStyleClass().add("download-modal-expand-text"); + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + Node icon = LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_DOWN, 16); + icon.getStyleClass().add("download-modal-expand-icon"); + icon.setRotate(listExpanded ? 180 : 0); + content.getChildren().addAll(text, spacer, icon); + + button.setGraphic(content); + button.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + button.setOnAction(event -> { + listExpanded = !listExpanded; + rebuildOverlay(); + }); + return button; + } + + private Node versionRow(VersionEntry entry) { + ProjectVersion version = entry.version(); + VBox row = new VBox(10); + row.getStyleClass().add("download-modal-file-row"); + HBox main = new HBox(14); + main.getStyleClass().add("download-modal-file-row-main"); + main.setAlignment(Pos.CENTER_LEFT); + + StackPane icon = new StackPane(LauncherIcons.icon(LauncherIcons.Glyph.FILE_CODE, 20)); + icon.getStyleClass().add("download-modal-file-icon"); + VBox copy = new VBox(3); + copy.setMinWidth(0); + HBox.setHgrow(copy, Priority.ALWAYS); + HBox title = new HBox(8); + title.setAlignment(Pos.CENTER_LEFT); + Label versionText = new Label("v" + value(version.versionNumber(), "unknown")); + versionText.getStyleClass().add("download-modal-file-version"); + title.getChildren().add(versionText); + if (!isRelease(version.channel())) { + title.getChildren().add(channelBadge(version.channel())); + } + Label date = new Label(timeAgo(version.releaseDate())); + date.getStyleClass().add("download-modal-file-date"); + if (shouldShowEntryGameVersion()) { + date.setText(date.getText() + " · " + entry.gameVersion()); + } + copy.getChildren().addAll(title, date); + List others = otherCompatibleVersions(version, entry.gameVersion()); + if (!others.isEmpty()) { + Label supports = new Label("Also supports: " + String.join(", ", others)); + supports.getStyleClass().add("download-modal-file-supports"); + copy.getChildren().add(supports); + } + if (!externalDependencies(version).isEmpty()) { + HBox external = new HBox(4, LauncherIcons.icon(LauncherIcons.Glyph.ALERT_CIRCLE, 12), new Label("EXTERNAL MODS")); + external.getStyleClass().add("download-modal-file-external-badge"); + external.setAlignment(Pos.CENTER_LEFT); + copy.getChildren().add(external); + } + + Button download = new Button(null, LauncherIcons.icon(LauncherIcons.Glyph.DOWNLOAD, 16)); + download.getStyleClass().add("download-modal-file-download"); + download.setOnAction(event -> install(entry)); + + main.getChildren().addAll(icon, copy, download); + row.getChildren().add(main); + return row; + } + + private Label channelBadge(String channel) { + Label badge = new Label(value(channel, "RELEASE").toUpperCase(Locale.ROOT)); + badge.getStyleClass().addAll("download-modal-channel-badge", channelStyle(channel)); + return badge; + } + + private Node externalDependencyNotice(ProjectVersion version) { + if (!ProjectClassification.isModpack(project.classification())) { + return null; + } + List external = externalDependencies(version); + if (external.isEmpty()) { + return null; + } + VBox notice = new VBox(4); + notice.getStyleClass().add("download-modal-external-dependency-notice"); + HBox title = new HBox(7, LauncherIcons.icon(LauncherIcons.Glyph.ALERT_CIRCLE, 14), new Label("This modpack uses external mods")); + title.getStyleClass().add("download-modal-external-dependency-title"); + title.setAlignment(Pos.CENTER_LEFT); + Label copy = new Label("%s %s from outside Modtale. Check the linked source pages if the download or install flow asks for them separately.".formatted( + externalDependencyNames(external), + external.size() == 1 ? "comes" : "come" + )); + copy.getStyleClass().add("download-modal-external-dependency-copy"); + copy.setWrapText(true); + notice.getChildren().addAll(title, copy); + return notice; + } + + private String externalDependencyNames(List dependencies) { + List names = dependencies.stream() + .map(this::dependencyTitle) + .filter(name -> !isBlank(name)) + .limit(3) + .toList(); + int remaining = dependencies.size() - names.size(); + return String.join(", ", names) + (remaining > 0 ? ", +" + remaining + " more" : ""); + } + + private List externalDependencies(ProjectVersion version) { + if (version == null || version.dependencies() == null) { + return List.of(); + } + return version.dependencies().stream() + .filter(dependency -> dependency != null && dependency.isExternal() && !dependency.isEmbedded()) + .toList(); + } + + private String dependencyTitle(ProjectDependency dependency) { + return firstNonBlank( + dependency.title(), + dependency.projectTitle(), + dependency.projectId(), + dependency.externalId(), + dependency.id(), + "Dependency" + ); + } + + private static String firstNonBlank(String... values) { + for (String candidate : values) { + if (!isBlank(candidate)) { + return candidate; + } + } + return ""; + } + + private static boolean isBlank(String value) { + return value == null || value.isBlank(); + } + + private static boolean sameProject(ProjectDetail left, ProjectDetail right) { + if (left == right) { + return true; + } + if (left == null || right == null) { + return false; + } + String leftId = value(left.id(), ""); + String rightId = value(right.id(), ""); + if (!leftId.isBlank() && !rightId.isBlank()) { + return leftId.equals(rightId); + } + return value(left.routeKey(), "").equals(value(right.routeKey(), "")); + } + + private Node emptyState() { + VBox empty = new VBox(10); + empty.getStyleClass().add("download-modal-empty"); + empty.setAlignment(Pos.CENTER); + empty.getChildren().addAll( + LauncherIcons.icon(LauncherIcons.Glyph.ALERT_CIRCLE, 30), + new Label("No compatible versions.") + ); + if (!effectiveShowExperimental() && !currentVersions().isEmpty()) { + Button show = new Button("Show experimental"); + show.getStyleClass().add("download-modal-show-experimental"); + show.setOnAction(event -> { + showExperimental = true; + rebuildOverlay(); + }); + empty.getChildren().add(show); + } + return empty; + } + + private HBox footer() { + HBox footer = new HBox(); + footer.getStyleClass().add("download-modal-footer"); + footer.setAlignment(Pos.CENTER); + Button history = new Button("VIEW FULL CHANGELOG", LauncherIcons.icon(LauncherIcons.Glyph.CHEVRON_RIGHT, 13)); + history.getStyleClass().add("download-modal-history"); + history.setContentDisplay(javafx.scene.control.ContentDisplay.RIGHT); + history.setOnAction(event -> { + ProjectDetail selectedProject = project; + hide(); + viewHistory.accept(selectedProject); + }); + footer.getChildren().add(history); + return footer; + } + + private void install(VersionEntry entry) { + ProjectDetail selectedProject = project; + ProjectVersion version = entry.version(); + String gameVersion = entry.gameVersion(); + hide(); + install.accept(new DownloadSelection(selectedProject, version, gameVersion, null)); + } + + private List gameVersions() { + Map> byGame = versionsByGame(); + Set preRelease = preReleaseGameVersionSet(); + boolean effectivePreRelease = effectiveShowPreReleaseGameVersions(); + return orderedGameVersions().stream() + .filter(byGame::containsKey) + .filter(version -> effectivePreRelease || !preRelease.contains(version)) + .toList(); + } + + private List activeSelectedGameVersions() { + return selectedGameVersions.isEmpty() ? gameVersions() : selectedGameVersions; + } + + private List selectedVersionEntries() { + Map entries = new LinkedHashMap<>(); + Map> byGame = versionsByGame(); + for (String gameVersion : activeSelectedGameVersions()) { + for (ProjectVersion version : byGame.getOrDefault(gameVersion, List.of())) { + entries.putIfAbsent(versionKey(version), new VersionEntry(version, gameVersion)); + } + } + return List.copyOf(entries.values()); + } + + private List currentVersions() { + return selectedVersionEntries().stream() + .map(VersionEntry::version) + .toList(); + } + + private List sortedVisibleVersions() { + boolean effectiveExperimental = effectiveShowExperimental(); + return selectedVersionEntries().stream() + .filter(entry -> effectiveExperimental || isRelease(entry.version().channel())) + .sorted(versionEntryComparator()) + .toList(); + } + + private List preferredVisibleGameVersions() { + List versions = gameVersions(); + String preferred = preferredGameVersion.get(); + if (preferred != null && versions.contains(preferred)) { + return List.of(preferred); + } + if (!selectedGameVersions.isEmpty()) { + List validSelections = selectedGameVersions.stream() + .filter(versions::contains) + .toList(); + if (!validSelections.isEmpty()) { + return validSelections; + } + } + List groups = GameVersionGroups.build(versions); + return groups.isEmpty() ? List.of() : groups.getFirst().versions(); + } + + private Map> versionsByGame() { + Map> grouped = new LinkedHashMap<>(); + for (String gameVersion : orderedGameVersions()) { + grouped.put(gameVersion, new ArrayList<>()); + } + for (ProjectVersion version : project.versions()) { + List gameVersions = version.gameVersions().isEmpty() + ? List.of(value(preferredGameVersion.get(), "")) + : version.gameVersions(); + for (String gameVersion : gameVersions) { + if (gameVersion == null || gameVersion.isBlank()) { + continue; + } + grouped.computeIfAbsent(gameVersion, ignored -> new ArrayList<>()).add(version); + } + } + grouped.entrySet().removeIf(entry -> entry.getValue().isEmpty()); + return grouped; + } + + private List orderedGameVersions() { + LinkedHashSet ordered = new LinkedHashSet<>(); + if (catalog != null) { + ordered.addAll(catalog.allVersions()); + if (ordered.isEmpty()) { + ordered.addAll(catalog.releaseVersions()); + ordered.addAll(catalog.preReleaseVersions()); + } + } + project.versions().stream() + .flatMap(version -> version.gameVersions().stream()) + .filter(version -> version != null && !version.isBlank()) + .sorted((left, right) -> compareSemver(right, left)) + .forEach(ordered::add); + return List.copyOf(ordered); + } + + private Set preReleaseGameVersionSet() { + return catalog == null ? Set.of() : Set.copyOf(catalog.preReleaseVersions()); + } + + private boolean effectiveShowPreReleaseGameVersions() { + return showPreReleaseGameVersions || forceShowPreReleaseGameVersions(); + } + + private boolean forceShowPreReleaseGameVersions() { + Map> byGame = versionsByGame(); + Set preRelease = preReleaseGameVersionSet(); + boolean hasPreRelease = byGame.keySet().stream().anyMatch(preRelease::contains); + boolean hasRelease = byGame.keySet().stream().anyMatch(version -> !preRelease.contains(version)); + return hasPreRelease && !hasRelease; + } + + private boolean showPreReleaseToggle() { + Map> byGame = versionsByGame(); + Set preRelease = preReleaseGameVersionSet(); + boolean hasPreRelease = byGame.keySet().stream().anyMatch(preRelease::contains); + boolean hasRelease = byGame.keySet().stream().anyMatch(version -> !preRelease.contains(version)); + return hasPreRelease && hasRelease; + } + + private boolean effectiveShowExperimental() { + List versions = currentVersions(); + boolean hasRelease = versions.stream().anyMatch(version -> isRelease(version.channel())); + boolean hasExperimental = versions.stream().anyMatch(version -> !isRelease(version.channel())); + return showExperimental || (hasExperimental && !hasRelease); + } + + private boolean showAlphaBetaToggle() { + boolean hasExperimental = project.versions().stream().anyMatch(version -> !isRelease(version.channel())); + boolean hasRelease = project.versions().stream().anyMatch(version -> isRelease(version.channel())); + return hasExperimental && hasRelease; + } + + private boolean shouldShowEntryGameVersion() { + return activeSelectedGameVersions().size() > 1; + } + + private String selectedGameVersionLabel() { + return GameVersionGroups.displayLabel(selectedGameVersions, gameVersions(), "any version"); + } + + private List otherCompatibleVersions(ProjectVersion version, String selectedGameVersion) { + return version.gameVersions().stream() + .filter(gameVersion -> !gameVersion.equals(selectedGameVersion)) + .toList(); + } + + private static boolean isRelease(String channel) { + return channel == null || channel.isBlank() || "RELEASE".equalsIgnoreCase(channel); + } + + private static String channelStyle(String channel) { + if ("ALPHA".equalsIgnoreCase(channel)) { + return "alpha"; + } + if ("BETA".equalsIgnoreCase(channel)) { + return "beta"; + } + return "release"; + } + + private static Comparator versionComparator() { + return (left, right) -> { + int date = compareReleaseDate(right.releaseDate(), left.releaseDate()); + if (date != 0) { + return date; + } + return compareSemver(right.versionNumber(), left.versionNumber()); + }; + } + + private static Comparator versionEntryComparator() { + return (left, right) -> versionComparator().compare(left.version(), right.version()); + } + + private static String versionKey(ProjectVersion version) { + return firstNonBlank( + version.id(), + value(version.versionNumber(), "unknown") + "-" + value(version.fileUrl(), "") + "-" + value(version.releaseDate(), "") + ); + } + + private static int compareReleaseDate(String left, String right) { + Instant leftInstant = parseInstant(left); + Instant rightInstant = parseInstant(right); + if (leftInstant == null && rightInstant == null) { + return 0; + } + if (leftInstant == null) { + return -1; + } + if (rightInstant == null) { + return 1; + } + return leftInstant.compareTo(rightInstant); + } + + private static Instant parseInstant(String value) { + if (value == null || value.isBlank()) { + return null; + } + try { + return Instant.parse(value); + } catch (DateTimeParseException ignored) { + return null; + } + } + + private static int compareSemver(String left, String right) { + List leftParts = semverParts(left); + List rightParts = semverParts(right); + int length = Math.max(leftParts.size(), rightParts.size()); + for (int i = 0; i < length; i++) { + int leftPart = i < leftParts.size() ? leftParts.get(i) : 0; + int rightPart = i < rightParts.size() ? rightParts.get(i) : 0; + int comparison = Integer.compare(leftPart, rightPart); + if (comparison != 0) { + return comparison; + } + } + return value(left, "").compareToIgnoreCase(value(right, "")); + } + + private static List semverParts(String value) { + if (value == null || value.isBlank()) { + return List.of(); + } + List parts = new ArrayList<>(); + for (String part : value.split("[^0-9]+")) { + if (part.isBlank()) { + continue; + } + try { + parts.add(Integer.parseInt(part)); + } catch (NumberFormatException ignored) { + parts.add(0); + } + } + return parts; + } + + record DownloadSelection( + ProjectDetail project, + ProjectVersion version, + String gameVersion, + List selectedDependencies + ) { + } + + private record VersionEntry(ProjectVersion version, String gameVersion) { + } +} diff --git a/launcher/src/main/java/net/modtale/launcher/ui/project/NativeGalleryCarousel.java b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeGalleryCarousel.java new file mode 100644 index 00000000..6e639ad3 --- /dev/null +++ b/launcher/src/main/java/net/modtale/launcher/ui/project/NativeGalleryCarousel.java @@ -0,0 +1,428 @@ +package net.modtale.launcher.ui.project; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.function.Consumer; +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.css.PseudoClass; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.shape.Rectangle; +import javafx.scene.transform.Scale; +import javafx.util.Duration; +import net.modtale.launcher.ui.common.CachedImageLoader; +import net.modtale.launcher.ui.common.LauncherIcons; + +final class NativeGalleryCarousel { + + private static final double MEDIA_ASPECT_RATIO = 16.0 / 9.0; + private static final double MODAL_REQUESTED_WIDTH = 1800; + private static final double MODAL_REQUESTED_HEIGHT = 1100; + private static final double INLINE_REQUESTED_WIDTH = 1200; + private static final double INLINE_REQUESTED_HEIGHT = 720; + private static final double THUMBNAIL_WIDTH = 144; + private static final double THUMBNAIL_HEIGHT = 80; + private static final double THUMBNAIL_REQUESTED_WIDTH = 256; + private static final double THUMBNAIL_REQUESTED_HEIGHT = 144; + private static final Duration AUTO_ADVANCE_DURATION = Duration.seconds(8); + private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected"); + private static final String THUMBNAIL_LOADED_PROPERTY = NativeGalleryCarousel.class.getName() + ".thumbnailLoaded"; + + enum Variant { + MODAL, + INLINE + } + + private final CachedImageLoader imageLoader; + private final Consumer openUrl; + + NativeGalleryCarousel(CachedImageLoader imageLoader, Consumer openUrl) { + this.imageLoader = imageLoader; + this.openUrl = openUrl; + } + + Node render(List images, int initialIndex, Variant variant) { + return new CarouselView(images, initialIndex, variant).root(); + } + + private final class CarouselView { + private final List images; + private final Variant variant; + private final VBox root = new VBox(0); + private final StackPane media = new FixedAspectPane(MEDIA_ASPECT_RATIO); + private final ImageView image = new ImageView(); + private final Button previous = arrow(LauncherIcons.Glyph.CHEVRON_LEFT, "Previous image"); + private final Button next = arrow(LauncherIcons.Glyph.CHEVRON_RIGHT, "Next image"); + private final Label caption = new Label(); + private final HBox thumbnails = new HBox(12); + private final ScrollPane thumbnailScroller = new ScrollPane(thumbnails); + private final Region progressFill = new Region(); + private final Scale progressScale = new Scale(0, 1, 0, 0); + private final List thumbnailViews = new ArrayList<>(); + private final List
    )} -
    +
    -
    -
    +
    +

    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