Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
e20474f
feat:添加GameRulePage
Mine-diamond Nov 16, 2025
73a5dff
feat:优化代码
Mine-diamond Nov 17, 2025
eab16c4
Merge branch 'main' into gamerule-page
Mine-diamond Nov 17, 2025
89b9beb
feat:优化代码
Mine-diamond Nov 17, 2025
7490d86
Merge branch 'main' into gamerule-page
Mine-diamond Nov 25, 2025
6aeb60c
feat: update
Mine-diamond Nov 25, 2025
b902f96
Merge branch 'main' into gamerule-page
Mine-diamond Dec 6, 2025
58bb703
feat: 添加类
Mine-diamond Dec 7, 2025
b524aae
Merge branch 'main' into gamerule-page
Mine-diamond Dec 7, 2025
b509f29
feat: 现在GameRule类应该初步可用了
Mine-diamond Dec 7, 2025
691599e
feat: 优化功能
Mine-diamond Dec 7, 2025
2d7c54a
feat: 优化功能
Mine-diamond Dec 7, 2025
990205f
feat: 优化功能
Mine-diamond Dec 7, 2025
d521d55
feat: 支持混合数据
Mine-diamond Dec 7, 2025
96f3b06
feat: 优化代码
Mine-diamond Dec 7, 2025
352d142
feat: 优化代码
Mine-diamond Dec 7, 2025
7ab690f
feat: 添加i18n
Mine-diamond Dec 7, 2025
40bf910
feat: 添加i18n
Mine-diamond Dec 7, 2025
4a7519c
fix style
Mine-diamond Dec 7, 2025
612855c
feat: 添加maxValue和minValue的支持
Mine-diamond Dec 8, 2025
f000020
feat: 优化i18n
Mine-diamond Dec 8, 2025
20c814c
feat: 分离页面
Mine-diamond Dec 8, 2025
d7c5a77
feat: 分离页面
Mine-diamond Dec 8, 2025
ee41ed2
feat: 添加保存功能
Mine-diamond Dec 8, 2025
190322d
feat: 添加对旧版格式的支持
Mine-diamond Dec 8, 2025
1099b34
feat: 重命名
Mine-diamond Dec 8, 2025
7c8bb5c
feat: 添加搜索功能
Mine-diamond Dec 8, 2025
4f7311e
feat: 优化gamerule.json列表
Mine-diamond Dec 8, 2025
557b820
feat: 优化代码
Mine-diamond Dec 9, 2025
10446c9
fix style
Mine-diamond Dec 9, 2025
536bef3
feat: 优化代码,添加规则
Mine-diamond Dec 9, 2025
117578c
feat: 添加撤回功能
Mine-diamond Dec 9, 2025
1fc786f
feat: 优化样式,添加i18n
Mine-diamond Dec 9, 2025
5894500
fix style
Mine-diamond Dec 9, 2025
0e6126d
feat: 添加遗漏的规则
Mine-diamond Dec 10, 2025
d5eec22
feat: 更改gamerule i18n规则
Mine-diamond Dec 10, 2025
83cd5c8
feat: 优化代码
Mine-diamond Dec 11, 2025
f116b66
feat: 优化代码
Mine-diamond Dec 11, 2025
244dce2
feat: 优化代码
Mine-diamond Dec 11, 2025
61ece69
feat: 添加i18n,添加确认弹窗
Mine-diamond Dec 11, 2025
bf3f849
feat: 现在NumberRangeValidator只会验证是否在范围内
Mine-diamond Dec 24, 2025
1a7ab6a
feat: 优化恢复全部游戏规则警告弹窗
Mine-diamond Dec 24, 2025
d78e4e6
Merge branch 'main' into gamerule-page
Mine-diamond Dec 24, 2025
6a6dc0f
fix: 无法运行
Mine-diamond Dec 24, 2025
9ba99ba
fix: 重构代码以避免裸使用泛型
Mine-diamond Dec 24, 2025
1440a4a
feat: 优化代码
Mine-diamond Dec 25, 2025
f6796ea
feat: 优化代码
Mine-diamond Dec 25, 2025
323e01f
feat: 当值为默认值时禁用重置图标
Mine-diamond Dec 25, 2025
a1fb0bb
feat: 优化代码
Mine-diamond Dec 25, 2025
75ac9d4
feat: 优化代码
Mine-diamond Dec 25, 2025
e3698d6
Update HMCL/src/main/resources/assets/lang/I18N.properties
Mine-diamond Dec 25, 2025
113d29e
Merge remote-tracking branch 'origin/gamerule-page' into gamerule-page
Mine-diamond Dec 25, 2025
a667ad6
feat: 优化gamerule.json
Mine-diamond Dec 26, 2025
773ff0c
feat: 支持在不同版本使用不同的默认值/最大值/最小值
Mine-diamond Dec 26, 2025
9ee1646
feat: 优化代码
Mine-diamond Dec 27, 2025
edb70bb
feat: 添加重置规则是显示具体变化的功能
Mine-diamond Dec 27, 2025
8f56be8
feat: 优化游戏规则变动列表界面
Mine-diamond Dec 27, 2025
307c799
fix: 修复错误的游戏规则数据
Mine-diamond Dec 27, 2025
3b7e459
feat: 添加test
Mine-diamond Dec 29, 2025
b6f0cdc
feat: 优化资源加载
Mine-diamond Dec 29, 2025
41cbef8
feat: 删除不再使用的文件
Mine-diamond Dec 29, 2025
ef7fd30
feat: 优化代码
Mine-diamond Dec 29, 2025
2fc339a
small fix
Mine-diamond Dec 29, 2025
942d1ba
feat: 优化样式
Mine-diamond Dec 29, 2025
d743fbe
feat: 将cell节点创建方法从cell移至skin中
Mine-diamond Dec 30, 2025
95d491b
feat: 为保存levelDat引入去抖动
Mine-diamond Dec 30, 2025
8fa29ef
feat: 优化gamerule.json解析
Mine-diamond Dec 30, 2025
fd8fc35
feat: 优化代码
Mine-diamond Dec 31, 2025
e7d4f43
feat: 微调恢复确认框样式
Mine-diamond Jan 6, 2026
2ed6760
feat: 微调游戏规则键文本的样式
Mine-diamond Jan 6, 2026
2052502
Merge branch 'main' into gamerule-page
Mine-diamond Jan 7, 2026
287f15d
feat: 优化保存level.dat方法
Mine-diamond Jan 7, 2026
3bce489
feat: 优化游戏规则列表样式
Mine-diamond Jan 8, 2026
70b29e3
feat: 添加已修改过滤功能
Mine-diamond Jan 9, 2026
22fffd5
feat: 优化代码
Mine-diamond Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public enum SVG {
REFRESH("M12 20Q8.65 20 6.325 17.675T4 12Q4 8.65 6.325 6.325T12 4Q13.725 4 15.3 4.7125T18 6.75V4H20V11H13V9H17.2Q16.4 7.6 15.0125 6.8T12 6Q9.5 6 7.75 7.75T6 12Q6 14.5 7.75 16.25T12 18Q13.925 18 15.475 16.9T17.65 14H19.75Q19.05 16.65 16.9 18.325T12 20Z"),
RELEASE_CIRCLE("M9,7H13A2,2 0 0,1 15,9V11C15,11.84 14.5,12.55 13.76,12.85L15,17H13L11.8,13H11V17H9V7M11,9V11H13V9H11M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12C4,16.41 7.58,20 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z"), // Not Material
RESTORE("M12 21Q8.55 21 5.9875 18.7125T3.05 13H5.1Q5.45 15.6 7.4125 17.3T12 19Q14.925 19 16.9625 16.9625T19 12Q19 9.075 16.9625 7.0375T12 5Q10.275 5 8.775 5.8T6.25 8H9V10H3V4H5V6.35Q6.275 4.75 8.1125 3.875T12 3Q13.875 3 15.5125 3.7125T18.3625 5.6375Q19.575 6.85 20.2875 8.4875T21 12Q21 13.875 20.2875 15.5125T18.3625 18.3625Q17.15 19.575 15.5125 20.2875T12 21Z"), // Not Material
RULE("m14.4 20-1.4-1.4 2.6-2.6-2.6-2.6 1.4-1.4 2.6 2.6 2.6-2.6 1.4 1.4-2.6 2.6 2.6 2.6-1.4 1.4-2.6-2.6-2.6 2.6ZM16.375 11L12.825 7.45l1.4-1.4 2.125 2.125 4.25-4.25 1.4 1.425-5.625 5.65ZM2 17v-2h9v2H2ZM2 9v-2h9v2H2Z"),
ROCKET_LAUNCH("M5.65 10.025 7.6 10.85Q7.95 10.15 8.325 9.5T9.15 8.2L7.75 7.925 5.65 10.025ZM9.2 12.1 12.05 14.925Q13.1 14.525 14.3 13.7T16.55 11.825Q18.3 10.075 19.2875 7.9375T20.15 4Q18.35 3.875 16.2 4.8625T12.3 7.6Q11.25 8.65 10.425 9.85T9.2 12.1ZM13.65 10.475Q13.075 9.9 13.075 9.0625T13.65 7.65Q14.225 7.075 15.075 7.075T16.5 7.65Q17.075 8.225 17.075 9.0625T16.5 10.475Q15.925 11.05 15.075 11.05T13.65 10.475ZM14.125 18.5 16.225 16.4 15.95 15Q15.3 15.45 14.65 15.8125T13.3 16.525L14.125 18.5ZM21.95 2.175Q22.425 5.2 21.3625 8.0625T17.7 13.525L18.2 16Q18.3 16.5 18.15 16.975T17.65 17.8L13.45 22 11.35 17.075 7.075 12.8 2.15 10.7 6.325 6.5Q6.675 6.15 7.1625 6T8.15 5.95L10.625 6.45Q13.225 3.85 16.075 2.775T21.95 2.175ZM3.925 15.975Q4.8 15.1 6.0625 15.0875T8.2 15.95Q9.075 16.825 9.0625 18.0875T8.175 20.225Q7.55 20.85 6.0875 21.3T2.05 22.1Q2.4 19.525 2.85 18.0625T3.925 15.975ZM5.35 17.375Q5.1 17.625 4.85 18.2875T4.5 19.625Q5.175 19.525 5.8375 19.2875T6.75 18.8Q7.05 18.5 7.075 18.075T6.8 17.35Q6.5 17.05 6.075 17.0625T5.35 17.375Z"),
SCHEMA("M4 23V17H6.5V15H4V9H6.5V7H4V1h7V7H8.5V9H11v2h3V9h7v6H14V13H11v2H8.5v2H11v6H4Zm2-2H9V19H6v2Zm0-8H9V11H6v2Zm10 0h3V11H16v2ZM6 5H9V3H6V5ZM7.5 4Zm0 8Zm10 0Zm-10 8Z"),
SCHEMA_FILL("M4 23V17H6.5V15H4V9H6.5V7H4V1h7V7H8.5V9H11v2h3V9h7v6H14V13H11v2H8.5v2H11v6H4Z"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <[email protected]> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.construct;

import com.jfoenix.validation.base.ValidatorBase;
import javafx.beans.NamedArg;
import javafx.scene.control.TextInputControl;
import org.jackhuang.hmcl.util.Lang;

/// NumberRangeValidator only check whether inputted number is in range, but not if it is a number,
/// if the input is not a number, NumberRangeValidator will not show error message
public class NumberRangeValidator extends ValidatorBase {
private final int minValue;
private final int maxValue;

public NumberRangeValidator(@NamedArg("outOfLimitMessage") String outOfLimitMessage, @NamedArg("minValue") int minValue, @NamedArg("maxValue") int maxValue) {
super(outOfLimitMessage);
this.minValue = minValue;
this.maxValue = maxValue;
}

@Override
protected void eval() {
if (srcControl.get() instanceof TextInputControl) {
evalTextInputField();
}
}

private void evalTextInputField() {
TextInputControl textField = ((TextInputControl) srcControl.get());
Double intOrNull = Lang.toDoubleOrNull(textField.getText());

if (intOrNull == null) {
hasErrors.set(false);
} else {
hasErrors.set(intOrNull > maxValue || intOrNull < minValue);
}
}
}
202 changes: 202 additions & 0 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameRuleInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <[email protected]> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.versions;

import com.github.steveice10.opennbt.tag.builtin.Tag;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import org.jackhuang.hmcl.gamerule.GameRule;
import org.jackhuang.hmcl.gamerule.GameRuleNBT;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;

import java.util.Objects;

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

public sealed abstract class GameRuleInfo<T> permits GameRuleInfo.BooleanGameRuleInfo, GameRuleInfo.IntGameRuleInfo {
private final String ruleKey;
private final String displayName;
private final GameRuleNBT<T, ? extends Tag> gameRuleNBT;
private final BooleanProperty modified = new SimpleBooleanProperty(this, "modified", false);

private final Runnable onSave;
private Runnable resetValue = () -> {
};

private GameRuleInfo(GameRule gameRule, GameRuleNBT<T, ? extends Tag> gameRuleNBT, Runnable onSave) {
ruleKey = gameRule.getRuleKey().get(0);
String displayName = "";
try {
if (StringUtils.isNotBlank(gameRule.getDisplayI18nKey())) {
displayName = i18n(gameRule.getDisplayI18nKey());
}
} catch (Exception e) {
LOG.warning("Failed to get i18n text for key: " + gameRule.getDisplayI18nKey(), e);
}
this.displayName = displayName;
this.gameRuleNBT = gameRuleNBT;
this.onSave = onSave;
}

public static GameRuleInfo<?> createGameRuleInfo(GameRule gameRule, GameRuleNBT<?, ? extends Tag> gameRuleNBT, Runnable onSave, GameVersionNumber gameVersion) {
if (gameRule instanceof GameRule.IntGameRule intGameRule) {
@SuppressWarnings("unchecked") var typedGameRuleNBT = (GameRuleNBT<String, Tag>) gameRuleNBT;
return new GameRuleInfo.IntGameRuleInfo(intGameRule, typedGameRuleNBT, onSave, gameVersion);
} else if (gameRule instanceof GameRule.BooleanGameRule booleanGameRule) {
@SuppressWarnings("unchecked") var typedGameRuleNBT = (GameRuleNBT<Boolean, Tag>) gameRuleNBT;
return new GameRuleInfo.BooleanGameRuleInfo(booleanGameRule, typedGameRuleNBT, onSave, gameVersion);
}
return null;
}

public abstract String getCurrentValueText();

public abstract String getDefaultValueText();

public void resetValue() {
resetValue.run();
}

public void save() {
onSave.run();
}

public String getRuleKey() {
return ruleKey;
}

public String getDisplayName() {
return displayName;
}

public GameRuleNBT<T, ? extends Tag> getGameRuleNBT() {
return gameRuleNBT;
}

public Runnable getOnSave() {
return onSave;
}

public Runnable getResetValue() {
return resetValue;
}

public void setResetValue(Runnable resetValue) {
this.resetValue = resetValue;
}

public BooleanProperty modifiedProperty() {
return modified;
}

public boolean getModified() {
return modified.get();
}

static final class BooleanGameRuleInfo extends GameRuleInfo<Boolean> {
private final BooleanProperty currentValue;
private final Boolean defaultValue;

public BooleanGameRuleInfo(GameRule.BooleanGameRule booleanGameRule, GameRuleNBT<Boolean, Tag> gameRuleNBT, Runnable onSave, GameVersionNumber gameVersionNumber) {
super(booleanGameRule, gameRuleNBT, onSave);
this.currentValue = new SimpleBooleanProperty(booleanGameRule.getValue());
this.defaultValue = booleanGameRule.getDefaultValue(gameVersionNumber).orElse(null);

currentValue.addListener((observable, oldValue, newValue) -> {
getGameRuleNBT().changeValue(newValue);
save();
});

if (defaultValue != null) {
setResetValue(() -> currentValue.set(defaultValue));
modifiedProperty().bind(Bindings.createBooleanBinding(() -> currentValue.getValue() != defaultValue, currentValue));
}

}

@Override
public String getCurrentValueText() {
return currentValue.getValue().toString();
}

@Override
public String getDefaultValueText() {
return defaultValue == null ? "" : defaultValue.toString();
}

public BooleanProperty currentValueProperty() {
return currentValue;
}
}

static final class IntGameRuleInfo extends GameRuleInfo<String> {
private final StringProperty currentValue;
private final Integer defaultValue;
private final int minValue;
private final int maxValue;

public IntGameRuleInfo(GameRule.IntGameRule intGameRule, GameRuleNBT<String, Tag> gameRuleNBT, Runnable onSave, GameVersionNumber gameVersionNumber) {
super(intGameRule, gameRuleNBT, onSave);
currentValue = new SimpleStringProperty(String.valueOf(intGameRule.getValue()));
defaultValue = intGameRule.getDefaultValue(gameVersionNumber).orElse(null);
minValue = intGameRule.getMinValue(gameVersionNumber);
maxValue = intGameRule.getMaxValue(gameVersionNumber);

currentValue.addListener((observable, oldValue, newValue) -> {
Integer value = Lang.toIntOrNull(newValue);
if (value != null && value >= minValue && value <= maxValue) {
getGameRuleNBT().changeValue(newValue);
save();
}
});

if (defaultValue != null) {
setResetValue(() -> currentValue.set(String.valueOf(defaultValue)));
modifiedProperty().bind(Bindings.createBooleanBinding(() -> !Objects.equals(Lang.toIntOrNull(currentValue.getValue()), defaultValue), currentValue));
}
}

@Override
public String getCurrentValueText() {
return currentValue.getValue();
}

@Override
public String getDefaultValueText() {
return defaultValue == null ? null : defaultValue.toString();
}

public StringProperty currentValueProperty() {
return currentValue;
}

public int getMinValue() {
return minValue;
}

public int getMaxValue() {
return maxValue;
}
}
}
Loading