Conversation
There was a problem hiding this comment.
Pull request overview
Adds support for creating/installing a game instance by dragging a Minecraft version-manifest-style JSON into the launcher, addressing feature request #5459 (install unlisted/ancient/third-party versions without manual folder setup).
Changes:
- Add i18n strings for “malformed instance JSON”.
- Add
Versions.installFromJson(Profile, Path)to parse a version JSON, write it into<gameDir>/versions/<id>/<id>.json, and trigger game jar download. - Extend drag-and-drop handlers (Root page + Game list page) to accept JSON files and invoke the new installer.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | Adds zh_CN error message for invalid instance JSON. |
| HMCL/src/main/resources/assets/lang/I18N_zh.properties | Adds zh_TW error message for invalid instance JSON. |
| HMCL/src/main/resources/assets/lang/I18N.properties | Adds English error message for invalid instance JSON. |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java | Implements JSON-based instance installation + download flow. |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java | Allows dragging .json into main page to trigger install. |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java | Allows dragging files into game list page to trigger install. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| FXUtils.applyDragListener(gameListPage, ModpackHelper::isFileModpackByExtension, modpacks -> { | ||
| Path modpack = modpacks.get(0); | ||
| Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack")); | ||
| FXUtils.applyDragListener(gameListPage, file -> ModpackHelper.isFileModpackByExtension(file) || "json".equalsIgnoreCase(FileUtils.getNameWithoutExtension(file)), files -> { |
| profile.getRepository().refreshVersions(); | ||
| profile.setSelectedVersion(result); | ||
| handler.resolve(); |
| }); | ||
| Task.runAsync(() -> { | ||
| var dir = profile.getGameDir().resolve("versions"); | ||
| var versionDir = Files.createDirectory(dir.resolve(result)); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| handler.resolve(); | ||
| } | ||
| }); | ||
| Task.runAsync(() -> { |
There was a problem hiding this comment.
Pull request overview
This PR adds support for installing a Minecraft instance by dragging a client/version JSON file into the launcher UI (resolving #5459), integrating the flow into existing drag-and-drop entry points and adding the needed i18n strings.
Changes:
- Add a new
Versions.installFromJson(Profile, Path)flow that parses a version JSON, prompts for a target instance name, downloads required game components, and saves the instance. - Extend drag-and-drop handlers on main UI pages to accept
.jsonfiles and trigger JSON-based installation. - Add new localized strings for “malformed JSON” errors across
I18N.propertiesvariants.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| HMCL/src/main/resources/assets/lang/I18N.properties | Adds English error string for invalid instance JSON. |
| HMCL/src/main/resources/assets/lang/I18N_zh.properties | Adds Traditional Chinese error string for invalid instance JSON. |
| HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | Adds Simplified Chinese error string for invalid instance JSON. |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java | Introduces installFromJson implementation and wires it into the install task pipeline. |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java | Extends main page drag-and-drop to accept JSON and call installFromJson. |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java | Extends game list page drag-and-drop to accept JSON and call installFromJson (but currently has a filter bug). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| FXUtils.applyDragListener(gameListPage, ModpackHelper::isFileModpackByExtension, modpacks -> { | ||
| Path modpack = modpacks.get(0); | ||
| Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack")); | ||
| FXUtils.applyDragListener(gameListPage, file -> ModpackHelper.isFileModpackByExtension(file) || "json".equalsIgnoreCase(FileUtils.getNameWithoutExtension(file)), files -> { |
There was a problem hiding this comment.
Drag-and-drop filter for the GameListPage checks "json".equalsIgnoreCase(FileUtils.getNameWithoutExtension(file)), which will never match normal files like something.json (nameWithoutExtension would be something). As a result, JSON files won’t be accepted for drag/drop here even though the handler supports them. Use FileUtils.getExtension(file) (consistent with the handler) to detect JSON files.
| FXUtils.applyDragListener(gameListPage, file -> ModpackHelper.isFileModpackByExtension(file) || "json".equalsIgnoreCase(FileUtils.getNameWithoutExtension(file)), files -> { | |
| FXUtils.applyDragListener(gameListPage, file -> ModpackHelper.isFileModpackByExtension(file) || "json".equalsIgnoreCase(FileUtils.getExtension(file)), files -> { |
| Version newVersion = version.setId(result).setJar(result); | ||
|
|
There was a problem hiding this comment.
installFromJson renames the parsed version by doing version.setId(result).setJar(result). For version JSONs that use inheritsFrom (common in modded/third-party manifests) or that omit explicit downloads.client.url, forcing jar to the new instance id can override the parent jar selection and/or cause the default download URL to be computed from the renamed id, breaking jar resolution/download. Prefer preserving the original jar semantics (and only normalizing away the “jar == old id” case) rather than always setting jar to the new id.
| Version newVersion = version.setId(result).setJar(result); | |
| String oldId = version.getId(); | |
| String oldJar = version.getJar(); | |
| Version newVersion = version.setId(result); | |
| if (oldJar == null || oldJar.equals(oldId)) { | |
| newVersion = newVersion.setJar(result); | |
| } |
resolves #5459