Files
xyou f70b061d1a
CI / Go Backend (push) Canceled after 0s
feat: 项目初始化 + 3D方块世界原型 + AI助搭系统
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器

HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块

Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚

AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
2026-08-08 14:07:56 +08:00

278 lines
12 KiB
C#

using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using PCL.Core.App;
using PCL.Core.App.Localization;
using PCL.Core.Utils;
using PCL.Core.Utils.OS;
namespace PCL;
public static class UpdateManager
{
public static bool isUpdateWaitingRestart;
public static UpdatesWrapperModel remoteServer = new(new List<IUpdateSource>
{
new UpdatesMirrorChyanModel(),
new UpdatesRandomModel(new[]
{
new UpdatesMinioModel("https://s3.pysio.online/pcl2-ce/", "Pysio"),
new UpdatesMinioModel("https://staticassets.naids.com/resources/pclce/", "Naids")
}),
new UpdatesMinioModel("https://github.com/PCL-Community/PCL2_CE_Server/raw/main/", "GitHub")
});
public static bool IsCurrentVersionBeta
{
get
{
if (ModBase.versionBaseName.Contains("beta"))
return true;
return (int)Config.Update.UpdateChannel == 1;
}
}
public static UpdateEnums.VersionStatus GetVersionStatus()
{
try
{
if (IsCurrentVersionBeta && (int)Config.Update.UpdateChannel != 1)
{
var isNewerThanStable = remoteServer.IsLatest(UpdateChannel.stable,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.versionBaseName),
ModBase.versionCode);
var isBetaLatest = remoteServer.IsLatest(UpdateChannel.beta,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.versionBaseName),
ModBase.versionCode);
return isNewerThanStable && isBetaLatest
? UpdateEnums.VersionStatus.Latest
: UpdateEnums.VersionStatus.NotLatest;
}
return remoteServer.IsLatest(
IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.versionBaseName),
ModBase.versionCode)
? UpdateEnums.VersionStatus.Latest
: UpdateEnums.VersionStatus.NotLatest;
}
catch (Exception ex)
{
ModBase.Log(
ex,
Lang.Text("Update.Check.Failed"),
ModBase.LogLevel.Hint,
userSummary: Lang.Text("Update.Check.Failed"));
return UpdateEnums.VersionStatus.Unknown;
}
}
public static ModLoader.LoaderCombo<JsonObject> updateLoader;
public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = null, bool forceValidated = false)
{
var dlTargetPath = ModBase.exePath + @"PCL\Plain Craft Launcher Community Edition.exe";
ModBase.RunInNewThread(() =>
{
try
{
var version = remoteServer.GetLatestVersion(
IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64
);
ModBase.WriteFile($"{ModBase.pathTemp}CEUpdateLog.md", version.Changelog);
ModBase.Log($"[Update] 远程最新版本: {version.VersionName}, 当前版本: {ModBase.versionBaseName}");
if (!(SemVer.Parse(version.VersionName) > SemVer.Parse(ModBase.versionBaseName)))
return;
if (type == UpdateEnums.UpdateType.PromptOnly)
{
ModBase.RunInUi(() =>
{
if (ModMain.MyMsgBox(
Lang.Text("Update.Available", ModBase.versionBaseName, version.VersionName),
Lang.Text("Update.Title"),
Lang.Text("Update.Action"),
Lang.Text("Common.Action.Cancel")
) == 1)
ModMain.frmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupUpdate);
});
return;
// 构造步骤加载器
}
var loaders = new List<ModLoader.LoaderBase>();
// 下载
loaders.AddRange(remoteServer.GetDownloadLoader(
IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, dlTargetPath));
loaders.Add(new ModLoader.LoaderTask<int, int>(Lang.Text("Update.Task.Check"), _ =>
{
var curHash = ModBase.GetFileSHA256(dlTargetPath);
if ((curHash ?? "") != (version.Sha256 ?? ""))
throw new Exception(Lang.Text("Update.Error.Sha256Mismatch", version.Sha256, curHash));
}));
if (type == UpdateEnums.UpdateType.UpdateNow)
loaders.Add(new ModLoader.LoaderTask<int, int>(Lang.Text("Update.Task.Install"), _ => UpdateRestart(true)));
else if (type == UpdateEnums.UpdateType.Silent)
loaders.Add(new ModLoader.LoaderTask<int, int>(Lang.Text("Update.Task.Prepare"), _ => isUpdateWaitingRestart = true));
else if (type == UpdateEnums.UpdateType.DownloadAndPrompt)
loaders.Add(new ModLoader.LoaderTask<int, int>(Lang.Text("Update.Task.ShowButton"), _ =>
{
isUpdateWaitingRestart = true;
ModBase.RunInUi(() =>
{
ModMain.frmMain.BtnExtraUpdateRestart.ToolTip =
Lang.Text("Main.Extra.UpdateRestart.ToolTipWithVersion", ModBase.versionBaseName, version.VersionName);
ModMain.frmMain.BtnExtraUpdateRestart.ShowRefresh();
ModMain.frmMain.BtnExtraUpdateRestart.Ribble();
});
})
{
show = false
});
loaders.Add(new ModLoader.LoaderTask<int, int>(Lang.Text("Update.Task.RefreshSettings"), _ =>
{
if (ModMain.frmSetupUpdate is not null)
ModBase.RunInUi(() =>
{
ModMain.frmSetupUpdate.BtnUpdate.Text = Lang.Text("Update.Task.RestartInstall");
ModMain.frmSetupUpdate.BtnUpdate.IsEnabled = true;
});
})
{
show = false
});
// 启动
updateLoader = new ModLoader.LoaderCombo<JsonObject>(Lang.Text("Update.Title"), loaders);
updateLoader.Start();
if (type == UpdateEnums.UpdateType.UpdateNow)
{
ModLoader.LoaderTaskbarAdd(updateLoader);
ModMain.frmMain.BtnExtraDownload.ShowRefresh();
ModMain.frmMain.BtnExtraDownload.Ribble();
}
}
catch (Exception ex)
{
ModBase.Log(ex, "[Update] 获取启动器更新失败");
if (type != UpdateEnums.UpdateType.Silent)
HintService.Hint(Lang.Text("Update.Error.FetchFailed"), HintType.Error);
}
});
}
public static void UpdateRestart(bool triggerRestartAndByEnd, bool triggerRestart = true)
{
try
{
var fileName = ModBase.exePath + @"PCL\Plain Craft Launcher Community Edition.exe";
if (!File.Exists(fileName))
{
ModBase.Log("[System] 更新失败:未找到更新文件");
return;
}
// id old new restart
var text =
$"update {Process.GetCurrentProcess().Id} \"{Basics.ExecutablePath}\" \"{fileName}\" {(triggerRestart ? "true" : "false")}";
ModBase.Log("[System] 更新程序启动,参数:" + text);
Process.Start(new ProcessStartInfo(fileName)
{ WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, Arguments = text });
if (triggerRestartAndByEnd)
{
ModMain.frmMain.EndProgram(false, true);
ModBase.Log("[System] 已由于更新强制结束程序");
}
}
catch (Win32Exception ex)
{
ModBase.Log(ex, "自动更新时触发 Win32 错误,疑似被拦截");
ModMain.MyMsgBox(
Lang.Text("Update.Error.UpdateBlockedMessage", ModBase.exePath),
Lang.Text("Update.Error.UpdateBlocked"),
Lang.Text("Common.Action.Confirm"),
"",
"",
true);
}
}
/// <summary>
/// 确保 PathTemp 下的 Latest.exe 是最新正式版的 PCL,它会被用于整合包打包。
/// 如果不是,则下载一个。
/// </summary>
internal static void DownloadLatestPCL(ModLoader.LoaderBase loaderToSyncProgress = null)
{
// 注意:如果要自行实现这个功能,请换用另一个文件路径,以免与官方版本冲突
var latestPCLPath = Path.Combine(ModBase.pathTemp, "CE-Latest.exe");
var target = remoteServer.GetLatestVersion(UpdateChannel.stable,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64);
if (target is null)
throw new Exception(Lang.Text("Update.Error.UnableToGetUpdate"));
if (File.Exists(latestPCLPath) && (ModBase.GetFileSHA256(latestPCLPath) ?? "") == (target.Sha256 ?? ""))
{
ModBase.Log("[System] 最新版 PCL 已存在,跳过下载");
return;
}
if ((ModBase.GetFileSHA256(Basics.ExecutablePath) ?? "") == (target.Sha256 ?? "")) // 正在使用的版本符合要求,直接拿来用
{
ModBase.CopyFile(Basics.ExecutablePath, latestPCLPath);
return;
}
var loaders = remoteServer.GetDownloadLoader(UpdateChannel.stable,
SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, latestPCLPath);
var loader = new ModLoader.LoaderCombo<int>(Lang.Text("Update.Task.DownloadLatestStable"), loaders);
loader.Start();
loader.WaitForExit();
}
public static ModLoader.LoaderTask<int, int> serverLoader =
new(Lang.Text("Update.Service.PclCe"),
_ => LoadOnlineInfo(),
priority: ThreadPriority.BelowNormal);
private static void LoadOnlineInfo()
{
ScheduleBasedOnConfig();
AnnouncementService.Load();
}
private static void ScheduleBasedOnConfig()
{
switch (Config.Update.UpdateMode)
{
case LauncherAutoUpdateBehavior.DownloadAndInstall:
ModBase.Log("[Update] 更新设置: 自动下载并安装更新");
if (GetVersionStatus() != UpdateEnums.VersionStatus.Latest)
UpdateStart(UpdateEnums.UpdateType.Silent);
break;
case LauncherAutoUpdateBehavior.DownloadAndAnnounce:
ModBase.Log("[Update] 更新设置: 自动下载并提示更新");
UpdateStart(UpdateEnums.UpdateType.DownloadAndPrompt);
break;
case LauncherAutoUpdateBehavior.AnnounceOnly:
ModBase.Log("[Update] 更新设置: 提示更新");
UpdateStart(UpdateEnums.UpdateType.PromptOnly);
break;
default:
ModBase.Log("[Update] 更新设置: 不自动检查更新");
return;
}
}
/// <summary>
/// 展示社区版提示
/// </summary>
/// <param name="IsUpdate">是否为更新时启动</param>
public static void ShowCEAnnounce()
{
ModMain.MyMsgBox(Lang.Text("Update.CommunityNotice.Body"),
Lang.Text("Update.CommunityNotice.Title"),
Lang.Text("Update.CommunityNotice.Confirm"));
}
}