Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,15 @@ public StringProperty defaultAddonSourceProperty() {
return defaultAddonSource;
}

/// Whether to update addons to preview versions
@SerializedName("updateAddonsToPreview")
private final BooleanProperty updateAddonsToPreview = new SimpleBooleanProperty(true);

/// Returns whether to update addons to preview versions property.
public BooleanProperty updateAddonsToPreviewProperty() {
return updateAddonsToPreview;
}

/// Whether proxy authentication is enabled.
@SerializedName("hasProxyAuth")
private final BooleanProperty hasProxyAuth = new SimpleBooleanProperty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.addon.LocalAddonFile;
import org.jackhuang.hmcl.addon.RemoteAddon;
import org.jackhuang.hmcl.setting.SettingsManager;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;

Expand All @@ -30,19 +31,17 @@

import static org.jackhuang.hmcl.util.logging.Logger.LOG;

public class AddonCheckUpdatesTask<T extends LocalAddonFile> extends Task<List<LocalAddonFile.AddonUpdate>> {
private final DownloadProvider downloadProvider;
public class AddonCheckUpdatesTask extends Task<List<LocalAddonFile.AddonUpdate>> {
private final List<Task<LocalAddonFile.AddonUpdate>> dependents;

public AddonCheckUpdatesTask(DownloadProvider downloadProvider, String gameVersion, Collection<T> addons) {
this.downloadProvider = downloadProvider;
public AddonCheckUpdatesTask(DownloadProvider downloadProvider, String gameVersion, Collection<? extends LocalAddonFile> addons) {
dependents = addons.stream().map(addon ->
Task.supplyAsync(Schedulers.io(), () -> {
LocalAddonFile.AddonUpdate candidate = null;
for (RemoteAddon.Source source : RemoteAddon.Source.values()) {
LocalAddonFile.AddonUpdate update = null;
try {
update = addon.checkUpdates(downloadProvider, gameVersion, source);
update = addon.checkUpdates(downloadProvider, gameVersion, source, SettingsManager.settings().updateAddonsToPreviewProperty().get());
} catch (IOException e) {
LOG.warning(String.format("Cannot check update for addon %s.", addon.getFileName()), e);
}
Expand All @@ -55,6 +54,7 @@ public AddonCheckUpdatesTask(DownloadProvider downloadProvider, String gameVersi
}
}

if (candidate != null && candidate.targetVersion().equals(candidate.currentVersion())) return null;
return candidate;
}).setName(addon.getFileName()).setSignificance(TaskSignificance.MAJOR).withCounter("update.checking")
).toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ public AddonUpdatesPage(LocalAddonManager<F> localAddonManager, List<LocalAddonF
targetVersionColumn.setPrefWidth(200);
setupCellValueFactory(targetVersionColumn, AddonUpdateObject::targetVersionProperty);

TableColumn<AddonUpdateObject, String> targetVersionTypeColumn = new TableColumn<>(i18n("addon.version_type"));
setupCellValueFactory(targetVersionTypeColumn, AddonUpdateObject::targetVersionTypeProperty);

TableColumn<AddonUpdateObject, String> sourceColumn = new TableColumn<>(i18n("addon.check_update.source"));
setupCellValueFactory(sourceColumn, AddonUpdateObject::sourceProperty);

Expand All @@ -102,7 +105,7 @@ public AddonUpdatesPage(LocalAddonManager<F> localAddonManager, List<LocalAddonF

TableView<AddonUpdateObject> table = new TableView<>(objects);
table.setEditable(true);
table.getColumns().setAll(enabledColumn, fileNameColumn, currentVersionColumn, targetVersionColumn, sourceColumn);
table.getColumns().setAll(enabledColumn, fileNameColumn, currentVersionColumn, targetVersionColumn, targetVersionTypeColumn, sourceColumn);
setMargin(table, new Insets(10, 10, 5, 10));

setCenter(table);
Expand Down Expand Up @@ -197,6 +200,7 @@ private static final class AddonUpdateObject {
final StringProperty fileName = new SimpleStringProperty();
final StringProperty currentVersion = new SimpleStringProperty();
final StringProperty targetVersion = new SimpleStringProperty();
final StringProperty targetVersionType = new SimpleStringProperty();
final StringProperty source = new SimpleStringProperty();

public AddonUpdateObject(LocalAddonFile.AddonUpdate data) {
Expand All @@ -206,13 +210,11 @@ public AddonUpdateObject(LocalAddonFile.AddonUpdate data) {
fileName.set(data.localAddonFile().getFileName());
currentVersion.set(data.currentVersion().version());
targetVersion.set(data.targetVersion().version());
switch (data.currentVersion().self().getSource()) {
case CURSEFORGE:
source.set(i18n("addon.curseforge"));
break;
case MODRINTH:
source.set(i18n("addon.modrinth"));
}
targetVersionType.set(data.targetVersion().versionType().name());
source.set(switch (data.currentVersion().source()) {
case CURSEFORGE -> i18n("addon.curseforge");
case MODRINTH -> i18n("addon.modrinth");
});
}

public LocalAddonFile.AddonUpdate getData() {
Expand All @@ -227,57 +229,26 @@ public BooleanProperty enabledProperty() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled.set(enabled);
}

public String getFileName() {
return fileName.get();
}

public StringProperty fileNameProperty() {
return fileName;
}

public void setFileName(String fileName) {
this.fileName.set(fileName);
}

public String getCurrentVersion() {
return currentVersion.get();
}

public StringProperty currentVersionProperty() {
return currentVersion;
}

public void setCurrentVersion(String currentVersion) {
this.currentVersion.set(currentVersion);
}

public String getTargetVersion() {
return targetVersion.get();
}

public StringProperty targetVersionProperty() {
return targetVersion;
}

public void setTargetVersion(String targetVersion) {
this.targetVersion.set(targetVersion);
}

public String getSource() {
return source.get();
public StringProperty targetVersionTypeProperty() {
return targetVersionType;
}

public StringProperty sourceProperty() {
return source;
}

public void setSource(String source) {
this.source.set(source);
}
}

public static class AddonUpdateTask extends Task<Void> {
Expand All @@ -293,35 +264,30 @@ public static class AddonUpdateTask extends Task<Void> {
LocalAddonFile local = addon.localAddonFile();
RemoteAddon.Version remote = addon.targetVersion();
boolean isDisabled = local.isDisabled();
String originalFileName = local.getFile().getFileName().toString();
String fileName = remote.file().filename();
Comment thread
ToobLac marked this conversation as resolved.
if (isDisabled)
fileName = StringUtils.addSuffix(fileName, LocalAddonManager.DISABLED_EXTENSION);
String newFileName = fileName;

dependents.add(Task
.runAsync(Schedulers.javafx(), () -> local.setOld(true))
.thenComposeAsync(() -> {
String fileName = addon.useRemoteFileName() ? remote.file().filename() : originalFileName;
if (isDisabled)
fileName = StringUtils.addSuffix(fileName, LocalAddonManager.DISABLED_EXTENSION);

var task = new FileDownloadTask(
remote.file().url(),
addonDirectory.resolve(fileName)
);

task.setName(remote.name());
return task;
})
.whenComplete(Schedulers.javafx(), exception -> {
.thenComposeAsync(() ->
new FileDownloadTask(remote.file().url(), addonDirectory.resolve(newFileName)).setName(remote.name())
).whenComplete(Schedulers.javafx(), exception -> {
if (exception != null) {
// restore state if failed
local.setOld(false);
if (isDisabled)
local.markDisabled();
failedAddons.add(local);
} else if (!local.keepOldFiles()) {
try {
local.delete();
} catch (IOException e) {
LOG.warning("Failed to delete outdated addon: " + local.getFile(), e);
} else {
local.onUpdated(newFileName);
if (!local.keepOldFiles()) {
try {
local.delete();
} catch (IOException e) {
LOG.warning("Failed to delete outdated addon: " + local.getFile(), e);
}
}
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,18 @@ public void checkUpdates(Collection<LocalModFile> mods) {
Runnable action = () -> Controllers.taskDialog(Task
.composeAsync(() -> {
Optional<String> gameVersion = repository.getGameVersion(instanceId);
return gameVersion.map(g -> new AddonCheckUpdatesTask<>(DownloadProviders.getDownloadProvider(), g, mods)).orElse(null);
if (gameVersion.isPresent()) {
return new AddonCheckUpdatesTask(DownloadProviders.getDownloadProvider(), gameVersion.get(), mods);
} else {
LOG.warning("Failed to check for updates, due to unable to get instance game version");
return null;
}
})
.whenComplete(Schedulers.javafx(), (result, exception) -> {
if (exception instanceof CancellationException) return;
if (exception != null || result == null) {
Controllers.dialog(i18n("addon.check_update.failed_check"), i18n("message.failed"), MessageDialogPane.MessageType.ERROR);
if (exception != null) LOG.warning("Failed to check for updates", exception);
} else if (result.isEmpty()) {
Controllers.dialog(i18n("addon.check_update.empty"));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public void checkUpdates(Collection<ResourcePackFile> resourcePacks) {
Runnable action = () -> Controllers.taskDialog(Task
.composeAsync(() -> {
Optional<String> gameVersion = repository.getGameVersion(instanceId);
return gameVersion.map(g -> new AddonCheckUpdatesTask<>(DownloadProviders.getDownloadProvider(), g, resourcePacks)).orElse(null);
return gameVersion.map(g -> new AddonCheckUpdatesTask(DownloadProviders.getDownloadProvider(), g, resourcePacks)).orElse(null);
})
.whenComplete(Schedulers.javafx(), (result, exception) -> {
if (exception != null || result == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ public DownloadSettingsPage() {
getChildren().setAll(scrollPane);

{
var downloadSource = new ComponentList();
downloadSource.getStyleClass().add("card-non-transparent");
var gameContent = new ComponentList();
gameContent.getStyleClass().add("card-non-transparent");
{
Function<DownloadSource, String> converter = source -> switch (source) {
case DEFAULT -> i18n("settings.launcher.download_source.auto");
Expand Down Expand Up @@ -102,10 +102,14 @@ public DownloadSettingsPage() {
defaultAddonSourcePane.setItems("modrinth", "curseforge");
defaultAddonSourcePane.valueProperty().bindBidirectional(settings().defaultAddonSourceProperty());

downloadSource.getContent().setAll(versionListSourcePane, downloadSourcePane, defaultAddonSourcePane);
var updateAddonsToPreviewButton = new LineToggleButton();
updateAddonsToPreviewButton.setTitle(i18n("settings.launcher.update_addons_to_preview"));
updateAddonsToPreviewButton.selectedProperty().bindBidirectional(settings().updateAddonsToPreviewProperty());

gameContent.getContent().setAll(versionListSourcePane, downloadSourcePane, defaultAddonSourcePane, updateAddonsToPreviewButton);
}

content.getChildren().addAll(ComponentList.createComponentListTitle(i18n("settings.launcher.download_source")), downloadSource);
content.getChildren().addAll(ComponentList.createComponentListTitle(i18n("settings.launcher.game_content")), gameContent);
}

{
Expand Down
3 changes: 3 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N.properties
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ addon.dependency.broken=Broken Dependencies (This addon existed before, but it d
addon.download.title.release=Minecraft %s
addon.download.title.snapshot=Minecraft %s (Snapshots)
addon.modrinth=Modrinth
addon.version_type=Type

archive.author=Author(s)
archive.date=Publish Date
Expand Down Expand Up @@ -1623,6 +1624,7 @@ settings.launcher.font.anti_aliasing.auto=Auto
settings.launcher.font.anti_aliasing.gray=Grayscale
settings.launcher.font.anti_aliasing.lcd=Sub-pixel
settings.launcher.fonts=Fonts
settings.launcher.game_content=Game Content
settings.launcher.general=General
settings.launcher.language=Language
settings.launcher.launcher_log.export=Export Launcher Logs
Expand Down Expand Up @@ -1669,6 +1671,7 @@ settings.launcher.theme_color_type.default=Default
settings.launcher.theme_color_type.system=Follow System
settings.launcher.title_transparent=Transparent Titlebar
settings.launcher.turn_off_animations=Disable Animation
settings.launcher.update_addons_to_preview=Update Addons to Alpha/Beta Versions
settings.launcher.version_list_source=Version List
settings.launcher.window_transparent=Transparent Window
settings.launcher.background.settings.opacity=Opacity
Expand Down
3 changes: 3 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ addon.dependency.broken=損壞的相依內容 (該相依內容曾經存在於附
addon.download.title.release=Minecraft %s
addon.download.title.snapshot=Minecraft %s (快照)
addon.modrinth=Modrinth
addon.version_type=版本類型

archive.author=作者
archive.date=發布日期
Expand Down Expand Up @@ -1424,6 +1425,7 @@ settings.launcher.font.anti_aliasing.auto=自動
settings.launcher.font.anti_aliasing.gray=灰階
settings.launcher.font.anti_aliasing.lcd=子像素
settings.launcher.fonts=字體
settings.launcher.game_content=遊戲內容
settings.launcher.general=一般
settings.launcher.language=語言
settings.launcher.launcher_log.export=匯出啟動器日誌
Expand Down Expand Up @@ -1470,6 +1472,7 @@ settings.launcher.theme_color_type.default=預設
settings.launcher.theme_color_type.system=跟隨系統
settings.launcher.title_transparent=標題欄透明
settings.launcher.turn_off_animations=關閉動畫
settings.launcher.update_addons_to_preview=更新附加內容到 Alpha/Beta 版本
settings.launcher.version_list_source=版本清單來源
settings.launcher.window_transparent=視窗透明
settings.launcher.background.settings.opacity=不透明度
Expand Down
3 changes: 3 additions & 0 deletions HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ addon.dependency.broken=损坏的前置内容 (该前置内容曾经在该附加
addon.download.title.release=Minecraft %s
addon.download.title.snapshot=Minecraft %s (快照)
addon.modrinth=Modrinth
addon.version_type=版本类型

archive.author=作者
archive.date=发布日期
Expand Down Expand Up @@ -1424,6 +1425,7 @@ settings.launcher.font.anti_aliasing.auto=自动
settings.launcher.font.anti_aliasing.gray=灰度
settings.launcher.font.anti_aliasing.lcd=子像素
settings.launcher.fonts=字体
settings.launcher.game_content=游戏内容
settings.launcher.general=通用
settings.launcher.language=语言
settings.launcher.launcher_log.export=导出启动器日志
Expand Down Expand Up @@ -1470,6 +1472,7 @@ settings.launcher.theme_color_type.default=默认
settings.launcher.theme_color_type.system=跟随系统
settings.launcher.title_transparent=标题栏透明
settings.launcher.turn_off_animations=关闭动画
settings.launcher.update_addons_to_preview=更新附加内容到测试版本
settings.launcher.version_list_source=版本列表源
settings.launcher.window_transparent=窗口透明
settings.launcher.background.settings.opacity=不透明度
Expand Down
Loading