Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
matrix:
# Use these Java versions
java: [
21, # Current Java LTS
17, # Minimum supported Java version
]
runs-on: ubuntu-22.04
steps:
Expand All @@ -30,7 +30,7 @@ jobs:
- name: build
run: ./gradlew build
- name: capture build artifacts
if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java
if: ${{ matrix.java == '17' }}
uses: actions/upload-artifact@v4
with:
name: Artifacts
Expand Down
64 changes: 64 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Changelog

## v1.1.0 Release

### Features

- **IP 缓存系统** - 实现 IP 缓存机制,优化延迟测试流程 (`c6d3182`)
- **获取状态与远程回退** - 添加获取状态显示,缓存为空时回退到远程 IP 获取 (`c578a64`)
- **延迟 Tooltip 显示** - 添加延迟 Tooltip 展示和 IP 列表获取接口 (`c8bc30c`)

### Bug Fixes

- **线程安全与异步测速** - 修复线程安全问题,将延迟测试改为异步执行 (`cfd057a`)
- **异常处理** - 处理 IP 加载过程中的意外异常 (`af6919e`)
- **URL 弃用 API 替换** - 使用 URI 替代已弃用的 `new URL(String)` (`6656515`)
- **线程泄漏** - 修复 ExecutorService 泄漏和线程安全问题 (`2792dd6`)
- **补充 Mixin** - 添加缺失的 ServerAddressMixin (`c4fc3bf`)、ServerUtil (`89e1e19`)
- **工作流修复** - 重命名类文件以修复 CI 构建错误 (`10f29fc`, `81f6b53`)

### Refactor

- **服务器检测逻辑抽取** - 将服务器检测逻辑重构为独立的工具类 (`05be7d7`)
- **类重命名与封装优化** - 重命名类,封装延迟逻辑并改进日志 (`a74f01c`)

### CI

- **Java 版本变更** - 将 CI 的 Java 版本更改为 17 (`915cbc5`)

---

## v1.0.0 Release

### Features

- **统一配置并优化底层连接** - 统一配置管理,所有底层连接切换为优选 IP (`83d5985`)
- **IP 管理刷新功能** - 添加 IP 管理刷新功能并优化状态显示 (`cdfe06c`)
- **IP 延迟测试** - 添加 IP 延迟测试并显示最快 IP (`82ca4e3`)
- **IP 获取超时提示** - 添加 IP 获取超时状态显示 (`b7f5b61`)
- **服务器列表状态展示** - 在服务器列表中显示自定义 IP 状态 (`b3daff1`)
- **服务器 IP 优选配置** - 添加服务器 IP 优选配置选项 (`d048dd6`)
- **简化 UI** - 移除自动 IP 切换,简化用户界面 (`4163285`)

### Bug Fixes

- **消息显示错误** - 修复消息显示异常 (`e81a100`)
- **测速等待问题** - 修复未等待测速完成就访问的问题 (`19ce16f`)
- **自动优选连接** - 修复连接时自动选择最优 IP 的逻辑 (`cd38b79`)
- **状态文本位置** - 优化状态文本显示位置 (`aee0a8a`)

### Refactor

- **更新默认目标服务器地址** (`d052c52`)
- **重构 IP 管理器** (`b173d5d`)

### Performance

- **优化延迟测试逻辑** (`74d2060`)

### Chores

- **优化代码结构** (`3771a4e`)
- **移除示例 mixin 文件** (`801f50c`)
- **更新模组基础信息** (`7b2fd8a`, `fa340f5`)
- **初始化 README** (`791c6f8`)
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ yarn_mappings=1.20.4+build.3
loader_version=0.15.7

# Mod Properties
mod_version=1.0.0
mod_version=1.1.0
maven_group=com.lnlfly
archives_base_name=ipick

Expand Down
11 changes: 11 additions & 0 deletions src/client/java/com/lnlfly/IPickClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.lnlfly;

import com.lnlfly.util.IpManager;
import net.fabricmc.api.ClientModInitializer;

