mirror of
https://github.com/zs-yg/MCSJ.git
synced 2025-12-06 19:00:43 +08:00
Compare commits
27 Commits
v0.0.3
...
94b2e7a196
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94b2e7a196 | ||
|
|
8c5d3a8219 | ||
|
|
060edfb873 | ||
|
|
397002f2e8 | ||
|
|
9e5e290da5 | ||
|
|
59b7c84310 | ||
|
|
306a7bb309 | ||
|
|
62713817e1 | ||
|
|
1870b066fc | ||
|
|
7d74c603b8 | ||
|
|
aea0742092 | ||
|
|
295791b4f2 | ||
|
|
ff0cf01100 | ||
|
|
b88c7507aa | ||
|
|
969fcdff6e | ||
|
|
3831c0ae0a | ||
|
|
5acb70c5d2 | ||
|
|
ddc6aa4e95 | ||
|
|
487212c6eb | ||
|
|
b0cd76dbc1 | ||
|
|
73c32eac51 | ||
|
|
3350b1798e | ||
|
|
ddc0d1d9e0 | ||
|
|
adaa360265 | ||
|
|
e2219d5042 | ||
|
|
8982aa9bcc | ||
|
|
0b6f66304b |
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
logs/
|
||||||
|
profiles/
|
||||||
|
jre/
|
||||||
|
setup/
|
||||||
54
Program.cs
54
Program.cs
@@ -1,6 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MCSJ.Tools;
|
using MCSJ.Tools;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
using MCSJ.Tools.JreDownload;
|
||||||
|
using MCSJ.Tools.ViewJre;
|
||||||
|
using MCSJ.Tools.ServerManagement;
|
||||||
|
|
||||||
namespace MCSJ
|
namespace MCSJ
|
||||||
{
|
{
|
||||||
@@ -8,33 +12,75 @@ namespace MCSJ
|
|||||||
{
|
{
|
||||||
static async Task Main(string[] args)
|
static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
|
// 验证日志目录
|
||||||
|
string logDir = LogCreator.GetLogDirectory();
|
||||||
|
Console.WriteLine($"日志目录: {logDir}");
|
||||||
|
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 versionManager = new VersionManager();
|
||||||
var downloadService = new DownloadService(versionManager);
|
var downloadService = new DownloadService(versionManager);
|
||||||
|
var jreViewer = new JreViewer();
|
||||||
|
LogMain.Debug("服务初始化完成");
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Console.WriteLine("MC服务器下载工具");
|
Console.WriteLine("MC服务器启动工具");
|
||||||
Console.WriteLine("1. 显示所有版本");
|
Console.WriteLine("1. 显示所有服务器版本");
|
||||||
Console.WriteLine("2. 下载指定版本");
|
Console.WriteLine("2. 下载指定服务器版本");
|
||||||
Console.WriteLine("3. 退出");
|
Console.WriteLine("3. 服务器管理");
|
||||||
|
Console.WriteLine("4. 下载JRE");
|
||||||
|
Console.WriteLine("5. 查看已安装的JRE");
|
||||||
|
Console.WriteLine("6. 退出");
|
||||||
Console.Write("请选择操作: ");
|
Console.Write("请选择操作: ");
|
||||||
|
|
||||||
var input = Console.ReadLine();
|
var input = Console.ReadLine();
|
||||||
|
LogMain.Debug($"用户选择操作: {input}");
|
||||||
|
|
||||||
switch (input)
|
switch (input)
|
||||||
{
|
{
|
||||||
case "1":
|
case "1":
|
||||||
versionManager.DisplayAllVersions();
|
versionManager.DisplayAllVersions();
|
||||||
|
LogMain.Info("显示所有版本列表");
|
||||||
break;
|
break;
|
||||||
case "2":
|
case "2":
|
||||||
Console.Write("请输入要下载的版本名称: ");
|
Console.Write("请输入要下载的版本名称: ");
|
||||||
var version = Console.ReadLine();
|
var version = Console.ReadLine();
|
||||||
|
LogMain.Info($"开始下载版本: {version}");
|
||||||
await downloadService.DownloadVersion(version);
|
await downloadService.DownloadVersion(version);
|
||||||
|
LogMain.Info($"版本下载完成: {version}");
|
||||||
break;
|
break;
|
||||||
case "3":
|
case "3":
|
||||||
|
ServerManager.ShowMenu();
|
||||||
|
LogMain.Info("进入服务器管理");
|
||||||
|
break;
|
||||||
|
case "4":
|
||||||
|
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 "5":
|
||||||
|
jreViewer.DisplayInstalledJres();
|
||||||
|
LogMain.Info("显示已安装的JRE列表");
|
||||||
|
break;
|
||||||
|
case "6":
|
||||||
|
LogMain.Info("程序正常退出");
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
Console.WriteLine("无效输入,请重新选择");
|
Console.WriteLine("无效输入,请重新选择");
|
||||||
|
LogMain.Warn($"无效的用户输入: {input}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -35,7 +35,11 @@ MCSJ 是一个开源的 Minecraft 服务器管理工具,旨在为用户提供
|
|||||||
2. 双击运行 MCSJ.exe 启动程序。
|
2. 双击运行 MCSJ.exe 启动程序。
|
||||||
3. 或者命令行输入MCSJ.exe 启动程序。可以查看是否需要安装运行时
|
3. 或者命令行输入MCSJ.exe 启动程序。可以查看是否需要安装运行时
|
||||||
|
|
||||||
## 关于作者
|
## 官方镜像仓库
|
||||||
|
|
||||||
|
[gitee镜像仓库](https://gitee.com/chr_super/mcsj)
|
||||||
|
|
||||||
|
## 关于
|
||||||
|
|
||||||
MCSJ 项目由 [zs-yg](https://github.com/zs-yg) 开发,欢迎提交 issue 和 PR。
|
MCSJ 项目由 [zs-yg](https://github.com/zs-yg) 开发,欢迎提交 issue 和 PR。
|
||||||
|
|
||||||
@@ -43,11 +47,17 @@ MCSJ 项目由 [zs-yg](https://github.com/zs-yg) 开发,欢迎提交 issue 和
|
|||||||
|
|
||||||
qq群:1043867176
|
qq群:1043867176
|
||||||
|
|
||||||
[b站号]:(https://space.bilibili.com/1698250734)
|
b站号:https://space.bilibili.com/1698250734
|
||||||
|
|
||||||
|
|
||||||
## 开源协议
|
## 开源协议
|
||||||
|
|
||||||
|
MIT协议
|
||||||
本项目已在 GitHub 开源,欢迎贡献代码与建议。
|
本项目已在 GitHub 开源,欢迎贡献代码与建议。
|
||||||
|
|
||||||
|
# 恰饭awa
|
||||||
|
|
||||||
|
不用捐款,使用这个链接注册服务器就行了awa
|
||||||
|
性能不错,可以免费白嫖
|
||||||
|
|
||||||
|
服务器:https://www.rainyun.com/Nzk2NDEy_
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
namespace MCSJ.Tools
|
namespace MCSJ.Tools
|
||||||
{
|
{
|
||||||
@@ -16,12 +17,20 @@ namespace MCSJ.Tools
|
|||||||
_httpClient = new HttpClient();
|
_httpClient = new HttpClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadVersion(string version)
|
public async Task DownloadVersion(string? version)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(version))
|
||||||
|
{
|
||||||
|
Console.WriteLine("版本名称不能为空");
|
||||||
|
LogMain.Error("版本名称不能为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var url = _versionManager.GetDownloadUrl(version);
|
var url = _versionManager.GetDownloadUrl(version);
|
||||||
if (url == null)
|
if (string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
Console.WriteLine($"版本 {version} 不存在");
|
Console.WriteLine($"版本 {version} 不存在");
|
||||||
|
LogMain.Error($"版本 {version} 不存在");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,8 +39,8 @@ namespace MCSJ.Tools
|
|||||||
if (!Directory.Exists(profilesRoot))
|
if (!Directory.Exists(profilesRoot))
|
||||||
Directory.CreateDirectory(profilesRoot);
|
Directory.CreateDirectory(profilesRoot);
|
||||||
|
|
||||||
string targetFolder = null;
|
string? targetFolder = null;
|
||||||
string profilePath = null;
|
string? profilePath = null;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Console.Write($"请输入存放文件夹名称(直接回车默认用版本名 '{version}'):");
|
Console.Write($"请输入存放文件夹名称(直接回车默认用版本名 '{version}'):");
|
||||||
@@ -41,10 +50,12 @@ namespace MCSJ.Tools
|
|||||||
if (!Directory.Exists(profilePath))
|
if (!Directory.Exists(profilePath))
|
||||||
break;
|
break;
|
||||||
Console.WriteLine($"文件夹 '{targetFolder}' 已存在,请重新输入(直接回车则取消下载):");
|
Console.WriteLine($"文件夹 '{targetFolder}' 已存在,请重新输入(直接回车则取消下载):");
|
||||||
|
LogMain.Warn($"文件夹 '{targetFolder}' 已存在,请重新输入(直接回车则取消下载):");
|
||||||
}
|
}
|
||||||
if (Directory.Exists(profilePath))
|
if (Directory.Exists(profilePath))
|
||||||
{
|
{
|
||||||
Console.WriteLine("下载已取消。");
|
Console.WriteLine("下载已取消。");
|
||||||
|
LogMain.Info("下载已取消。");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Directory.CreateDirectory(profilePath);
|
Directory.CreateDirectory(profilePath);
|
||||||
@@ -53,6 +64,7 @@ namespace MCSJ.Tools
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console.WriteLine($"开始下载 {version} 到 {profilePath} ...");
|
Console.WriteLine($"开始下载 {version} 到 {profilePath} ...");
|
||||||
|
LogMain.Info($"开始下载 {version} 到 {profilePath} ...");
|
||||||
var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
@@ -84,10 +96,12 @@ namespace MCSJ.Tools
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Console.WriteLine($"\n{version} 下载完成! 文件已保存到 {jarPath}");
|
Console.WriteLine($"\n{version} 下载完成! 文件已保存到 {jarPath}");
|
||||||
|
LogMain.Info($"{version} 下载完成! 文件已保存到 {jarPath}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"下载失败: {ex.Message}");
|
Console.WriteLine($"下载失败: {ex.Message}");
|
||||||
|
LogMain.Error($"下载失败: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
namespace MCSJ.Tools
|
namespace MCSJ.Tools
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,7 @@ namespace MCSJ.Tools
|
|||||||
{
|
{
|
||||||
var filePath = Path.Combine("resources", "serverlist.txt");
|
var filePath = Path.Combine("resources", "serverlist.txt");
|
||||||
Console.WriteLine($"尝试从路径加载版本列表: {Path.GetFullPath(filePath)}");
|
Console.WriteLine($"尝试从路径加载版本列表: {Path.GetFullPath(filePath)}");
|
||||||
|
LogMain.Info($"尝试从路径加载版本列表: {Path.GetFullPath(filePath)}");
|
||||||
|
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
{
|
{
|
||||||
@@ -42,7 +44,8 @@ namespace MCSJ.Tools
|
|||||||
|
|
||||||
if (string.IsNullOrEmpty(version) || string.IsNullOrEmpty(url))
|
if (string.IsNullOrEmpty(version) || string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
Console.WriteLine($"忽略无效条目: {rawLine} (版本或URL为空)");
|
Console.WriteLine($"忽略无效条目: {rawLine} (版本或URL为空)");
|
||||||
|
LogMain.Warn($"忽略无效条目: {rawLine} (版本或URL为空)");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +54,7 @@ namespace MCSJ.Tools
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"忽略无效条目: {rawLine} (缺少冒号分隔或格式不正确)");
|
Console.WriteLine($"忽略无效条目: {rawLine} (缺少冒号分隔或格式不正确)");
|
||||||
|
LogMain.Warn($"忽略无效条目: {rawLine} (缺少冒号分隔或格式不正确)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,25 +64,37 @@ namespace MCSJ.Tools
|
|||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"成功加载 {_versions.Count} 个版本");
|
Console.WriteLine($"成功加载 {_versions.Count} 个版本");
|
||||||
|
LogMain.Info($"成功加载 {_versions.Count} 个版本");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"加载版本列表失败: {ex.Message}");
|
Console.WriteLine($"加载版本列表失败: {ex.Message}");
|
||||||
Console.WriteLine($"当前工作目录: {Directory.GetCurrentDirectory()}");
|
Console.WriteLine($"当前工作目录: {Directory.GetCurrentDirectory()}");
|
||||||
Console.WriteLine("请确保serverlist.txt每行格式为: 版本名:下载URL (版本名可以包含空格),支持以#开头的注释");
|
Console.WriteLine("请确保serverlist.txt每行格式为: 版本名:下载URL (版本名可以包含空格),支持以#开头的注释");
|
||||||
|
LogMain.Error($"加载版本列表失败: {ex.Message}");
|
||||||
|
LogMain.Error($"当前工作目录: {Directory.GetCurrentDirectory()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisplayAllVersions()
|
public void DisplayAllVersions()
|
||||||
{
|
{
|
||||||
Console.WriteLine("可用版本列表:");
|
var filePath = Path.Combine("resources", "serverlist.txt");
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
Console.WriteLine("版本列表文件不存在");
|
||||||
|
LogMain.Error("版本列表文件不存在");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("可用版本列表:");
|
||||||
|
LogMain.Info("可用版本列表:");
|
||||||
foreach (var version in _versions.Keys)
|
foreach (var version in _versions.Keys)
|
||||||
{
|
{
|
||||||
Console.WriteLine(version);
|
Console.WriteLine(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetDownloadUrl(string version)
|
public string? GetDownloadUrl(string version)
|
||||||
{
|
{
|
||||||
return _versions.TryGetValue(version, out var url) ? url : null;
|
return _versions.TryGetValue(version, out var url) ? url : null;
|
||||||
}
|
}
|
||||||
|
|||||||
61
Tools/jredownload/JreDownloadProgress.cs
Normal file
61
Tools/jredownload/JreDownloadProgress.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
|
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();
|
||||||
|
LogMain.Info("JRE下载完成");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
230
Tools/jredownload/JreDownloadService.cs
Normal file
230
Tools/jredownload/JreDownloadService.cs
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
|
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} 已存在,无需重复下载");
|
||||||
|
LogMain.Info($"JRE {version} 已存在,无需重复下载");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 读取jrelist.txt获取下载链接
|
||||||
|
var downloadUrl = GetDownloadUrl(version);
|
||||||
|
if (string.IsNullOrEmpty(downloadUrl))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"找不到版本 {version} 的下载链接");
|
||||||
|
LogMain.Error($"找不到版本 {version} 的下载链接");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 下载压缩包
|
||||||
|
var progress = new JreDownloadProgress();
|
||||||
|
var tempZipPath = await DownloadJreZip(downloadUrl, version, progress);
|
||||||
|
if (string.IsNullOrEmpty(tempZipPath))
|
||||||
|
{
|
||||||
|
Console.WriteLine("下载失败");
|
||||||
|
LogMain.Error("下载失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 解压到jre文件夹
|
||||||
|
var jreFolder = Path.Combine(JreRootFolder, version);
|
||||||
|
if (!ExtractJre(tempZipPath, jreFolder))
|
||||||
|
{
|
||||||
|
Console.WriteLine("解压失败");
|
||||||
|
LogMain.Error("解压失败");
|
||||||
|
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");
|
||||||
|
LogMain.Error("找不到java.exe或javaw.exe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 生成jre.toml
|
||||||
|
CreateJreToml(version, javaExePath, javawExePath);
|
||||||
|
|
||||||
|
// 6. 清理临时文件
|
||||||
|
File.Delete(tempZipPath);
|
||||||
|
|
||||||
|
Console.WriteLine($"JRE {version} 安装完成");
|
||||||
|
LogMain.Info($"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}");
|
||||||
|
LogMain.Error($"无效的下载URL: {url}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"正在准备下载 {url}...");
|
||||||
|
LogMain.Info($"正在准备下载 {url}...");
|
||||||
|
var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var totalBytes = response.Content.Headers.ContentLength ?? 0;
|
||||||
|
Console.WriteLine($"文件总大小: {totalBytes} 字节");
|
||||||
|
LogMain.Info($"文件总大小: {totalBytes} 字节");
|
||||||
|
long bytesRead = 0;
|
||||||
|
var lastReportTime = DateTime.MinValue;
|
||||||
|
Console.WriteLine("开始下载...");
|
||||||
|
LogMain.Info("开始下载...");
|
||||||
|
|
||||||
|
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}");
|
||||||
|
LogMain.Error($"下载失败: {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}");
|
||||||
|
LogMain.Error($"解压失败: {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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Tools/log_systeam/log_creator.cs
Normal file
29
Tools/log_systeam/log_creator.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MCSJ.Tools.LogSystem
|
||||||
|
{
|
||||||
|
public static class LogCreator
|
||||||
|
{
|
||||||
|
public static string GenerateLogFileName()
|
||||||
|
{
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
return $"{now:yyyy-MM-dd-HH-mm-ss}.log";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetLogDirectory()
|
||||||
|
{
|
||||||
|
string logDir = Path.Combine(Directory.GetCurrentDirectory(), "logs");
|
||||||
|
if (!Directory.Exists(logDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(logDir);
|
||||||
|
}
|
||||||
|
return logDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetLogFilePath()
|
||||||
|
{
|
||||||
|
return Path.Combine(GetLogDirectory(), GenerateLogFileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
Tools/log_systeam/log_main.cs
Normal file
37
Tools/log_systeam/log_main.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace MCSJ.Tools.LogSystem
|
||||||
|
{
|
||||||
|
public static class LogMain
|
||||||
|
{
|
||||||
|
private static readonly object _lock = new object();
|
||||||
|
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
DEBUG,
|
||||||
|
INFO,
|
||||||
|
WARN,
|
||||||
|
ERROR,
|
||||||
|
FATAL
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Log(LogLevel level, string message)
|
||||||
|
{
|
||||||
|
string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}";
|
||||||
|
string logPath = LogCreator.GetLogFilePath();
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
File.AppendAllText(logPath, logEntry + Environment.NewLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Debug(string message) => Log(LogLevel.DEBUG, message);
|
||||||
|
public static void Info(string message) => Log(LogLevel.INFO, message);
|
||||||
|
public static void Warn(string message) => Log(LogLevel.WARN, message);
|
||||||
|
public static void Error(string message) => Log(LogLevel.ERROR, message);
|
||||||
|
public static void Fatal(string message) => Log(LogLevel.FATAL, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
74
Tools/server_management/EulaAgreer.cs
Normal file
74
Tools/server_management/EulaAgreer.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
|
namespace MCSJ.Tools.ServerManagement
|
||||||
|
{
|
||||||
|
public static class EulaAgreer
|
||||||
|
{
|
||||||
|
public static void AgreeEula()
|
||||||
|
{
|
||||||
|
LogMain.Info("开始处理EULA同意流程");
|
||||||
|
|
||||||
|
// 获取服务器列表
|
||||||
|
var servers = ServerManager.GetServerProfiles();
|
||||||
|
if (servers.Count == 0)
|
||||||
|
{
|
||||||
|
LogMain.Error("没有可用的服务器存档");
|
||||||
|
Console.WriteLine("没有可用的服务器存档");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示服务器列表供选择
|
||||||
|
LogMain.Info($"找到 {servers.Count} 个服务器存档");
|
||||||
|
Console.WriteLine("可用的服务器存档:");
|
||||||
|
for (int i = 0; i < servers.Count; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{i + 1}. {servers[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write("请选择服务器(输入编号): ");
|
||||||
|
if (!int.TryParse(Console.ReadLine(), out int serverIndex) || serverIndex < 1 || serverIndex > servers.Count)
|
||||||
|
{
|
||||||
|
LogMain.Warn($"无效的服务器选择: {serverIndex}");
|
||||||
|
Console.WriteLine("无效选择");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string selectedServer = servers[serverIndex - 1];
|
||||||
|
LogMain.Info($"用户选择了服务器: {selectedServer}");
|
||||||
|
string eulaPath = Path.Combine("profiles", selectedServer, "eula.txt");
|
||||||
|
|
||||||
|
// 检查eula文件是否存在
|
||||||
|
if (!File.Exists(eulaPath))
|
||||||
|
{
|
||||||
|
LogMain.Warn($"没有找到eula.txt文件: {eulaPath}");
|
||||||
|
Console.WriteLine("没有找到eula.txt文件");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取并修改eula文件
|
||||||
|
string eulaContent = File.ReadAllText(eulaPath);
|
||||||
|
if (eulaContent.Contains("eula=true"))
|
||||||
|
{
|
||||||
|
LogMain.Info("EULA已经同意,无需修改");
|
||||||
|
Console.WriteLine("EULA已经同意,无需修改");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eulaContent.Contains("eula=false"))
|
||||||
|
{
|
||||||
|
eulaContent = eulaContent.Replace("eula=false", "eula=true");
|
||||||
|
File.WriteAllText(eulaPath, eulaContent);
|
||||||
|
LogMain.Info("已成功同意EULA");
|
||||||
|
Console.WriteLine("已同意EULA");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMain.Error($"无效的eula.txt格式: {eulaPath}");
|
||||||
|
Console.WriteLine("无效的eula.txt格式");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
133
Tools/server_management/ScriptGenerator.cs
Normal file
133
Tools/server_management/ScriptGenerator.cs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
|
namespace MCSJ.Tools.ServerManagement
|
||||||
|
{
|
||||||
|
public static class ScriptGenerator
|
||||||
|
{
|
||||||
|
public static void GenerateScript()
|
||||||
|
{
|
||||||
|
LogMain.Info("开始生成服务器启动脚本");
|
||||||
|
|
||||||
|
// 获取服务器列表
|
||||||
|
var servers = ServerManager.GetServerProfiles();
|
||||||
|
if (servers.Count == 0)
|
||||||
|
{
|
||||||
|
LogMain.Error("没有可用的服务器存档");
|
||||||
|
Console.WriteLine("没有可用的服务器存档");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示服务器列表供选择
|
||||||
|
LogMain.Info($"找到 {servers.Count} 个服务器存档");
|
||||||
|
Console.WriteLine("可用的服务器存档:");
|
||||||
|
for (int i = 0; i < servers.Count; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{i + 1}. {servers[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write("请选择服务器(输入编号): ");
|
||||||
|
if (!int.TryParse(Console.ReadLine(), out int serverIndex) || serverIndex < 1 || serverIndex > servers.Count)
|
||||||
|
{
|
||||||
|
LogMain.Error($"无效的服务器选择: {serverIndex}");
|
||||||
|
Console.WriteLine("无效选择");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string selectedServer = servers[serverIndex - 1];
|
||||||
|
LogMain.Info($"用户选择了服务器: {selectedServer}");
|
||||||
|
string serverPath = Path.Combine("profiles", selectedServer);
|
||||||
|
|
||||||
|
// 检查JRE配置
|
||||||
|
string jreConfigPath = "setup/jre.toml";
|
||||||
|
if (!File.Exists(jreConfigPath) || new FileInfo(jreConfigPath).Length == 0)
|
||||||
|
{
|
||||||
|
LogMain.Error("没有找到有效的JRE配置");
|
||||||
|
Console.WriteLine("没有下载的JRE,请先下载JRE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析JRE配置
|
||||||
|
var jreVersions = new Dictionary<string, Dictionary<string, string>>();
|
||||||
|
string currentVersion = string.Empty;
|
||||||
|
|
||||||
|
foreach (var line in File.ReadAllLines(jreConfigPath))
|
||||||
|
{
|
||||||
|
if (line.StartsWith("[") && line.EndsWith("]"))
|
||||||
|
{
|
||||||
|
var version = line.Trim('[', ']');
|
||||||
|
currentVersion = version ?? string.Empty;
|
||||||
|
if (currentVersion != null!)
|
||||||
|
{
|
||||||
|
jreVersions[currentVersion] = new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.Contains("=") && currentVersion != null)
|
||||||
|
{
|
||||||
|
var parts = line.Split('=');
|
||||||
|
string key = parts[0].Trim();
|
||||||
|
string value = parts[1].Trim().Trim('\'');
|
||||||
|
jreVersions[currentVersion][key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jreVersions.Count == 0)
|
||||||
|
{
|
||||||
|
LogMain.Error("JRE配置文件为空");
|
||||||
|
Console.WriteLine("没有可用的JRE配置");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择JRE版本
|
||||||
|
Console.WriteLine("可用的JRE版本:");
|
||||||
|
int versionIndex = 1;
|
||||||
|
var versionList = new List<string>(jreVersions.Keys);
|
||||||
|
foreach (var version in versionList)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{versionIndex}. {version}");
|
||||||
|
versionIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write("请选择JRE版本(输入编号): ");
|
||||||
|
if (!int.TryParse(Console.ReadLine(), out int selectedVersionIndex) ||
|
||||||
|
selectedVersionIndex < 1 || selectedVersionIndex > versionList.Count)
|
||||||
|
{
|
||||||
|
Console.WriteLine("无效选择");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string selectedVersion = versionList[selectedVersionIndex - 1];
|
||||||
|
LogMain.Info($"用户选择了JRE版本: {selectedVersion}");
|
||||||
|
var versionConfig = jreVersions[selectedVersion];
|
||||||
|
|
||||||
|
if (!versionConfig.ContainsKey("java_path") || !versionConfig.ContainsKey("javaw_path"))
|
||||||
|
{
|
||||||
|
LogMain.Error($"JRE配置不完整: {selectedVersion}");
|
||||||
|
Console.WriteLine("JRE配置不完整");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择java执行方式
|
||||||
|
Console.WriteLine("选择Java执行方式:");
|
||||||
|
Console.WriteLine("1. java.exe (控制台模式)");
|
||||||
|
Console.WriteLine("2. javaw.exe (无控制台模式)");
|
||||||
|
Console.Write("请选择: ");
|
||||||
|
string javaPath = Console.ReadLine() == "1"
|
||||||
|
? Path.GetFullPath(versionConfig["java_path"])
|
||||||
|
: Path.GetFullPath(versionConfig["javaw_path"]);
|
||||||
|
|
||||||
|
// 生成启动脚本(统一使用反斜杠)
|
||||||
|
string scriptContent = $"@echo off\r\n" +
|
||||||
|
$"cd /D \"{Path.GetFullPath(serverPath).Replace('/', '\\')}\"\r\n" +
|
||||||
|
$"\"{javaPath.Replace('/', '\\')}\" -jar server.jar\r\n" +
|
||||||
|
"pause";
|
||||||
|
|
||||||
|
string scriptPath = Path.Combine(serverPath, "start.bat");
|
||||||
|
File.WriteAllText(scriptPath, scriptContent);
|
||||||
|
LogMain.Info($"成功生成启动脚本: {scriptPath}");
|
||||||
|
Console.WriteLine($"已生成启动脚本: {scriptPath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
Tools/server_management/ServerManager.cs
Normal file
71
Tools/server_management/ServerManager.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
|
namespace MCSJ.Tools.ServerManagement
|
||||||
|
{
|
||||||
|
public class ServerManager
|
||||||
|
{
|
||||||
|
private const int SERVER_MANAGEMENT_OPTION = 3;
|
||||||
|
|
||||||
|
public static void ShowMenu()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
LogMain.Info("显示服务器管理菜单");
|
||||||
|
Console.WriteLine("\n=== 服务器管理 ===");
|
||||||
|
Console.WriteLine("1. 生成启动脚本");
|
||||||
|
Console.WriteLine("2. 启动服务器");
|
||||||
|
Console.WriteLine("3. 同意eula.txt");
|
||||||
|
Console.WriteLine("4. 返回主菜单");
|
||||||
|
Console.Write("请选择: ");
|
||||||
|
|
||||||
|
var choice = Console.ReadLine();
|
||||||
|
switch (choice)
|
||||||
|
{
|
||||||
|
case "1":
|
||||||
|
LogMain.Info("用户选择: 生成启动脚本");
|
||||||
|
ScriptGenerator.GenerateScript();
|
||||||
|
break;
|
||||||
|
case "2":
|
||||||
|
LogMain.Info("用户选择: 启动服务器");
|
||||||
|
ServerStarter.StartServer();
|
||||||
|
break;
|
||||||
|
case "3":
|
||||||
|
LogMain.Info("用户选择: 同意eula.txt");
|
||||||
|
EulaAgreer.AgreeEula();
|
||||||
|
break;
|
||||||
|
case "4":
|
||||||
|
LogMain.Info("用户选择: 返回主菜单");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
LogMain.Warn($"无效菜单选项: {choice}");
|
||||||
|
Console.WriteLine("无效选项");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("\n按任意键继续...");
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<string> GetServerProfiles()
|
||||||
|
{
|
||||||
|
var profiles = new List<string>();
|
||||||
|
if (Directory.Exists("profiles"))
|
||||||
|
{
|
||||||
|
LogMain.Info("获取服务器存档列表");
|
||||||
|
foreach (var dir in Directory.GetDirectories("profiles"))
|
||||||
|
{
|
||||||
|
profiles.Add(Path.GetFileName(dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMain.Warn("服务器存档目录不存在");
|
||||||
|
}
|
||||||
|
return profiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
Tools/server_management/ServerStarter.cs
Normal file
90
Tools/server_management/ServerStarter.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
|
namespace MCSJ.Tools.ServerManagement
|
||||||
|
{
|
||||||
|
public static class ServerStarter
|
||||||
|
{
|
||||||
|
public static void StartServer()
|
||||||
|
{
|
||||||
|
LogMain.Info("开始启动服务器流程");
|
||||||
|
|
||||||
|
// 获取服务器列表
|
||||||
|
var servers = ServerManager.GetServerProfiles();
|
||||||
|
if (servers.Count == 0)
|
||||||
|
{
|
||||||
|
LogMain.Error("没有可用的服务器存档");
|
||||||
|
Console.WriteLine("没有可用的服务器存档");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示服务器列表供选择
|
||||||
|
LogMain.Info($"找到 {servers.Count} 个服务器存档");
|
||||||
|
Console.WriteLine("可用的服务器存档:");
|
||||||
|
for (int i = 0; i < servers.Count; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{i + 1}. {servers[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write("请选择服务器(输入编号): ");
|
||||||
|
if (!int.TryParse(Console.ReadLine(), out int serverIndex) || serverIndex < 1 || serverIndex > servers.Count)
|
||||||
|
{
|
||||||
|
LogMain.Warn($"无效的服务器选择: {serverIndex}");
|
||||||
|
Console.WriteLine("无效选择");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string selectedServer = servers[serverIndex - 1];
|
||||||
|
LogMain.Info($"用户选择了服务器: {selectedServer}");
|
||||||
|
string serverPath = Path.Combine("profiles", selectedServer);
|
||||||
|
string batPath = Path.Combine(serverPath, "start.bat");
|
||||||
|
|
||||||
|
// 检查启动脚本是否存在
|
||||||
|
if (!File.Exists(batPath))
|
||||||
|
{
|
||||||
|
LogMain.Warn($"没有找到启动脚本: {batPath}");
|
||||||
|
Console.WriteLine("没有找到启动脚本,请先生成脚本");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动服务器
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string fullBatPath = Path.GetFullPath(batPath);
|
||||||
|
string fullServerPath = Path.GetFullPath(serverPath);
|
||||||
|
|
||||||
|
if (!File.Exists(fullBatPath))
|
||||||
|
{
|
||||||
|
LogMain.Error($"启动脚本不存在: {fullBatPath}");
|
||||||
|
Console.WriteLine($"启动脚本不存在: {fullBatPath}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = fullBatPath,
|
||||||
|
WorkingDirectory = fullServerPath,
|
||||||
|
UseShellExecute = true,
|
||||||
|
CreateNoWindow = false
|
||||||
|
};
|
||||||
|
|
||||||
|
LogMain.Info($"启动路径: {fullBatPath}");
|
||||||
|
LogMain.Info($"工作目录: {fullServerPath}");
|
||||||
|
Console.WriteLine($"启动路径: {fullBatPath}");
|
||||||
|
Console.WriteLine($"工作目录: {fullServerPath}");
|
||||||
|
|
||||||
|
Process.Start(startInfo);
|
||||||
|
LogMain.Info($"成功启动服务器: {selectedServer}");
|
||||||
|
Console.WriteLine($"已启动服务器: {selectedServer}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogMain.Error($"启动服务器失败: {ex.Message}");
|
||||||
|
Console.WriteLine($"启动服务器失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
Tools/viewjre/JreViewer.cs
Normal file
53
Tools/viewjre/JreViewer.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using MCSJ.Tools.LogSystem;
|
||||||
|
|
||||||
|
namespace MCSJ.Tools.ViewJre
|
||||||
|
{
|
||||||
|
public class JreViewer
|
||||||
|
{
|
||||||
|
private const string SetupFolder = "setup";
|
||||||
|
private const string JreTomlFile = "jre.toml";
|
||||||
|
|
||||||
|
public void DisplayInstalledJres()
|
||||||
|
{
|
||||||
|
var tomlPath = Path.Combine(SetupFolder, JreTomlFile);
|
||||||
|
|
||||||
|
if (!File.Exists(tomlPath))
|
||||||
|
{
|
||||||
|
Console.WriteLine("没有安装任何JRE");
|
||||||
|
LogMain.Info("没有安装任何JRE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = File.ReadAllText(tomlPath);
|
||||||
|
var versions = content.Split('\n')
|
||||||
|
.Where(line => line.StartsWith("[jre."))
|
||||||
|
.Select(line => line.Split('.')[1].Split(']')[0].Trim()) // 精确提取版本号
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (versions.Count == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("没有安装任何JRE");
|
||||||
|
LogMain.Info("没有安装任何JRE");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("已安装的JRE版本:");
|
||||||
|
LogMain.Info("已安装的JRE版本:");
|
||||||
|
foreach (var version in versions)
|
||||||
|
{
|
||||||
|
Console.WriteLine(version); // 直接输出版本号,不带前缀
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"读取JRE列表失败: {ex.Message}");
|
||||||
|
LogMain.Error($"读取JRE列表失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
build.bat
Normal file
15
build.bat
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
dotnet publish MCSJ.csproj -c Release -r win-x86 --self-contained false /p:Optimize=true /p:DebugType=None
|
||||||
|
dotnet publish MCSJ.csproj -c Release -r win-x64 --self-contained false /p:Optimize=true /p:DebugType=None
|
||||||
|
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
|
||||||
|
7z a -t7z MCSJ-x64.7z MCSJ-x64
|
||||||
|
7z a -t7z MCSJ-x86.7z MCSJ-x86
|
||||||
|
7z a -tzip MCSJ-x64.zip MCSJ-x64
|
||||||
|
7z a -tzip MCSJ-x86.zip MCSJ-x86
|
||||||
|
7z a -ttar MCSJ-x64.tar MCSJ-x64
|
||||||
|
7z a -ttar MCSJ-x86.tar MCSJ-x86
|
||||||
|
rmdir /s /q MCSJ-x64
|
||||||
|
rmdir /s /q MCSJ-x86
|
||||||
5
resources/jrelist.txt
Normal file
5
resources/jrelist.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
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
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
1.21.11-pre2:https://piston-data.mojang.com/v1/objects/7f997b55094aa7754f25173aafef657449f02bec/server.jar
|
||||||
|
1.21.11-pre1:https://piston-data.mojang.com/v1/objects/1087f90b4d73209318d87aa8deecfaae24861004/server.jar
|
||||||
|
25w46a:https://piston-data.mojang.com/v1/objects/e61a72ec98fae895ef3e80b05269ae343c42fc0b/server.jar
|
||||||
|
25w45a:https://piston-data.mojang.com/v1/objects/4c0fe96ca002d7049226a740194c8d7114bd5059/server.jar
|
||||||
|
25w44a:https://piston-data.mojang.com/v1/objects/1ade1ebd6affbfed6dbfb2ce8864cf19efed07ba/server.jar
|
||||||
|
25w43a:https://piston-data.mojang.com/v1/objects/dac322a1091905430e2a6ade129a4915552455d0/server.jar
|
||||||
25w42a:https://piston-data.mojang.com/v1/objects/d9c6cfd4ba84f5080206259d2563f75796f14470/server.jar
|
25w42a:https://piston-data.mojang.com/v1/objects/d9c6cfd4ba84f5080206259d2563f75796f14470/server.jar
|
||||||
25w41a:https://piston-data.mojang.com/v1/objects/804aefaf397b417479e89144834e277ebde2ce71/server.jar
|
25w41a:https://piston-data.mojang.com/v1/objects/804aefaf397b417479e89144834e277ebde2ce71/server.jar
|
||||||
1.21.10:https://piston-data.mojang.com/v1/objects/95495a7f485eedd84ce928cef5e223b757d2f764/server.jar
|
1.21.10:https://piston-data.mojang.com/v1/objects/95495a7f485eedd84ce928cef5e223b757d2f764/server.jar
|
||||||
@@ -735,8 +741,8 @@
|
|||||||
13w38b:https://launcher.mojang.com/v1/objects/82588f79a6a61c4c4289a9dc60b7b7b3fedaead9/server.jar
|
13w38b:https://launcher.mojang.com/v1/objects/82588f79a6a61c4c4289a9dc60b7b7b3fedaead9/server.jar
|
||||||
13w38a:https://launcher.mojang.com/v1/objects/627585cdb9386e7f05cdfb8f092e5a303d4fd5f3/server.jar
|
13w38a:https://launcher.mojang.com/v1/objects/627585cdb9386e7f05cdfb8f092e5a303d4fd5f3/server.jar
|
||||||
1.6.4:https://launcher.mojang.com/v1/objects/050f93c1f3fe9e2052398f7bd6aca10c63d64a87/server.jar
|
1.6.4:https://launcher.mojang.com/v1/objects/050f93c1f3fe9e2052398f7bd6aca10c63d64a87/server.jar
|
||||||
1.6.3:https://launcher.mojang.com/v1/objects/5a4c69bdf7c4a9aa9580096805d8497ba7721e05/server.jar
|
|
||||||
13w37b:https://launcher.mojang.com/v1/objects/f6322a6791bbeabac94cbaa1cf9b779ad88b120f/server.jar
|
13w37b:https://launcher.mojang.com/v1/objects/f6322a6791bbeabac94cbaa1cf9b779ad88b120f/server.jar
|
||||||
|
1.6.3:https://launcher.mojang.com/v1/objects/5a4c69bdf7c4a9aa9580096805d8497ba7721e05/server.jar
|
||||||
13w37a:https://launcher.mojang.com/v1/objects/c3d3d936394b35f20b871b140f5a8e6079822e51/server.jar
|
13w37a:https://launcher.mojang.com/v1/objects/c3d3d936394b35f20b871b140f5a8e6079822e51/server.jar
|
||||||
13w36b:https://launcher.mojang.com/v1/objects/2b6cdcd2df82ca8f04c1c2c7d77faf4cd25151ea/server.jar
|
13w36b:https://launcher.mojang.com/v1/objects/2b6cdcd2df82ca8f04c1c2c7d77faf4cd25151ea/server.jar
|
||||||
13w36a:https://launcher.mojang.com/v1/objects/8453f031175bac1a92db000befd14f70c8df8fb7/server.jar
|
13w36a:https://launcher.mojang.com/v1/objects/8453f031175bac1a92db000befd14f70c8df8fb7/server.jar
|
||||||
@@ -765,8 +771,8 @@
|
|||||||
1.5.1:https://launcher.mojang.com/v1/objects/d07c71ee2767dabb79fb32dad8162e1b854d5324/server.jar
|
1.5.1:https://launcher.mojang.com/v1/objects/d07c71ee2767dabb79fb32dad8162e1b854d5324/server.jar
|
||||||
1.5:https://launcher.mojang.com/v1/objects/aedad5159ef56d69c5bcf77ed141f53430af43c3/server.jar
|
1.5:https://launcher.mojang.com/v1/objects/aedad5159ef56d69c5bcf77ed141f53430af43c3/server.jar
|
||||||
1.4.7:https://launcher.mojang.com/v1/objects/2f0ec8efddd2f2c674c77be9ddb370b727dec676/server.jar
|
1.4.7:https://launcher.mojang.com/v1/objects/2f0ec8efddd2f2c674c77be9ddb370b727dec676/server.jar
|
||||||
1.4.6:https://launcher.mojang.com/v1/objects/a0aeb5709af5f2c3058c1cf0dc6b110a7a61278c/server.jar
|
|
||||||
1.4.5:https://launcher.mojang.com/v1/objects/c12fd88a8233d2c517dbc8196ba2ae855f4d36ea/server.jar
|
1.4.5:https://launcher.mojang.com/v1/objects/c12fd88a8233d2c517dbc8196ba2ae855f4d36ea/server.jar
|
||||||
|
1.4.6:https://launcher.mojang.com/v1/objects/a0aeb5709af5f2c3058c1cf0dc6b110a7a61278c/server.jar
|
||||||
1.4.4:https://launcher.mojang.com/v1/objects/4215dcadb706508bf9d6d64209a0080b9cee9e71/server.jar
|
1.4.4:https://launcher.mojang.com/v1/objects/4215dcadb706508bf9d6d64209a0080b9cee9e71/server.jar
|
||||||
1.4.3:https://launcher.mojang.com/v1/objects/9be68adf6e80721975df12f2445fa24617328d18/server.jar
|
1.4.3:https://launcher.mojang.com/v1/objects/9be68adf6e80721975df12f2445fa24617328d18/server.jar
|
||||||
1.4.2:https://launcher.mojang.com/v1/objects/5be700523a729bb78ef99206fb480a63dcd09825/server.jar
|
1.4.2:https://launcher.mojang.com/v1/objects/5be700523a729bb78ef99206fb480a63dcd09825/server.jar
|
||||||
@@ -776,3 +782,57 @@
|
|||||||
1.3.1:https://launcher.mojang.com/v1/objects/82563ce498bfc1fc8a2cb5bf236f7da86a390646/server.jar
|
1.3.1:https://launcher.mojang.com/v1/objects/82563ce498bfc1fc8a2cb5bf236f7da86a390646/server.jar
|
||||||
1.3:https://launcher.mojang.com/v1/objects/cb21a9aaaf599c94dd7fa1b777b2f0cc37a776c7/server.jar
|
1.3:https://launcher.mojang.com/v1/objects/cb21a9aaaf599c94dd7fa1b777b2f0cc37a776c7/server.jar
|
||||||
1.2.5:https://launcher.mojang.com/v1/objects/d8321edc9470e56b8ad5c67bbd16beba25843336/server.jar
|
1.2.5:https://launcher.mojang.com/v1/objects/d8321edc9470e56b8ad5c67bbd16beba25843336/server.jar
|
||||||
|
paper-1.21.9-pre4:https://api.papermc.io/v2/projects/paper/versions/1.21.9-pre4/builds/22/downloads/paper-1.21.9-pre4-22.jar
|
||||||
|
paper-1.21.9-pre3:https://api.papermc.io/v2/projects/paper/versions/1.21.9-pre3/builds/12/downloads/paper-1.21.9-pre3-12.jar
|
||||||
|
paper-1.21.9-pre2:https://api.papermc.io/v2/projects/paper/versions/1.21.9-pre2/builds/7/downloads/paper-1.21.9-pre2-7.jar
|
||||||
|
paper-1.21.9:https://api.papermc.io/v2/projects/paper/versions/1.21.9/builds/59/downloads/paper-1.21.9-59.jar
|
||||||
|
paper-1.21.8:https://api.papermc.io/v2/projects/paper/versions/1.21.8/builds/60/downloads/paper-1.21.8-60.jar
|
||||||
|
paper-1.21.7:https://api.papermc.io/v2/projects/paper/versions/1.21.7/builds/32/downloads/paper-1.21.7-32.jar
|
||||||
|
paper-1.21.6:https://api.papermc.io/v2/projects/paper/versions/1.21.6/builds/48/downloads/paper-1.21.6-48.jar
|
||||||
|
paper-1.21.5:https://api.papermc.io/v2/projects/paper/versions/1.21.5/builds/114/downloads/paper-1.21.5-114.jar
|
||||||
|
paper-1.21.4:https://api.papermc.io/v2/projects/paper/versions/1.21.4/builds/232/downloads/paper-1.21.4-232.jar
|
||||||
|
paper-1.21.3:https://api.papermc.io/v2/projects/paper/versions/1.21.3/builds/83/downloads/paper-1.21.3-83.jar
|
||||||
|
paper-1.21.10:https://api.papermc.io/v2/projects/paper/versions/1.21.10/builds/115/downloads/paper-1.21.10-115.jar
|
||||||
|
paper-1.21.1:https://api.papermc.io/v2/projects/paper/versions/1.21.1/builds/133/downloads/paper-1.21.1-133.jar
|
||||||
|
paper-1.21:https://api.papermc.io/v2/projects/paper/versions/1.21/builds/130/downloads/paper-1.21-130.jar
|
||||||
|
paper-1.20.6:https://api.papermc.io/v2/projects/paper/versions/1.20.6/builds/151/downloads/paper-1.20.6-151.jar
|
||||||
|
paper-1.20.5:https://api.papermc.io/v2/projects/paper/versions/1.20.5/builds/22/downloads/paper-1.20.5-22.jar
|
||||||
|
paper-1.20.4:https://api.papermc.io/v2/projects/paper/versions/1.20.4/builds/499/downloads/paper-1.20.4-499.jar
|
||||||
|
paper-1.20.2:https://api.papermc.io/v2/projects/paper/versions/1.20.2/builds/318/downloads/paper-1.20.2-318.jar
|
||||||
|
paper-1.20.1:https://api.papermc.io/v2/projects/paper/versions/1.20.1/builds/196/downloads/paper-1.20.1-196.jar
|
||||||
|
paper-1.20:https://api.papermc.io/v2/projects/paper/versions/1.20/builds/17/downloads/paper-1.20-17.jar
|
||||||
|
paper-1.19.4:https://api.papermc.io/v2/projects/paper/versions/1.19.4/builds/550/downloads/paper-1.19.4-550.jar
|
||||||
|
paper-1.19.3:https://api.papermc.io/v2/projects/paper/versions/1.19.3/builds/448/downloads/paper-1.19.3-448.jar
|
||||||
|
paper-1.19.2:https://api.papermc.io/v2/projects/paper/versions/1.19.2/builds/307/downloads/paper-1.19.2-307.jar
|
||||||
|
paper-1.19.1:https://api.papermc.io/v2/projects/paper/versions/1.19.1/builds/111/downloads/paper-1.19.1-111.jar
|
||||||
|
paper-1.19:https://api.papermc.io/v2/projects/paper/versions/1.19/builds/81/downloads/paper-1.19-81.jar
|
||||||
|
paper-1.18.2:https://api.papermc.io/v2/projects/paper/versions/1.18.2/builds/388/downloads/paper-1.18.2-388.jar
|
||||||
|
paper-1.18.1:https://api.papermc.io/v2/projects/paper/versions/1.18.1/builds/216/downloads/paper-1.18.1-216.jar
|
||||||
|
paper-1.18:https://api.papermc.io/v2/projects/paper/versions/1.18/builds/66/downloads/paper-1.18-66.jar
|
||||||
|
paper-1.17.1:https://api.papermc.io/v2/projects/paper/versions/1.17.1/builds/411/downloads/paper-1.17.1-411.jar
|
||||||
|
paper-1.17:https://api.papermc.io/v2/projects/paper/versions/1.17/builds/79/downloads/paper-1.17-79.jar
|
||||||
|
paper-1.16.5:https://api.papermc.io/v2/projects/paper/versions/1.16.5/builds/794/downloads/paper-1.16.5-794.jar
|
||||||
|
paper-1.16.4:https://api.papermc.io/v2/projects/paper/versions/1.16.4/builds/416/downloads/paper-1.16.4-416.jar
|
||||||
|
paper-1.16.3:https://api.papermc.io/v2/projects/paper/versions/1.16.3/builds/253/downloads/paper-1.16.3-253.jar
|
||||||
|
paper-1.16.2:https://api.papermc.io/v2/projects/paper/versions/1.16.2/builds/189/downloads/paper-1.16.2-189.jar
|
||||||
|
paper-1.16.1:https://api.papermc.io/v2/projects/paper/versions/1.16.1/builds/138/downloads/paper-1.16.1-138.jar
|
||||||
|
paper-1.15.2:https://api.papermc.io/v2/projects/paper/versions/1.15.2/builds/393/downloads/paper-1.15.2-393.jar
|
||||||
|
paper-1.15.1:https://api.papermc.io/v2/projects/paper/versions/1.15.1/builds/62/downloads/paper-1.15.1-62.jar
|
||||||
|
paper-1.15:https://api.papermc.io/v2/projects/paper/versions/1.15/builds/21/downloads/paper-1.15-21.jar
|
||||||
|
paper-1.14.4:https://api.papermc.io/v2/projects/paper/versions/1.14.4/builds/245/downloads/paper-1.14.4-245.jar
|
||||||
|
paper-1.14.3:https://api.papermc.io/v2/projects/paper/versions/1.14.3/builds/134/downloads/paper-1.14.3-134.jar
|
||||||
|
paper-1.14.2:https://api.papermc.io/v2/projects/paper/versions/1.14.2/builds/107/downloads/paper-1.14.2-107.jar
|
||||||
|
paper-1.14.1:https://api.papermc.io/v2/projects/paper/versions/1.14.1/builds/50/downloads/paper-1.14.1-50.jar
|
||||||
|
paper-1.14:https://api.papermc.io/v2/projects/paper/versions/1.14/builds/17/downloads/paper-1.14-17.jar
|
||||||
|
paper-1.13.2:https://api.papermc.io/v2/projects/paper/versions/1.13.2/builds/657/downloads/paper-1.13.2-657.jar
|
||||||
|
paper-1.13.1:https://api.papermc.io/v2/projects/paper/versions/1.13.1/builds/386/downloads/paper-1.13.1-386.jar
|
||||||
|
paper-1.13-pre7:https://api.papermc.io/v2/projects/paper/versions/1.13-pre7/builds/12/downloads/paper-1.13-pre7-12.jar
|
||||||
|
paper-1.13:https://api.papermc.io/v2/projects/paper/versions/1.13/builds/173/downloads/paper-1.13-173.jar
|
||||||
|
paper-1.12.2:https://api.papermc.io/v2/projects/paper/versions/1.12.2/builds/1620/downloads/paper-1.12.2-1620.jar
|
||||||
|
paper-1.12.1:https://api.papermc.io/v2/projects/paper/versions/1.12.1/builds/1204/downloads/paper-1.12.1-1204.jar
|
||||||
|
paper-1.12:https://api.papermc.io/v2/projects/paper/versions/1.12/builds/1169/downloads/paper-1.12-1169.jar
|
||||||
|
paper-1.11.2:https://api.papermc.io/v2/projects/paper/versions/1.11.2/builds/1106/downloads/paper-1.11.2-1106.jar
|
||||||
|
paper-1.10.2:https://api.papermc.io/v2/projects/paper/versions/1.10.2/builds/918/downloads/paper-1.10.2-918.jar
|
||||||
|
paper-1.9.4:https://api.papermc.io/v2/projects/paper/versions/1.9.4/builds/775/downloads/paper-1.9.4-775.jar
|
||||||
|
paper-1.8.8:https://api.papermc.io/v2/projects/paper/versions/1.8.8/builds/445/downloads/paper-1.8.8-445.jar
|
||||||
|
paper-1.7.10:https://api.papermc.io/v2/projects/paper/versions/1.7.10/builds/2025/downloads/paper-1.7.10-2025.jar
|
||||||
Reference in New Issue
Block a user