Compare commits

..
24 changed files with 89 additions and 76 deletions

No files matched your search

+6 -5
View File
@@ -11,8 +11,9 @@ concurrency:
jobs:
mirror:
strategy:
fail-fast: false
matrix:
target:
include:
- name: Gitee
repo: gitee.com/huanghongxun/HMCL
user: 'hmcl-sync'
@@ -21,12 +22,12 @@ jobs:
repo: cnb.cool/HMCL-dev/HMCL
user: 'cnb'
token: 'CNB_SYNC_TOKEN'
name: Mirror to ${{ matrix.target.name }}
name: Mirror to ${{ matrix.name }}
if: ${{ github.repository == 'HMCL-dev/HMCL' }}
runs-on: ubuntu-latest
steps:
- name: Mirror GitHub to ${{ matrix.target.name }}
- name: Mirror GitHub to ${{ matrix.name }}
run: |
git clone --mirror "https://github.com/$GITHUB_REPOSITORY.git" -- repo
git clone --mirror "https://github.com/${{ github.repository }}.git" -- repo
cd repo
git push -f --prune "https://${{ matrix.target.user }}:${{ secrets[matrix.target.token] }}@${{ matrix.target.repo }}.git" "refs/heads/*:refs/heads/*" "refs/tags/*:refs/tags/*"
git push -f --prune "https://${{ matrix.user }}:${{ secrets[matrix.token] }}@${{ matrix.repo }}.git" "refs/heads/*:refs/heads/*" "refs/tags/*:refs/tags/*"
@@ -39,10 +39,7 @@ public class JFXListViewSkin<T> extends ListViewSkin<T> {
flow = (VirtualFlow<ListCell<T>>) getChildren().get(0);
JFXDepthManager.setDepth(flow, listView.depthProperty().get());
listView.depthProperty().addListener((o, oldVal, newVal) -> JFXDepthManager.setDepth(flow, newVal));
if (!Boolean.TRUE.equals(listView.getProperties().get("no-smooth-scrolling"))) {
FXUtils.smoothScrolling(flow);
}
FXUtils.smoothScrolling(flow);
}
@Override
@@ -204,7 +204,6 @@ public final class LogWindow extends Stage {
LogWindowImpl() {
getStyleClass().add("log-window");
listView.getProperties().put("no-smooth-scrolling", true);
listView.setItems(FXCollections.observableList(new CircularArrayList<>(logs.size())));
for (int i = 0; i < LEVELS.length; i++) {
@@ -25,6 +25,7 @@ import javafx.animation.Animation.Status;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.EventHandler;
import javafx.scene.control.IndexedCell;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.skin.VirtualFlow;
import javafx.scene.input.MouseEvent;
@@ -225,6 +226,7 @@ final class ScrollUtils {
final double[] derivatives = new double[FRICTIONS.length];
Timeline timeline = new Timeline();
Holder<ScrollDirection> scrollDirectionHolder = new Holder<>();
final EventHandler<MouseEvent> mouseHandler = event -> timeline.stop();
final EventHandler<ScrollEvent> scrollHandler = event -> {
if (event.getEventType() == ScrollEvent.SCROLL) {
@@ -232,6 +234,7 @@ final class ScrollUtils {
if (scrollDirection == ScrollDirection.LEFT || scrollDirection == ScrollDirection.RIGHT) {
return;
}
scrollDirectionHolder.value = scrollDirection;
double currentSpeed = isTrackPad(event, scrollDirection) ? speed / trackPadAdjustment : speed;
derivatives[0] += scrollDirection.intDirection * currentSpeed;
@@ -253,7 +256,15 @@ final class ScrollUtils {
}
double dy = derivatives[derivatives.length - 1];
virtualFlow.scrollPixels(dy);
int cellCount = virtualFlow.getCellCount();
IndexedCell<?> firstVisibleCell = virtualFlow.getFirstVisibleCell();
double height = firstVisibleCell != null ? firstVisibleCell.getHeight() * cellCount : 0.0;
double delta = height > 0.0
? dy / height
: (scrollDirectionHolder.value == ScrollDirection.DOWN ? 0.001 : -0.001);
virtualFlow.setPosition(Math.min(Math.max(virtualFlow.getPosition() + delta, 0), 1));
if (Math.abs(dy) < 0.001) {
timeline.stop();
@@ -30,7 +30,7 @@ import java.util.concurrent.CompletableFuture;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class InputDialogPane extends JFXDialogLayout {
public class InputDialogPane extends JFXDialogLayout implements DialogAware {
private final CompletableFuture<String> future = new CompletableFuture<>();
private final JFXTextField textField;
@@ -70,9 +70,15 @@ public class InputDialogPane extends JFXDialogLayout {
});
});
textField.setOnAction(event -> acceptButton.fire());
onEscPressed(this, cancelButton::fire);
}
@Override
public void onDialogShown() {
textField.requestFocus();
}
public CompletableFuture<String> getCompletableFuture() {
return future;
}
@@ -43,7 +43,6 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair;
@@ -93,9 +92,22 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
ModAdviser.ModSuggestion state = ModAdviser.ModSuggestion.SUGGESTED;
if (basePath.length() > "minecraft/".length()) {
state = adviser.advise(StringUtils.substringAfter(basePath, "minecraft/") + (isDirectory ? "/" : ""), isDirectory);
if (!isDirectory && Objects.equals(FileUtils.getNameWithoutExtension(file), version))
state = ModAdviser.ModSuggestion.HIDDEN;
if (isDirectory && Objects.equals(FileUtils.getName(file), version + "-natives")) // Ignore <version>-natives
String fileName = FileUtils.getName(file);
if (!isDirectory) {
switch (fileName) {
case ".DS_Store", // macOS system file
"desktop.ini", "Thumbs.db" // Windows system files
-> state = ModAdviser.ModSuggestion.HIDDEN;
}
if (fileName.startsWith("._")) // macOS system file
state = ModAdviser.ModSuggestion.HIDDEN;
if (FileUtils.getNameWithoutExtension(file).equals(version))
state = ModAdviser.ModSuggestion.HIDDEN;
}
if (isDirectory && fileName.equals(version + "-natives")) // Ignore <version>-natives
state = ModAdviser.ModSuggestion.HIDDEN;
if (state == ModAdviser.ModSuggestion.HIDDEN)
return null;
@@ -126,6 +126,7 @@ public class PersonalizationPage extends StackPane {
themeList.getContent().add(animationButton);
animationButton.selectedProperty().bindBidirectional(config().animationDisabledProperty());
animationButton.setTitle(i18n("settings.launcher.turn_off_animations"));
animationButton.setSubtitle(i18n("settings.take_effect_after_restart"));
}
content.getChildren().addAll(ComponentList.createComponentListTitle(i18n("settings.launcher.appearance")), themeList);
@@ -299,8 +300,12 @@ public class PersonalizationPage extends StackPane {
{
BorderPane fontAntiAliasingPane = new BorderPane();
{
Label left = new Label(i18n("settings.launcher.font.anti_aliasing"));
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
VBox left = new VBox();
Label title = new Label(i18n("settings.launcher.font.anti_aliasing"));
title.getStyleClass().add("title");
Label subtitle = new Label(i18n("settings.take_effect_after_restart"));
subtitle.getStyleClass().add("subtitle");
left.getChildren().setAll(title, subtitle);
fontAntiAliasingPane.setLeft(left);
}
@@ -254,8 +254,12 @@ public final class SettingsPage extends ScrollPane {
{
BorderPane languagePane = new BorderPane();
Label left = new Label(i18n("settings.launcher.language"));
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
VBox left = new VBox();
Label title = new Label(i18n("settings.launcher.language"));
title.getStyleClass().add("title");
Label subtitle = new Label(i18n("settings.take_effect_after_restart"));
subtitle.getStyleClass().add("subtitle");
left.getChildren().setAll(title, subtitle);
languagePane.setLeft(left);
SupportedLocale currentLocale = I18n.getLocale();
@@ -23,7 +23,6 @@ import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.ListChangeListener;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
@@ -93,9 +92,6 @@ final class ModListPageSkin extends SkinBase<ModListPage> {
// FXThread
private boolean isSearching = false;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private final ChangeListener<Boolean> holder;
ModListPageSkin(ModListPage skinnable) {
super(skinnable);
@@ -107,12 +103,6 @@ final class ModListPageSkin extends SkinBase<ModListPage> {
root.getStyleClass().add("no-padding");
listView = new JFXListView<>();
this.holder = FXUtils.onWeakChange(skinnable.loadingProperty(), loading -> {
if (!loading) {
listView.scrollTo(0);
}
});
{
toolbarPane = new TransitionPane();
@@ -1378,7 +1378,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.general=General
settings.launcher.language=Language (Applies After Restart)
settings.launcher.language=Language
settings.launcher.launcher_log.export=Export Launcher Logs
settings.launcher.launcher_log.export.failed=Failed to export logs.
settings.launcher.launcher_log.export.success=Logs have been exported to "%s".
@@ -1397,7 +1397,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=Username
settings.launcher.theme=Theme Color
settings.launcher.title_transparent=Transparent Titlebar
settings.launcher.turn_off_animations=Disable Animation (Applies After Restart)
settings.launcher.turn_off_animations=Disable Animation
settings.launcher.version_list_source=Version List
settings.launcher.background.settings.opacity=Opacity
@@ -1367,7 +1367,7 @@ settings.launcher.font.anti_aliasing.auto=تلقائي
settings.launcher.font.anti_aliasing.gray=تدرج رمادي
settings.launcher.font.anti_aliasing.lcd=Sub-pixel
settings.launcher.general=عام
settings.launcher.language=اللغة (يطبق بعد إعادة التشغيل)
settings.launcher.language=اللغة
settings.launcher.launcher_log.export=تصدير سجلات المشغل
settings.launcher.launcher_log.export.failed=فشل تصدير السجلات.
settings.launcher.launcher_log.export.success=تم تصدير السجلات إلى "%s".
@@ -1386,7 +1386,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=اسم المستخدم
settings.launcher.theme=السمة
settings.launcher.title_transparent=شريط العنوان الشفاف
settings.launcher.turn_off_animations=تعطيل الرسوم المتحركة (يطبق بعد إعادة التشغيل)
settings.launcher.turn_off_animations=تعطيل الرسوم المتحركة
settings.launcher.version_list_source=قائمة الإصدارات
settings.launcher.background.settings.opacity=الشفافية
@@ -1387,7 +1387,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=Nombre de usuario
settings.launcher.theme=Tema
settings.launcher.title_transparent=Barra de título transparente
settings.launcher.turn_off_animations=Desactivar animación (Se aplica después de reiniciar)
settings.launcher.turn_off_animations=Desactivar animación
settings.launcher.version_list_source=Lista de versiones
settings.launcher.background.settings.opacity=Opacidad
@@ -1152,7 +1152,7 @@ settings.launcher.download_source=引源
settings.launcher.download_source.auto=自擇所引源
settings.launcher.enable_game_list=見版列於主頁
settings.launcher.font=書體
settings.launcher.font.anti_aliasing=抗鋸 (復啟而效)
settings.launcher.font.anti_aliasing=抗鋸
settings.launcher.font.anti_aliasing.auto=自調
settings.launcher.font.anti_aliasing.gray=灰階
settings.launcher.font.anti_aliasing.lcd=子像素
@@ -1176,7 +1176,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=戶簿
settings.launcher.theme=主題
settings.launcher.title_transparent=通透題欄
settings.launcher.turn_off_animations=廢動效 (復啟而效)
settings.launcher.turn_off_animations=廢動效
settings.launcher.version_list_source=版列供者
settings.launcher.background.settings.opacity=陰翳
@@ -1360,7 +1360,7 @@ settings.launcher.font.anti_aliasing.auto=Автоматический
settings.launcher.font.anti_aliasing.gray=Оттенки серого
settings.launcher.font.anti_aliasing.lcd=Субпиксель
settings.launcher.general=Общие
settings.launcher.language=Язык (Применится после перезапуска)
settings.launcher.language=Язык
settings.launcher.launcher_log.export=Экспорт логов лаунчера
settings.launcher.launcher_log.export.failed=Не удалось экспортировать логи
settings.launcher.launcher_log.export.success=Логи экспортированы в %s
@@ -1379,7 +1379,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=Имя пользователя
settings.launcher.theme=Тема
settings.launcher.title_transparent=Прозрачная строка заголовка
settings.launcher.turn_off_animations=Отключить анимацию (Применится после перезапуска)
settings.launcher.turn_off_animations=Отключить анимацию
settings.launcher.version_list_source=Список версий
settings.launcher.background.settings.opacity=Непрозрачность
@@ -1302,7 +1302,7 @@ settings.launcher.font.anti_aliasing.auto=Авто
settings.launcher.font.anti_aliasing.gray=Відтінки сірого
settings.launcher.font.anti_aliasing.lcd=Субпіксельне
settings.launcher.general=Загальні
settings.launcher.language=Мова (Застосовується після перезавантаження)
settings.launcher.language=Мова
settings.launcher.launcher_log.export=Експортувати журнали лаунчера
settings.launcher.launcher_log.export.failed=Не вдалося експортувати журнали.
settings.launcher.launcher_log.export.success=Журнали було експортовано до "%s".
@@ -1321,7 +1321,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=Ім'я користувача
settings.launcher.theme=Тема
settings.launcher.title_transparent=Прозорий заголовок
settings.launcher.turn_off_animations=Вимкнути анімацію (Застосовується після перезавантаження)
settings.launcher.turn_off_animations=Вимкнути анімацію
settings.launcher.version_list_source=Список версій
settings.launcher.background.settings.opacity=Непрозорість
@@ -1161,12 +1161,12 @@ settings.launcher.download_source=下載來源
settings.launcher.download_source.auto=自動選取下載來源
settings.launcher.enable_game_list=在首頁內顯示遊戲清單
settings.launcher.font=字體
settings.launcher.font.anti_aliasing=反鋸齒 (重啟後生效)
settings.launcher.font.anti_aliasing=反鋸齒
settings.launcher.font.anti_aliasing.auto=自動
settings.launcher.font.anti_aliasing.gray=灰階
settings.launcher.font.anti_aliasing.lcd=子像素
settings.launcher.general=一般
settings.launcher.language=語言 (重啟後生效)
settings.launcher.language=語言
settings.launcher.launcher_log.export=匯出啟動器日誌
settings.launcher.launcher_log.export.failed=無法匯出日誌。
settings.launcher.launcher_log.export.success=日誌已儲存到「%s」。
@@ -1185,7 +1185,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=帳戶
settings.launcher.theme=主題色
settings.launcher.title_transparent=標題欄透明
settings.launcher.turn_off_animations=關閉動畫 (重啟後生效)
settings.launcher.turn_off_animations=關閉動畫
settings.launcher.version_list_source=版本清單來源
settings.launcher.background.settings.opacity=不透明度
@@ -1171,12 +1171,12 @@ settings.launcher.download_source=下载源
settings.launcher.download_source.auto=自动选择下载源
settings.launcher.enable_game_list=在主页内显示版本列表
settings.launcher.font=字体
settings.launcher.font.anti_aliasing=抗锯齿 (重启后生效)
settings.launcher.font.anti_aliasing=抗锯齿
settings.launcher.font.anti_aliasing.auto=自动
settings.launcher.font.anti_aliasing.gray=灰度
settings.launcher.font.anti_aliasing.lcd=子像素
settings.launcher.general=通用
settings.launcher.language=语言 (重启后生效)
settings.launcher.language=语言
settings.launcher.launcher_log.export=导出启动器日志
settings.launcher.launcher_log.export.failed=无法导出日志
settings.launcher.launcher_log.export.success=日志已保存到“%s”
@@ -1195,7 +1195,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=账户
settings.launcher.theme=主题色
settings.launcher.title_transparent=标题栏透明
settings.launcher.turn_off_animations=关闭动画 (重启后生效)
settings.launcher.turn_off_animations=关闭动画
settings.launcher.version_list_source=版本列表源
settings.launcher.background.settings.opacity=不透明度
@@ -22,7 +22,6 @@ import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.task.GetTask;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.util.Collections;
@@ -65,13 +64,11 @@ public final class LiteLoaderBMCLVersionList extends VersionList<LiteLoaderRemot
NetworkUtils.withQuery(downloadProvider.getApiRoot() + "/liteloader/list", Map.of(
"mcversion", gameVersion
)))
.thenApplyAsync(json -> JsonUtils.fromMaybeMalformedJson(json, LiteLoaderBMCLVersion.class))
.thenGetJsonAsync(LiteLoaderBMCLVersion.class)
.thenAcceptAsync(v -> {
lock.writeLock().lock();
try {
versions.clear();
if (v == null)
return;
versions.put(gameVersion, new LiteLoaderRemoteVersion(
gameVersion, v.version, RemoteVersion.Type.UNCATEGORIZED,
Collections.singletonList(NetworkUtils.withQuery(
@@ -63,13 +63,7 @@ public final class NeoForgeOfficialVersionList extends VersionList<NeoForgeRemot
if (majorVersion == 0) { // Snapshot version.
mcVersion = version.substring(si1 + 1, si2);
} else {
String ver = version.substring(0, Integer.parseInt(version.substring(si1 + 1, si2)) == 0 ? si1 : si2);
if (majorVersion >= 26) {
int separator = version.indexOf('+');
mcVersion = separator < 0 ? ver : ver + "-" + version.substring(separator + 1);
} else {
mcVersion = "1." + ver;
}
mcVersion = "1." + version.substring(0, Integer.parseInt(version.substring(si1 + 1, si2)) == 0 ? si1 : si2);
}
} catch (RuntimeException e) {
LOG.warning(String.format("Cannot parse NeoForge version %s for cracking its mc version.", version), e);
@@ -19,7 +19,7 @@ public class NeoForgeRemoteVersion extends RemoteVersion {
}
private static Type getType(String version) {
return version.contains("beta") || version.contains("alpha") ? Type.SNAPSHOT : Type.RELEASE;
return version.contains("beta") ? Type.SNAPSHOT : Type.RELEASE;
}
public static String normalize(String version) {
@@ -114,20 +114,16 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
if (category != null && category.getSelf() instanceof CurseAddon.Category) {
categoryId = ((CurseAddon.Category) category.getSelf()).getId();
}
var query = new LinkedHashMap<String, String>();
query.put("gameId", "432");
query.put("classId", Integer.toString(section));
if (categoryId != 0)
query.put("categoryId", Integer.toString(categoryId));
query.put("gameVersion", gameVersion);
query.put("searchFilter", searchFilter);
query.put("sortField", Integer.toString(toModsSearchSortField(sortType)));
query.put("sortOrder", toSortOrder(sortOrder));
query.put("index", Integer.toString(pageOffset * pageSize));
query.put("pageSize", Integer.toString(pageSize));
Response<List<CurseAddon>> response = withApiKey(HttpRequest.GET(downloadProvider.injectURL(NetworkUtils.withQuery(PREFIX + "/v1/mods/search", query))))
Response<List<CurseAddon>> response = withApiKey(HttpRequest.GET(downloadProvider.injectURL(NetworkUtils.withQuery(PREFIX + "/v1/mods/search", mapOf(
pair("gameId", "432"),
pair("classId", Integer.toString(section)),
pair("categoryId", Integer.toString(categoryId)),
pair("gameVersion", gameVersion),
pair("searchFilter", searchFilter),
pair("sortField", Integer.toString(toModsSearchSortField(sortType))),
pair("sortOrder", toSortOrder(sortOrder)),
pair("index", Integer.toString(pageOffset * pageSize)),
pair("pageSize", Integer.toString(pageSize)))))))
.getJson(Response.typeOf(listTypeOf(CurseAddon.class)));
if (searchFilter.isEmpty()) {
return new SearchResult(response.getData().stream().map(CurseAddon::toMod), calculateTotalPages(response, pageSize));
@@ -177,6 +177,7 @@ public final class FileUtils {
if (!Character.isValidCodePoint(codePoint)
|| Character.isISOControl(codePoint)
|| codePoint == '/' || codePoint == '\0'
|| codePoint == ':'
// Unicode replacement character
|| codePoint == 0xfffd
// Not Unicode character
@@ -185,7 +186,7 @@ public final class FileUtils {
// https://learn.microsoft.com/windows/win32/fileio/naming-a-file
if (os == OperatingSystem.WINDOWS &&
(ch == '<' || ch == '>' || ch == ':' || ch == '"' || ch == '\\' || ch == '|' || ch == '?' || ch == '*')) {
(ch == '<' || ch == '>' || ch == '"' || ch == '\\' || ch == '|' || ch == '?' || ch == '*')) {
return false;
}
}
@@ -52,6 +52,7 @@ public class FileUtilsTest {
assertFalse(FileUtils.isNameValid(os, "a\uD83Db"));
assertFalse(FileUtils.isNameValid(os, "a\uDE00b"));
assertFalse(FileUtils.isNameValid(os, "a\uDE00\uD83Db"));
assertFalse(FileUtils.isNameValid(os, "f:oo"));
// Platform-specific tests
boolean isWindows = os == OperatingSystem.WINDOWS;
@@ -62,7 +63,6 @@ public class FileUtilsTest {
assertEquals(isNotWindows, FileUtils.isNameValid(os, "foo "));
assertEquals(isNotWindows, FileUtils.isNameValid(os, "f<oo"));
assertEquals(isNotWindows, FileUtils.isNameValid(os, "f>oo"));
assertEquals(isNotWindows, FileUtils.isNameValid(os, "f:oo"));
assertEquals(isNotWindows, FileUtils.isNameValid(os, "f?oo"));
assertEquals(isNotWindows, FileUtils.isNameValid(os, "f*oo"));
assertEquals(isNotWindows, FileUtils.isNameValid(os, "f\\oo"));
+1 -1
View File
@@ -15,4 +15,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
versionRoot=3.9
versionRoot=3.10