6 Commits

Author SHA1 Message Date
zs-yg
969fcdff6e 修复下载jre的已知问题 2025-11-20 21:08:01 +08:00
zs-yg
3831c0ae0a 修改打包命令 2025-11-16 18:38:36 +08:00
zs-yg
5acb70c5d2 添加一键下载jre的功能 2025-11-16 18:26:18 +08:00
zs-yg
ddc6aa4e95 添加jre25链接 2025-11-15 13:05:15 +08:00
zs-yg
487212c6eb 添加jre链接 2025-11-15 12:59:36 +08:00
zs-yg
b0cd76dbc1 删除jre链接 2025-11-15 12:50:45 +08:00
8 changed files with 325 additions and 12 deletions

4
.gitignore vendored
View File

@@ -1,4 +1,6 @@
bin/
obj/
logs/
profiles/
profiles/
jre/
setup/

View File

@@ -2,6 +2,7 @@ using System;
using System.Threading.Tasks;
using MCSJ.Tools;
using MCSJ.Tools.LogSystem;
using MCSJ.Tools.JreDownload;
namespace MCSJ
{
@@ -15,6 +16,10 @@ namespace MCSJ
LogMain.Debug($"日志文件: {LogCreator.GetLogFilePath()}");
LogMain.Info("MC服务器下载工具启动");
var httpClient = new HttpClient {
Timeout = TimeSpan.FromMinutes(5),
DefaultRequestHeaders = { { "User-Agent", "MCSJ-JRE-Downloader" } }
};
var versionManager = new VersionManager();
var downloadService = new DownloadService(versionManager);
LogMain.Debug("服务初始化完成");
@@ -24,7 +29,8 @@ namespace MCSJ
Console.WriteLine("MC服务器下载工具");
Console.WriteLine("1. 显示所有版本");
Console.WriteLine("2. 下载指定版本");
Console.WriteLine("3. 退出");
Console.WriteLine("3. 下载JRE");
Console.WriteLine("4. 退出");
Console.Write("请选择操作: ");
var input = Console.ReadLine();
@@ -44,6 +50,19 @@ namespace MCSJ
LogMain.Info($"版本下载完成: {version}");
break;
case "3":
Console.Write("请输入要下载的JRE版本(jre8,jre11,jre17/21/25): ");
var jreVersion = Console.ReadLine();
if (string.IsNullOrWhiteSpace(jreVersion))
{
Console.WriteLine("JRE版本不能为空");
continue;
}
LogMain.Info($"开始下载JRE: {jreVersion}");
var jreDownloadService = new JreDownloadService(httpClient);
await jreDownloadService.DownloadAndSetupJre(jreVersion);
LogMain.Info($"JRE下载完成: {jreVersion}");
break;
case "4":
LogMain.Info("程序正常退出");
return;
default:

View File

@@ -16,10 +16,16 @@ namespace MCSJ.Tools
_httpClient = new HttpClient();
}
public async Task DownloadVersion(string version)
public async Task DownloadVersion(string? version)
{
if (string.IsNullOrWhiteSpace(version))
{
Console.WriteLine("版本名称不能为空");
return;
}
var url = _versionManager.GetDownloadUrl(version);
if (url == null)
if (string.IsNullOrEmpty(url))
{
Console.WriteLine($"版本 {version} 不存在");
return;
@@ -30,8 +36,8 @@ namespace MCSJ.Tools
if (!Directory.Exists(profilesRoot))
Directory.CreateDirectory(profilesRoot);
string targetFolder = null;
string profilePath = null;
string? targetFolder = null;
string? profilePath = null;
while (true)
{
Console.Write($"请输入存放文件夹名称(直接回车默认用版本名 '{version}'");

View File

@@ -71,6 +71,13 @@ namespace MCSJ.Tools
public void DisplayAllVersions()
{
var filePath = Path.Combine("resources", "serverlist.txt");
if (!File.Exists(filePath))
{
Console.WriteLine("版本列表文件不存在");
return;
}
Console.WriteLine("可用版本列表:");
foreach (var version in _versions.Keys)
{
@@ -78,7 +85,7 @@ namespace MCSJ.Tools
}
}
public string GetDownloadUrl(string version)
public string? GetDownloadUrl(string version)
{
return _versions.TryGetValue(version, out var url) ? url : null;
}

View File

@@ -0,0 +1,59 @@
using System;
using System.IO;
namespace MCSJ.Tools.JreDownload
{
public class JreDownloadProgress : IProgress<(long bytesReceived, long totalBytesToReceive, int progressPercentage)>
{
public void Report((long bytesReceived, long totalBytesToReceive, int progressPercentage) value)
{
// 保存当前控制台颜色
var originalColor = Console.ForegroundColor;
try
{
// 计算下载百分比
int percentage = value.progressPercentage;
// 格式化文件大小使用MB单位
string received = FormatFileSizeMB(value.bytesReceived);
string total = FormatFileSizeMB(value.totalBytesToReceive);
// 创建进度条
string progressBar = CreateProgressBar(percentage);
// 显示进度信息(仅进度条部分为绿色)
Console.Write("\r下载进度: ");
Console.ForegroundColor = ConsoleColor.Green;
Console.Write($"{progressBar}");
Console.ForegroundColor = originalColor;
Console.Write($" {percentage}% [{FormatFileSizeMB(value.bytesReceived)} / {FormatFileSizeMB(value.totalBytesToReceive)}]");
// 下载完成时换行
if (percentage == 100)
{
Console.WriteLine();
}
}
finally
{
// 恢复原始控制台颜色
Console.ForegroundColor = originalColor;
}
}
private string CreateProgressBar(int percentage)
{
int width = 20; // 进度条宽度
int progress = percentage * width / 100;
return $"[{new string('#', progress)}{new string('-', width - progress)}]";
}
private string FormatFileSizeMB(long bytes)
{
double mb = bytes / (1024.0 * 1024.0);
return $"{mb:0.##} MB";
}
}
}

View File

@@ -0,0 +1,217 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO.Compression;
namespace MCSJ.Tools.JreDownload
{
public class JreDownloadService
{
private readonly HttpClient _httpClient;
private const string JreListPath = "resources/jrelist.txt";
private const string JreRootFolder = "jre";
private const string SetupFolder = "setup";
public JreDownloadService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task DownloadAndSetupJre(string version)
{
// 0. 检查是否已存在该版本
if (CheckJreExists(version))
{
Console.WriteLine($"JRE {version} 已存在,无需重复下载");
return;
}
// 1. 读取jrelist.txt获取下载链接
var downloadUrl = GetDownloadUrl(version);
if (string.IsNullOrEmpty(downloadUrl))
{
Console.WriteLine($"找不到版本 {version} 的下载链接");
return;
}
// 2. 下载压缩包
var progress = new JreDownloadProgress();
var tempZipPath = await DownloadJreZip(downloadUrl, version, progress);
if (string.IsNullOrEmpty(tempZipPath))
{
Console.WriteLine("下载失败");
return;
}
// 3. 解压到jre文件夹
var jreFolder = Path.Combine(JreRootFolder, version);
if (!ExtractJre(tempZipPath, jreFolder))
{
Console.WriteLine("解压失败");
return;
}
// 4. 查找java.exe和javaw.exe
var javaExePath = FindJavaExe(jreFolder, "java.exe");
var javawExePath = FindJavaExe(jreFolder, "javaw.exe");
if (javaExePath == null || javawExePath == null)
{
Console.WriteLine("找不到java.exe或javaw.exe");
return;
}
// 5. 生成jre.toml
CreateJreToml(version, javaExePath, javawExePath);
// 6. 清理临时文件
File.Delete(tempZipPath);
Console.WriteLine($"JRE {version} 安装完成");
}
private string? GetDownloadUrl(string version)
{
if (string.IsNullOrWhiteSpace(version))
return null;
if (!File.Exists(JreListPath))
return null;
var lines = File.ReadAllLines(JreListPath);
return lines.FirstOrDefault(l => l.StartsWith(version + ":"))?.Split(':').LastOrDefault();
}
private async Task<string?> DownloadJreZip(string url, string version, IProgress<(long, long, int)>? progress = null)
{
var tempPath = Path.GetTempFileName();
try
{
Console.WriteLine($"开始下载 JRE {version}...");
// 确保URL是绝对路径自动补全https协议头
if (!url.StartsWith("http:") && !url.StartsWith("https:"))
{
url = "https:" + url;
}
if (!Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
Console.WriteLine($"无效的下载URL: {url}");
return null;
}
Console.WriteLine($"正在准备下载 {url}...");
var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
var totalBytes = response.Content.Headers.ContentLength ?? 0;
Console.WriteLine($"文件总大小: {totalBytes} 字节");
long bytesRead = 0;
var lastReportTime = DateTime.MinValue;
Console.WriteLine("开始下载...");
using (var stream = await response.Content.ReadAsStreamAsync())
using (var fileStream = new FileStream(tempPath, FileMode.Create))
{
var buffer = new byte[8192];
int bytesReadThisPass;
while ((bytesReadThisPass = await stream.ReadAsync(buffer)) != 0)
{
await fileStream.WriteAsync(buffer.AsMemory(0, bytesReadThisPass));
bytesRead += bytesReadThisPass;
// 限制进度报告频率,避免过多控制台输出
if (DateTime.Now - lastReportTime > TimeSpan.FromMilliseconds(100) || bytesRead == totalBytes)
{
int progressPercentage = totalBytes > 0 ? (int)(bytesRead * 100 / totalBytes) : 0;
Console.WriteLine($"报告进度: {bytesRead}/{totalBytes} ({progressPercentage}%)");
progress?.Report((bytesRead, totalBytes, progressPercentage));
lastReportTime = DateTime.Now;
}
}
}
return tempPath;
}
catch (Exception ex)
{
Console.WriteLine($"下载失败: {ex.Message}");
return null;
}
}
private bool ExtractJre(string zipPath, string targetFolder)
{
try
{
if (Directory.Exists(targetFolder))
Directory.Delete(targetFolder, true);
Directory.CreateDirectory(targetFolder);
ZipFile.ExtractToDirectory(zipPath, targetFolder);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"解压失败: {ex.Message}");
return false;
}
}
private string? FindJavaExe(string folder, string exeName)
{
if (string.IsNullOrWhiteSpace(folder) || string.IsNullOrWhiteSpace(exeName))
return null;
if (!Directory.Exists(folder))
return null;
return Directory.GetFiles(folder, exeName, SearchOption.AllDirectories).FirstOrDefault();
}
private bool CheckJreExists(string version)
{
var tomlPath = Path.Combine(SetupFolder, "jre.toml");
if (!File.Exists(tomlPath))
return false;
try
{
var content = File.ReadAllText(tomlPath);
return content.Contains($"[jre.{version}]");
}
catch
{
return false;
}
}
private void CreateJreToml(string version, string javaExePath, string javawExePath)
{
if (!Directory.Exists(SetupFolder))
Directory.CreateDirectory(SetupFolder);
var tomlPath = Path.Combine(SetupFolder, "jre.toml");
var content = $@"[jre.{version}]
java_path = '{javaExePath}'
javaw_path = '{javawExePath}'
";
if (File.Exists(tomlPath))
{
var existingContent = File.ReadAllText(tomlPath);
if (!existingContent.Contains($"[jre.{version}]"))
{
File.AppendAllText(tomlPath, content);
}
}
else
{
File.WriteAllText(tomlPath, content);
}
}
}
}

View File

@@ -4,4 +4,6 @@ cd bin\Release\net8.0
ren win-x64 MCSJ-x64
ren win-x86 MCSJ-x86
rmdir /s /q MCSJ-x64\publish
rmdir /s /q MCSJ-x86\publish
rmdir /s /q MCSJ-x86\publish
7z a -tzip MCSJ-x64.zip MCSJ-x64
7z a -tzip MCSJ-x86.zip MCSJ-x86

View File

@@ -1,4 +1,5 @@
jre8:https://developer-oss.lanrar.com/file/?AWcAPlxtVGVSWwY+V2JSPldoDjZXcgdwVT4AcwVhBCsGP1o9Dn0OaglxUDcDblF9Vm8OalQmVz8EcVc0UzdXeAExAHlcNVQ3UjYGfVd0UjpXYw5UV3AHM1VmACgFIwRsBnZaKw41DjMJM1BjAwhROVZoDjZUOVdjBDFXYlM+V28BOABvXDVUJlJiBiNXPlJnVz0OPVc+BzNVYgA2BWsEIwZ2Wn0Obg5oCW9QNANiUX9WPQ46VCRXZAQ2V35Tblc0ATUANFxgVDRSMAZnVzZSMVc/DmhXbgdhVWIANQVgBD0GPlo5DmYOPgloUD4DZVEyVm0OblQ5V2cEYlc1UyFXLAFoACdcJ1R1UncGNVdxUjpXaQ42VzwHNlVjAD8FagQ0BjBaKw4nDjMJMlBjAzFRbVY9DjxUPVdmBDJXZlM2V2UBNABlXC9ULlIiBjZXb1IkVzAOO1cuB3BVIgBxBWQENAYxWjsOYA5rCWhQMQNuUWhWOQ4tVH5XPARzV2xTPldkATEAeVwzVDNSPQZ+VzBSYVcjDjpXPgc9VXwAIAU9BGoGcVpjDgwOOQk0UDsDZ1F+VioOf1RyVyUEZlcOU3pXNwE8AGc=&toolsdown
jre11:https://developer-oss.lanrar.com/file/?AGZXaQk4ADEGDwM7VGEFaVZpADgEIQN0AmlVJlwxUGAGKFc4DWRULlI1C2oFfFAyBj0DK1diBnYDYVJlVDlWeQAwVy4JZgBtBn0DIlRpBWpWUwB9BG0DNQIrVSlcaVAhBiBXZg05VGxSYQsCBThQNQZhAzRXPgY2AzdSZlQ4VmQAOVc0CXIAMgYjA2hUNAU0VjsANgRuAzQCNlVhXCZQIQZ2Vz0NYlQwUjYLaAV+UGAGbQMpVzkGMQMrUmVUOlYzADVXNQlhADYGZgNtVGQFYFY6AGYEagMyAjVVY1xmUDcGN1diDTRUZlI1CzkFaFBjBjoDY1c/BjIDZ1J6VHJWPgBwVyYJIQAnBjUDJ1RpBWBWMQAxBGgDMAI8VWBcMVBnBiBXdA05VG1SYQs7BWxQYAZrAzBXOwY1AzNSbVQ6VmQANlcuCXoAcgY2AzlUdwU5VjwAIwQuA3ECclVuXDFQZgYwVzMNYVQ3UjwLbQVoUGEGegNzV2EGdAM5UmVUOlZnAC5XMglnAG0GfgNmVDIFKlY9ADMEYwMvAiNVN1xvUCYGaFdfDTNUa1I5C20Ff1B3BigDf1d4BmEDW1IhVGlWagAw&toolsdown
jre17:https://developer-oss.lanrar.com/file/?CG5aZFprVWQBCAY+BTABbQY5DzdWcwRzC2ABcl0wBDIDLQdmWjVQKlM0AGEGf1Y0UWoBKVVgC3sEZlViAWoALwg4WiNaNlU2AXoGJwU4AW4GAw9yVj8EMgsiAX1daAR1AyUHNlpuUGhTYAAJBjtWM1E2ATZVPAs7BDBVYQFtADAIOVo7WiFVZwEkBm0FZQE0BmwPOFY9BDELOgE1XScEdQNzB21aNVA0UzcAYwZ9VmZROgErVTsLPAQsVWYBbgAyCDBaOVpjVTQBNgY2BWYBOQZrDz9WawRnCz0BMV1nBDQDMgc0WmZQMFM9ADAGMVYxUTMBYVUzCzsEYlV9AScAaAh4WitaclVyATIGIgU4AWQGYQ8+VjoENws1ATRdMAQzAyUHJFpuUGlTYAAwBm9WZlE8ATJVOQs4BDRVagFpADAIPVojWilVJwExBjwFJgE9BmwPLFZ8BHYLewE6XTAEMgM1B2NaNlAzUz0AZgZjVm5RLQFxVWMLeQQ+VWIBbwAxCCZaP1o0VTgBeQZjBWMBLgZtDzxWMQQoCyoBY11uBHIDbQcPWmRQb1M4AGYGfFZxUX8BfVV6C2wEXFUmATwAPAg4&toolsdown
jre21:https://developer-oss.lanrar.com/file/?VDIFOwg5U2JWX1RsBDFUOFplDjYDJgB3Vj0GdV0zVmZXeVU2WzBXLVYxBWoAeVQ2UGsFLV9qVCQHZVJmAG1XeFRkBXwIbFMqVndUawQ+VApaeA49A2gALFYrBmldcVZxVzFVa1tqV2ZWXwU6ADBUaFA4BTZfMlRlBzJSZABuV2BUYQV0CDNTdFY9VDYEaVRgWjMOPANuADNWYgYmXXFWJ1dqVTBbNlcxVjUFfABlVGRQJQUxXzVUeQcxUmQAbldvVDAFMAhhUzVWZFRnBGRUZFphDjoDZABhVjMGY11kVmBXYVVkW2BXOlZjBWUAMlQzUD4FN18zVGcHLlIuADVXJlRyBScIJlNiVnJUawQ0VGhaNA44A20AO1ZiBjFdN1ZxVyNVa1trV2ZWZgVuAGVUYlA8BTNfMVRhBzlSYABvV2BUegV8CHNTYVZsVHUEbVRlWiYOfgMsAHVWbAYxXTZWYVdkVTNbMVc7VjAFZgBjVHNQfwVpX3BUawcxUmYAbFd4VGYFYQhsUylWM1QwBH5UZFo2DjMDcgAkVjUGb112VjlXCFVhW21XPlYwBX0AclQhUHMFcF9lVAkHdVI1AGFXZg==&toolsdown
jre8:https://pan.tenire.com/down.php/2dd2a856cdb549dce5b557026e20b36a.zip
jre11:https://pan.tenire.com/down.php/3ec613e667f35e364d921aeb0315272a.zip
jre17:https://pan.tenire.com/down.php/f28009799fca1c62f4c37a5ab4759db3.zip
jre21:https://pan.tenire.com/down.php/253e308ecfce3be809f2e85d6513791d.zip
jre25:https://pan.tenire.com/down.php/e3ae0f146ce3fa1d27a805f86b138058.zip