public class IPickClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
IpManager.get().fetchAndCacheIps();
}
}
6 changes: 3 additions & 3 deletions src/client/java/com/lnlfly/config/ModConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ public class ModConfig {
public String ipListUrl = "https://gitea.dusays.com/fenychn0206/static/raw/branch/main/IPs.json"; // 默认 API 地址
public String targetServerAddress = "mc.lnlfly.com"; // 默认目标服务器地址

public static ModConfig get() {
public static synchronized ModConfig get() {
if (INSTANCE == null) {
load();
}
return INSTANCE;
}

public static void load() {
public static synchronized void load() {
if (CONFIG_FILE.exists()) {
try (FileReader reader = new FileReader(CONFIG_FILE)) {
INSTANCE = GSON.fromJson(reader, ModConfig.class);
Expand All @@ -39,7 +39,7 @@ public static void load() {
}
}

public static void save() {
public static synchronized void save() {
if (INSTANCE == null) return;
try (FileWriter writer = new FileWriter(CONFIG_FILE)) {
GSON.toJson(INSTANCE, writer);
Expand Down
10 changes: 0 additions & 10 deletions src/client/java/com/lnlfly/ipickClient.java

This file was deleted.

37 changes: 10 additions & 27 deletions src/client/java/com/lnlfly/mixin/client/AddServerScreenMixin.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.lnlfly.mixin.client;

import com.lnlfly.config.ModConfig;
import com.lnlfly.util.ServerUtil;
import net.minecraft.client.gui.screen.multiplayer.AddServerScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.CheckboxWidget;
Expand Down Expand Up @@ -29,33 +30,27 @@ protected AddServerScreenMixin(Text title) {
@Inject(method = "init", at = @At("TAIL"))
private void onInit(CallbackInfo ci) {
int centerX = this.width / 2;
int yStart = this.height / 4 + 96;
int yStart = this.height / 4 + 96;

Text label = Text.literal("进入时选择最优IP");

// 计算宽度以居中
// CheckboxWidget 的宽度通常是 20 (方框) + 4 (间距) + 文本宽度

int width = this.textRenderer.getWidth(label) + 24;

// 加载配置
ModConfig config = ModConfig.get();

// 居中显示“进入时选择最优IP”
this.autoSelectBestIpCheckbox = CheckboxWidget.builder(label, this.textRenderer)
.pos(centerX - width / 2, yStart)
.checked(config.selectBestIpOnEnter) // 设置初始状态
.checked(config.selectBestIpOnEnter)
.callback((checkbox, checked) -> {
config.selectBestIpOnEnter = checked;
ModConfig.save(); // 保存配置
ModConfig.save();
})
.build();

this.addDrawableChild(this.autoSelectBestIpCheckbox);

// 初始可见性检查
updateCheckboxVisibility();

// 为地址栏添加监听器以更新可见性
if (this.addressField != null) {
this.addressField.setChangedListener(text -> {
updateCheckboxVisibility();
Expand All @@ -66,23 +61,11 @@ private void onInit(CallbackInfo ci) {

private void updateCheckboxVisibility() {
if (this.addressField == null) return;

String enteredHost = normalizeHost(this.addressField.getText());
String target = ModConfig.get().targetServerAddress;
String targetHost = target == null ? "" : normalizeHost(target);
boolean isSpecificDomain = !targetHost.isEmpty() && targetHost.equalsIgnoreCase(enteredHost);

if (this.autoSelectBestIpCheckbox != null) {
this.autoSelectBestIpCheckbox.visible = isSpecificDomain;
}
}

private String normalizeHost(String address) {
String value = address.trim();
int colon = value.indexOf(':');
if (colon > 0 && value.indexOf(']') < 0) {
return value.substring(0, colon);
boolean isTarget = ServerUtil.isTargetServer(this.addressField.getText());

if (this.autoSelectBestIpCheckbox != null) {
this.autoSelectBestIpCheckbox.visible = isTarget;
}
return value;
}
}
34 changes: 7 additions & 27 deletions src/client/java/com/lnlfly/mixin/client/ConnectScreenMixin.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.lnlfly.mixin.client;

import com.lnlfly.IPick;
import com.lnlfly.config.ModConfig;
import com.lnlfly.util.IpInfo;
import com.lnlfly.util.IpManager;
import com.lnlfly.util.ServerUtil;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
Expand All @@ -21,14 +23,11 @@ public class ConnectScreenMixin {

@Inject(method = "connect(Lnet/minecraft/client/gui/screen/Screen;Lnet/minecraft/client/MinecraftClient;Lnet/minecraft/client/network/ServerAddress;Lnet/minecraft/client/network/ServerInfo;Z)V", at = @At("HEAD"), cancellable = true)
private static void onConnect(Screen parent, MinecraftClient client, ServerAddress address, ServerInfo info, boolean quickPlay, CallbackInfo ci) {
if (isTargetServer(address)) {
// 检查配置是否开启
if (ServerUtil.isTargetServer(address.getAddress())) {
if (ModConfig.get().selectBestIpOnEnter) {
IpManager ipManager = IpManager.get();
// 如果 IP 还没获取到或正在测速
if (!ipManager.isLoaded() || ipManager.isTestingLatency()) {
ci.cancel(); // 取消连接
// 弹出提示
ci.cancel();
SystemToast.add(client.getToastManager(), SystemToast.Type.PERIODIC_NOTIFICATION, Text.literal("IPick"), Text.literal("请等待服务器 IP 测速完成"));
}
}
Expand All @@ -37,36 +36,17 @@ private static void onConnect(Screen parent, MinecraftClient client, ServerAddre

@ModifyVariable(method = "connect(Lnet/minecraft/client/gui/screen/Screen;Lnet/minecraft/client/MinecraftClient;Lnet/minecraft/client/network/ServerAddress;Lnet/minecraft/client/network/ServerInfo;Z)V", at = @At("HEAD"), argsOnly = true)
private static ServerAddress modifyAddress(ServerAddress address) {
if (isTargetServer(address)) {
// 检查配置是否开启
if (ServerUtil.isTargetServer(address.getAddress())) {
if (ModConfig.get().selectBestIpOnEnter) {
IpManager ipManager = IpManager.get();
IpInfo bestIp = ipManager.getBestIp();

// 如果找到了最优 IP,则替换

if (bestIp != null) {
System.out.println("IPick: Redirecting connection from " + address.getAddress() + " to best IP: " + bestIp.ip + ":" + bestIp.port);
IPick.LOGGER.info("Redirecting connection from {} to best IP: {}:{}", address.getAddress(), bestIp.ip, bestIp.port);
return new ServerAddress(bestIp.ip, bestIp.port);
}
}
}
return address;
}

private static boolean isTargetServer(ServerAddress address) {
String target = ModConfig.get().targetServerAddress;
if (target == null) return false;

String targetHost = normalizeHost(target);
return !targetHost.isEmpty() && address.getAddress().equalsIgnoreCase(targetHost);
}

private static String normalizeHost(String address) {
String value = address.trim();
int colon = value.indexOf(':');
if (colon > 0 && value.indexOf(']') < 0) {
return value.substring(0, colon);
}
return value;
}
}
15 changes: 2 additions & 13 deletions src/client/java/com/lnlfly/mixin/client/ServerAddressMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.lnlfly.config.ModConfig;
import com.lnlfly.util.IpInfo;
import com.lnlfly.util.IpManager;
import com.lnlfly.util.ServerUtil;
import net.minecraft.client.network.ServerAddress;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
Expand All @@ -16,24 +17,12 @@ public class ServerAddressMixin {
ModConfig config = ModConfig.get();
if (!config.selectBestIpOnEnter) return;

String targetHost = normalizeHost(config.targetServerAddress);
String requestHost = normalizeHost(address);
if (targetHost.isEmpty() || !targetHost.equalsIgnoreCase(requestHost)) return;
if (!ServerUtil.isTargetServer(address)) return;

IpManager ipManager = IpManager.get();
IpInfo bestIp = ipManager.getBestIp();
if (!ipManager.isLatencyTestCompleted() || bestIp == null) return;

cir.setReturnValue(new ServerAddress(bestIp.ip, bestIp.port));
}

private static String normalizeHost(String value) {
if (value == null) return "";
String host = value.trim();
int colon = host.indexOf(':');
if (colon > 0 && host.indexOf(']') < 0) {
return host.substring(0, colon);
}
return host;
}
}
Loading