CI / Go Backend (push) Canceled after 0s
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
637 lines
28 KiB
C#
637 lines
28 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using PCL.Core.App;
|
||
using PCL.Core.App.Localization;
|
||
using PCL.Core.UI;
|
||
using PCL.Core.Utils;
|
||
using PCL.Core.Utils.Exts;
|
||
using PCL.Network;
|
||
|
||
namespace PCL;
|
||
|
||
public static class ModInstanceList
|
||
{
|
||
#region 实例处理
|
||
|
||
public const int mcInstanceCacheVersion = 30;
|
||
|
||
private static object _McInstanceSelected_mcInstanceSelectedLast = 0; // 为 0 以保证与 Nothing 不相同,使得 UI 显示可以正常初始化
|
||
|
||
/// <summary>
|
||
/// 当前的 Minecraft 版本。
|
||
/// </summary>
|
||
public static McInstance McMcInstanceSelected
|
||
{
|
||
get => field;
|
||
set
|
||
{
|
||
if (ReferenceEquals(_McInstanceSelected_mcInstanceSelectedLast, value))
|
||
return;
|
||
field = value; // 由于有可能是 Nothing,导致无法初始化,才得这样弄一圈
|
||
_McInstanceSelected_mcInstanceSelectedLast = value;
|
||
if (value is null)
|
||
return;
|
||
// 重置缓存的 Mod 文件夹
|
||
PageDownloadCompDetail.cachedFolder.Clear();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前按卡片分类的所有版本列表。
|
||
/// </summary>
|
||
public static Dictionary<McInstanceCardType, List<PCL.McInstance>> mcInstanceList = new();
|
||
|
||
#endregion
|
||
|
||
#region 实例列表加载
|
||
|
||
/// <summary>
|
||
/// 是否要求本次加载强制刷新实例列表。
|
||
/// </summary>
|
||
public static bool mcInstanceListForceRefresh;
|
||
|
||
/// <summary>
|
||
/// 是否为本次打开 PCL 后第一次加载实例列表。
|
||
/// 这会清理所有 .pclignore 文件,而非跳过这些对应实例。
|
||
/// </summary>
|
||
private static bool _isFirstMcInstanceListLoad = true;
|
||
|
||
/// <summary>
|
||
/// 加载 Minecraft 文件夹的实例列表。
|
||
/// </summary>
|
||
public static ModLoader.LoaderTask<string, int> mcInstanceListLoader =
|
||
new("Minecraft Instance List", InitMcInstanceList) { reloadTimeout = 1 };
|
||
|
||
private static void InitMcInstanceList(ModLoader.LoaderTask<string, int> loader)
|
||
{
|
||
var path = loader.input;
|
||
try
|
||
{
|
||
// 初始化
|
||
mcInstanceList = new Dictionary<McInstanceCardType, List<PCL.McInstance>>();
|
||
var versionsPath = Path.Combine(path, "versions");
|
||
var folderList = new List<string>();
|
||
|
||
// 读取版本文件夹
|
||
if (Directory.Exists(versionsPath))
|
||
try
|
||
{
|
||
foreach (var folder in new DirectoryInfo(versionsPath).GetDirectories())
|
||
folderList.Add(folder.Name);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new Exception(Lang.Text("Minecraft.Error.CannotReadInstanceFolder", versionsPath), ex);
|
||
}
|
||
|
||
// 如果没有可用实例,清空缓存并跳过后续处理
|
||
if (!folderList.Any())
|
||
{
|
||
ModBase.WriteIni(Path.Combine(path, "PCL.ini"), "InstanceCache", "");
|
||
McMcInstanceSelected = null;
|
||
States.Game.SelectedInstance = "";
|
||
ModBase.Log("[Minecraft] 未找到可用 Minecraft 实例");
|
||
return;
|
||
}
|
||
|
||
// 根据文件夹名列表生成辨识码
|
||
var folderListHash = ModBase.GetHash(mcInstanceCacheVersion + "#" + string.Join("#", folderList));
|
||
var folderListCheck = (int)(folderListHash % (int.MaxValue - 1));
|
||
|
||
// 尝试使用缓存
|
||
var useCache = !mcInstanceListForceRefresh &&
|
||
ModBase.Val(ModBase.ReadIni(Path.Combine(path, "PCL.ini"), "InstanceCache")) ==
|
||
folderListCheck;
|
||
|
||
if (useCache)
|
||
{
|
||
var cachedResult = InitMcInstanceListWithCache(path);
|
||
if (cachedResult is not null)
|
||
mcInstanceList = cachedResult;
|
||
else
|
||
useCache = false; // 缓存无效,需要重载
|
||
}
|
||
|
||
// 如果不能使用缓存,重新加载
|
||
if (!useCache)
|
||
{
|
||
mcInstanceListForceRefresh = false;
|
||
ModBase.Log("[Minecraft] 文件夹列表变更或缓存无效,重载所有实例");
|
||
ModBase.WriteIni(Path.Combine(path, "PCL.ini"), "InstanceCache", folderListCheck.ToString());
|
||
mcInstanceList = InitMcInstanceListWithoutCache(path);
|
||
}
|
||
|
||
_isFirstMcInstanceListLoad = false;
|
||
|
||
if (loader.IsAborted)
|
||
return;
|
||
|
||
// 尝试读取已储存的选择
|
||
var savedSelection = ModBase.ReadIni(Path.Combine(path, "PCL.ini"), "Version");
|
||
if (!string.IsNullOrEmpty(savedSelection))
|
||
foreach (var card in mcInstanceList)
|
||
foreach (var instance in card.Value)
|
||
if ((instance.Name ?? "") == savedSelection && instance.state != McInstanceState.Error)
|
||
{
|
||
McMcInstanceSelected = instance;
|
||
States.Game.SelectedInstance = McMcInstanceSelected.Name;
|
||
ModBase.Log("[Minecraft] 选择该文件夹储存的 Minecraft 实例:" + McMcInstanceSelected.PathInstance);
|
||
return;
|
||
}
|
||
|
||
// 自动选择第一项
|
||
var firstInstance = mcInstanceList
|
||
.SelectMany(kv => kv.Value)
|
||
.FirstOrDefault(i => i.state != McInstanceState.Error);
|
||
|
||
if (firstInstance is not null)
|
||
{
|
||
McMcInstanceSelected = firstInstance;
|
||
States.Game.SelectedInstance = McMcInstanceSelected.Name;
|
||
ModBase.Log("[Launch] 自动选择 Minecraft 实例:" + McMcInstanceSelected.PathInstance);
|
||
}
|
||
else
|
||
{
|
||
McMcInstanceSelected = null;
|
||
States.Game.SelectedInstance = "";
|
||
ModBase.Log("[Minecraft] 未找到可用 Minecraft 实例");
|
||
}
|
||
|
||
// 调试延迟
|
||
if (Config.Debug.AddRandomDelay is bool debugDelay && debugDelay)
|
||
Thread.Sleep(RandomUtils.NextInt(200, 3000));
|
||
}
|
||
catch (ThreadInterruptedException)
|
||
{
|
||
// 中断线程时什么也不做
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ModBase.WriteIni(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); // 要求下次重新加载
|
||
ModBase.Log(
|
||
ex,
|
||
Lang.Text("Select.Instance.Error.ListLoad"),
|
||
ModBase.LogLevel.Feedback,
|
||
userSummary: Lang.Text("Select.Instance.Error.ListLoad"));
|
||
}
|
||
}
|
||
|
||
// 获取实例列表
|
||
private static Dictionary<McInstanceCardType, List<PCL.McInstance>> InitMcInstanceListWithCache(string path)
|
||
{
|
||
var results = new Dictionary<McInstanceCardType, List<PCL.McInstance>>();
|
||
try
|
||
{
|
||
var cardCount = int.Parse(ModBase.ReadIni(path + "PCL.ini", "CardCount", (-1).ToString()));
|
||
if (cardCount == -1)
|
||
return null;
|
||
for (int i = 0, loopTo = cardCount - 1; i <= loopTo; i++)
|
||
{
|
||
var cardType =
|
||
(McInstanceCardType)int.Parse(ModBase.ReadIni(path + "PCL.ini", "CardKey" + (i + 1),
|
||
"0"));
|
||
var instanceList = new List<PCL.McInstance>();
|
||
|
||
// 循环读取实例
|
||
foreach (var folder in ModBase.ReadIni(path + "PCL.ini", "CardValue" + (i + 1), ":").Split(":"))
|
||
{
|
||
if (string.IsNullOrEmpty(folder))
|
||
continue;
|
||
var versionFolder = $@"{path}versions\{folder}\";
|
||
if (File.Exists(versionFolder + ".pclignore"))
|
||
{
|
||
if (_isFirstMcInstanceListLoad)
|
||
{
|
||
ModBase.Log("[Minecraft] 清理残留的忽略项目:" + versionFolder); // #2781
|
||
File.Delete(versionFolder + ".pclignore");
|
||
}
|
||
else
|
||
{
|
||
ModBase.Log("[Minecraft] 跳过要求忽略的项目:" + versionFolder);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
try
|
||
{
|
||
// 读取单个实例
|
||
var instance = new PCL.McInstance(versionFolder);
|
||
instanceList.Add(instance);
|
||
var instanceCfg = States.Instance;
|
||
instance.Desc = instanceCfg.CustomInfo[instance.PathInstance];
|
||
|
||
if (string.IsNullOrEmpty(instance.Desc))
|
||
instance.Desc = instanceCfg.Info[instance.PathInstance];
|
||
if (!instanceCfg.LogoPathConfig.IsDefault(instance.PathInstance))
|
||
instance.Logo = instanceCfg.LogoPath[instance.PathInstance];
|
||
if (!instanceCfg.ReleaseTimeConfig.IsDefault(instance.PathInstance))
|
||
instance.releaseTime = DateTime.Parse(instanceCfg.ReleaseTime[instance.PathInstance]);
|
||
if (!instanceCfg.StateConfig.IsDefault(instance.PathInstance))
|
||
instance.state =
|
||
(McInstanceState)(int)instanceCfg.State[instance.PathInstance];
|
||
instance.IsStar = instanceCfg.Starred[instance.PathInstance];
|
||
instance.displayType =
|
||
(McInstanceCardType)(int)instanceCfg.CardType[instance.PathInstance];
|
||
if (instance.state != McInstanceState.Error &&
|
||
!instanceCfg.VanillaVersionNameConfig.IsDefault(instance.PathInstance) &&
|
||
!instanceCfg.VanillaVersionConfig
|
||
.IsDefault(instance.PathInstance)) // 旧版本可能没有这一项,导致 Instance 不加载(#643)
|
||
{
|
||
var instanceInfo = new McInstanceInfo
|
||
{
|
||
Fabric = instanceCfg.FabricVersion[instance.PathInstance],
|
||
LegacyFabric = instanceCfg.LegacyFabricVersion[instance.PathInstance],
|
||
Quilt = instanceCfg.QuiltVersion[instance.PathInstance],
|
||
Forge = instanceCfg.ForgeVersion[instance.PathInstance],
|
||
LabyMod = instanceCfg.LabyModVersion[instance.PathInstance],
|
||
NeoForge = instanceCfg.NeoForgeVersion[instance.PathInstance],
|
||
Cleanroom = instanceCfg.CleanroomVersion[instance.PathInstance],
|
||
OptiFine = instanceCfg.OptiFineVersion[instance.PathInstance],
|
||
HasLiteLoader = instanceCfg.HasLiteLoader[instance.PathInstance],
|
||
VanillaName = instanceCfg.VanillaVersionName[instance.PathInstance],
|
||
vanilla = new Version(instanceCfg.VanillaVersion[instance.PathInstance])
|
||
};
|
||
instanceInfo.HasFabric = instanceInfo.Fabric.Any();
|
||
instanceInfo.HasLegacyFabric = instanceInfo.LegacyFabric.Any();
|
||
instanceInfo.HasQuilt = instanceInfo.Quilt.Any();
|
||
instanceInfo.HasForge = instanceInfo.Forge.Any();
|
||
instanceInfo.HasNeoForge = instanceInfo.NeoForge.Any();
|
||
instanceInfo.HasCleanroom = instanceInfo.Cleanroom.Any();
|
||
instanceInfo.HasOptiFine = instanceInfo.OptiFine.Any();
|
||
instance.Info = instanceInfo;
|
||
}
|
||
|
||
// 重新检查错误实例
|
||
if (instance.state == McInstanceState.Error)
|
||
{
|
||
// 重新获取实例错误信息
|
||
var oldDesc = instance.Desc;
|
||
instance.state = McInstanceState.Original;
|
||
instance.Check();
|
||
// 校验错误原因是否改变
|
||
var customInfo = States.Instance.CustomInfo[instance.PathInstance];
|
||
if (instance.state == McInstanceState.Original || (string.IsNullOrEmpty(customInfo) &&
|
||
!((oldDesc ?? "") ==
|
||
(instance.Desc ?? ""))))
|
||
{
|
||
ModBase.Log("[Minecraft] 实例 " + instance.Name + " 的错误状态已变更,新的状态为:" + instance.Desc);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 校验未加载的实例
|
||
if (string.IsNullOrEmpty(instance.Logo))
|
||
{
|
||
ModBase.Log("[Minecraft] 实例 " + instance.Name + " 未被加载");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
catch (Exception ex)
|
||
{
|
||
ModBase.Log(ex, "读取实例加载缓存失败(" + folder + ")");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
if (instanceList.Any())
|
||
results.Add(cardType, instanceList);
|
||
}
|
||
|
||
return results;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ModBase.Log(ex, "读取实例缓存失败");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private static Dictionary<McInstanceCardType, List<PCL.McInstance>> InitMcInstanceListWithoutCache(string path)
|
||
{
|
||
var instanceList = new List<PCL.McInstance>();
|
||
|
||
#region 循环加载每个实例的信息
|
||
|
||
foreach (var folder in new DirectoryInfo(path + "versions").GetDirectories())
|
||
{
|
||
if (!folder.Exists || !folder.EnumerateFiles().Any())
|
||
{
|
||
ModBase.Log("[Minecraft] 跳过空文件夹:" + folder.FullName);
|
||
continue;
|
||
}
|
||
|
||
if ((folder.Name == "cache" || folder.Name == "BLClient" || folder.Name == "PCL") &&
|
||
!File.Exists(Path.Combine(folder.FullName, folder.Name + ".json")))
|
||
{
|
||
ModBase.Log("[Minecraft] 跳过可能不是实例文件夹的项目:" + folder.FullName);
|
||
continue;
|
||
}
|
||
|
||
var instanceFolder = folder.FullName + @"\";
|
||
if (File.Exists(instanceFolder + ".pclignore"))
|
||
{
|
||
if (_isFirstMcInstanceListLoad)
|
||
{
|
||
ModBase.Log("[Minecraft] 清理残留的忽略项目:" + instanceFolder); // #2781
|
||
try
|
||
{
|
||
File.Delete(instanceFolder + ".pclignore");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ModBase.Log(
|
||
ex,
|
||
Lang.Text("Select.Folder.Error.Cleanup", instanceFolder),
|
||
ModBase.LogLevel.Hint,
|
||
userSummary: Lang.Text("Select.Folder.Error.Cleanup", instanceFolder));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ModBase.Log("[Minecraft] 跳过要求忽略的项目:" + instanceFolder);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
var instance = new PCL.McInstance(instanceFolder);
|
||
instanceList.Add(instance);
|
||
instance.Load();
|
||
}
|
||
|
||
#endregion
|
||
|
||
var results = new Dictionary<McInstanceCardType, List<PCL.McInstance>>();
|
||
|
||
#region 将实例分类到各个卡片
|
||
|
||
try
|
||
{
|
||
// 未经过自定义的实例列表
|
||
var instanceListOriginal = new Dictionary<McInstanceCardType, List<PCL.McInstance>>();
|
||
|
||
// 单独列出收藏的实例
|
||
var staredInstances = new List<PCL.McInstance>();
|
||
foreach (var instance in instanceList.ToList())
|
||
{
|
||
if (!instance.IsStar)
|
||
continue;
|
||
if (instance.displayType == McInstanceCardType.Hidden)
|
||
continue;
|
||
staredInstances.Add(instance);
|
||
instanceList.Remove(instance);
|
||
}
|
||
|
||
if (staredInstances.Any())
|
||
instanceListOriginal.Add(McInstanceCardType.Star, staredInstances);
|
||
|
||
// 预先筛选出愚人节和错误的实例
|
||
McInstanceFilter(ref instanceList, ref instanceListOriginal, new[] { McInstanceState.Error },
|
||
McInstanceCardType.Error);
|
||
McInstanceFilter(ref instanceList, ref instanceListOriginal, new[] { McInstanceState.Fool },
|
||
McInstanceCardType.Fool);
|
||
|
||
// 筛选 API 实例
|
||
McInstanceFilter(ref instanceList, ref instanceListOriginal,
|
||
new[]
|
||
{
|
||
McInstanceState.Forge, McInstanceState.NeoForge, McInstanceState.LiteLoader, McInstanceState.Fabric,
|
||
McInstanceState.LegacyFabric, McInstanceState.Quilt, McInstanceState.Cleanroom,
|
||
McInstanceState.LabyMod
|
||
}, McInstanceCardType.API);
|
||
|
||
// 将老实例预先分类入不常用,只剩余原版、快照、OptiFine
|
||
var instanceUseful = new List<PCL.McInstance>();
|
||
var instanceRubbish = new List<PCL.McInstance>();
|
||
McInstanceFilter(ref instanceList, new[] { McInstanceState.Old }, ref instanceRubbish);
|
||
|
||
// 确认最新实例,若为快照则加入常用列表
|
||
var latestInstance = instanceList
|
||
.Where(v => v.state == McInstanceState.Original || v.state == McInstanceState.Snapshot)
|
||
.MaxOrDefault(v => v.releaseTime);
|
||
if (latestInstance is not null && latestInstance.state == McInstanceState.Snapshot)
|
||
{
|
||
instanceUseful.Add(latestInstance);
|
||
instanceList.Remove(latestInstance);
|
||
}
|
||
|
||
// 将剩余的快照全部拖进不常用列表
|
||
McInstanceFilter(ref instanceList, new[] { McInstanceState.Snapshot }, ref instanceRubbish);
|
||
|
||
// 获取每个 Drop 下最新的原版与 OptiFine
|
||
var newerInstance = new Dictionary<string, PCL.McInstance>();
|
||
var existDrops = new List<int>();
|
||
foreach (var instance in instanceList)
|
||
{
|
||
if (!instance.Info.Valid)
|
||
continue;
|
||
if (!existDrops.Contains(instance.Info.Drop))
|
||
existDrops.Add(instance.Info.Drop);
|
||
var key = instance.Info.Drop + "-" + (int)instance.state;
|
||
if (!newerInstance.ContainsKey(key))
|
||
{
|
||
newerInstance.Add(key, instance);
|
||
continue;
|
||
}
|
||
|
||
if (instance.Info.HasOptiFine)
|
||
{
|
||
if (instance.Info.OptiFineCode > newerInstance[key].Info.OptiFineCode)
|
||
newerInstance[key] = instance; // OptiFine 根据版本号判断
|
||
}
|
||
else if (instance.releaseTime > newerInstance[key].releaseTime)
|
||
{
|
||
newerInstance[key] = instance; // 原版根据发布时间判断
|
||
}
|
||
}
|
||
|
||
// 将每个 Drop 下的最常规版本加入
|
||
foreach (var drop in existDrops)
|
||
if (newerInstance.ContainsKey(drop + "-" + (int)McInstanceState.OptiFine) &&
|
||
newerInstance.ContainsKey(drop + "-" + (int)McInstanceState.Original))
|
||
{
|
||
// 同时存在 OptiFine 与原版
|
||
var vanillaInstance = newerInstance[drop + "-" + (int)McInstanceState.Original];
|
||
var optiFineInstance = newerInstance[drop + "-" + (int)McInstanceState.OptiFine];
|
||
if (vanillaInstance.Info.Drop > optiFineInstance.Info.Drop)
|
||
{
|
||
// 仅在原版比 OptiFine 更新时才加入原版
|
||
instanceUseful.Add(vanillaInstance);
|
||
instanceList.Remove(vanillaInstance);
|
||
}
|
||
|
||
instanceUseful.Add(optiFineInstance);
|
||
instanceList.Remove(optiFineInstance);
|
||
}
|
||
else if (newerInstance.ContainsKey(drop + "-" + (int)McInstanceState.OptiFine))
|
||
{
|
||
// 没有原版,直接加入 OptiFine
|
||
instanceUseful.Add(newerInstance[drop + "-" + (int)McInstanceState.OptiFine]);
|
||
instanceList.Remove(newerInstance[drop + "-" + (int)McInstanceState.OptiFine]);
|
||
}
|
||
else if (newerInstance.ContainsKey(drop + "-" + (int)McInstanceState.Original))
|
||
{
|
||
// 没有 OptiFine,直接加入原版
|
||
instanceUseful.Add(newerInstance[drop + "-" + (int)McInstanceState.Original]);
|
||
instanceList.Remove(newerInstance[drop + "-" + (int)McInstanceState.Original]);
|
||
}
|
||
|
||
// 将剩余的东西添加进去
|
||
instanceRubbish.AddRange(instanceList);
|
||
if (instanceUseful.Any())
|
||
instanceListOriginal.Add(McInstanceCardType.OriginalLike, instanceUseful);
|
||
if (instanceRubbish.Any())
|
||
instanceListOriginal.Add(McInstanceCardType.Rubbish, instanceRubbish);
|
||
|
||
// 按照自定义实例分类重新添加
|
||
foreach (var instancePair in instanceListOriginal)
|
||
foreach (var instance in instancePair.Value)
|
||
{
|
||
var realType = instance.displayType == 0 || instancePair.Key == McInstanceCardType.Star
|
||
? instancePair.Key
|
||
: instance.displayType;
|
||
if (!results.ContainsKey(realType))
|
||
results.Add(realType, new List<PCL.McInstance>());
|
||
results[realType].Add(instance);
|
||
}
|
||
}
|
||
|
||
catch (Exception ex)
|
||
{
|
||
results.Clear();
|
||
ModBase.Log(
|
||
ex,
|
||
Lang.Text("Select.Instance.Error.Classify"),
|
||
ModBase.LogLevel.Feedback,
|
||
userSummary: Lang.Text("Select.Instance.Error.Classify"));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 对卡片与实例进行排序
|
||
|
||
// 卡片排序
|
||
var sortedInstanceList = new Dictionary<McInstanceCardType, List<PCL.McInstance>>();
|
||
foreach (var sortRule in new[]
|
||
{
|
||
McInstanceCardType.Star, McInstanceCardType.API, McInstanceCardType.OriginalLike,
|
||
McInstanceCardType.Rubbish, McInstanceCardType.Fool, McInstanceCardType.Error,
|
||
McInstanceCardType.Hidden
|
||
})
|
||
if (results.ContainsKey(sortRule))
|
||
sortedInstanceList.Add(sortRule,
|
||
results[sortRule]);
|
||
results = sortedInstanceList;
|
||
|
||
// 版本排序
|
||
foreach (var cardType in new[]
|
||
{
|
||
McInstanceCardType.Star, McInstanceCardType.API, McInstanceCardType.OriginalLike,
|
||
McInstanceCardType.Rubbish, McInstanceCardType.Fool
|
||
})
|
||
{
|
||
if (!results.ContainsKey(cardType))
|
||
continue;
|
||
|
||
int getComponentCode(PCL.McInstance instance)
|
||
{
|
||
if (instance.Info.ForgelikeCode > 0)
|
||
return instance.Info.ForgelikeCode;
|
||
if (instance.Info.HasOptiFine)
|
||
return instance.Info.OptiFineCode;
|
||
return 0;
|
||
}
|
||
|
||
;
|
||
results[cardType] = SortUtils.Sort(results[cardType], (left, right) =>
|
||
{
|
||
// 发布时间
|
||
if ((left.releaseTime.Year >= 2000 || right.releaseTime.Year >= 2000) &&
|
||
left.releaseTime != right.releaseTime)
|
||
return left.releaseTime > right.releaseTime;
|
||
// 附加组件种类
|
||
if (left.Info.HasFabric != right.Info.HasFabric)
|
||
return left.Info.HasFabric;
|
||
if (left.Info.HasQuilt != right.Info.HasQuilt)
|
||
return left.Info.HasQuilt;
|
||
if (left.Info.HasLegacyFabric != right.Info.HasLegacyFabric)
|
||
return left.Info.HasLegacyFabric;
|
||
if (left.Info.HasNeoForge != right.Info.HasNeoForge)
|
||
return left.Info.HasNeoForge;
|
||
if (left.Info.HasForge != right.Info.HasForge)
|
||
return left.Info.HasForge;
|
||
if (left.Info.HasCleanroom != right.Info.HasCleanroom)
|
||
return left.Info.HasCleanroom;
|
||
if (left.Info.HasLabyMod != right.Info.HasLabyMod)
|
||
return left.Info.HasLabyMod;
|
||
if (left.Info.HasOptiFine != right.Info.HasOptiFine)
|
||
return left.Info.HasOptiFine;
|
||
if (left.Info.HasLiteLoader != right.Info.HasLiteLoader)
|
||
return left.Info.HasLiteLoader;
|
||
// 附加组件版本
|
||
if (getComponentCode(left) != getComponentCode(right))
|
||
return getComponentCode(left) > getComponentCode(right);
|
||
// 名称
|
||
return string.CompareOrdinal(left.Name, right.Name) > 0;
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 保存卡片缓存
|
||
|
||
ModBase.WriteIni(path + "PCL.ini", "CardCount", results.Count.ToString());
|
||
for (int i = 0, loopTo = results.Count - 1; i <= loopTo; i++)
|
||
{
|
||
ModBase.WriteIni(path + "PCL.ini", "CardKey" + (i + 1),
|
||
((int)results.Keys.ElementAtOrDefault(i)).ToString());
|
||
var value = "";
|
||
foreach (var Instance in results.Values.ElementAtOrDefault(i))
|
||
value += Instance.Name + ":";
|
||
ModBase.WriteIni(path + "PCL.ini", "CardValue" + (i + 1), value);
|
||
}
|
||
|
||
#endregion
|
||
|
||
return results;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 筛选特定种类的实例,并直接添加为卡片。
|
||
/// </summary>
|
||
/// <param name="instanceList">用于筛选的列表。</param>
|
||
/// <param name="formula">需要筛选出的实例类型。-2 代表隐藏的实例。</param>
|
||
/// <param name="cardType">卡片的名称。</param>
|
||
private static void McInstanceFilter(ref List<PCL.McInstance> instanceList,
|
||
ref Dictionary<McInstanceCardType, List<PCL.McInstance>> target, McInstanceState[] formula,
|
||
McInstanceCardType cardType)
|
||
{
|
||
var keepList = instanceList.Where(v => formula.Contains(v.state)).ToList();
|
||
// 加入实例列表,并从剩余中删除
|
||
if (keepList.Any())
|
||
{
|
||
target.Add(cardType, keepList);
|
||
instanceList = instanceList.Except(keepList).ToList();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 筛选特定种类的实例,并增加入一个已有列表中。
|
||
/// </summary>
|
||
/// <param name="instanceList">用于筛选的列表。</param>
|
||
/// <param name="formula">需要筛选出的实例类型。-2 代表隐藏的实例。</param>
|
||
/// <param name="keepList">传入需要增加入的列表。</param>
|
||
private static void McInstanceFilter(ref List<PCL.McInstance> instanceList, McInstanceState[] formula,
|
||
ref List<McInstance> keepList)
|
||
{
|
||
keepList.AddRange(instanceList.Where(v => formula.Contains(v.state)));
|
||
// 加入实例列表,并从剩余中删除
|
||
if (keepList.Any()) instanceList = instanceList.Except(keepList).ToList();
|
||
}
|
||
|
||
#endregion
|
||
}
|