diff --git a/CheatEnabler/CHANGELOG.md b/CheatEnabler/CHANGELOG.md index 138a541..012fece 100644 --- a/CheatEnabler/CHANGELOG.md +++ b/CheatEnabler/CHANGELOG.md @@ -1,5 +1,10 @@ ## Changlog +* 2.3.24 + + `Complete Dyson Sphere Shells instantly`: Fix a bug that may cause negative power in some cases +* 2.3.23 + + New feature: `Complete Dyson Sphere Shells instantly` + + Fix a crash when config panel is opened before game is fully loaded * 2.3.22 + Fix `Pump Anywhere` * 2.3.21 @@ -122,6 +127,11 @@ ## 更新日志 +* 2.3.24 + + `立即完成戴森壳建造`:修复了在某些情况下可能导致发电为负的问题 +* 2.3.23 + + 新功能:`立即完成戴森壳建造` + + 修复了在游戏完全加载前打开配置面板可能导致的崩溃问题 * 2.3.22 + 修复了`平地抽水` * 2.3.21 diff --git a/CheatEnabler/CheatEnabler.cs b/CheatEnabler/CheatEnabler.cs index 25c33f2..8061dd3 100644 --- a/CheatEnabler/CheatEnabler.cs +++ b/CheatEnabler/CheatEnabler.cs @@ -86,6 +86,7 @@ public class CheatEnabler : BaseUnityPlugin PlayerFunctions.Init(); PlayerPatch.Init(); DysonSpherePatch.Init(); + DysonSphereFunctions.Init(); CombatPatch.Init(); } diff --git a/CheatEnabler/CheatEnabler.csproj b/CheatEnabler/CheatEnabler.csproj index 976d27f..0f500e7 100644 --- a/CheatEnabler/CheatEnabler.csproj +++ b/CheatEnabler/CheatEnabler.csproj @@ -5,7 +5,7 @@ net472 org.soardev.cheatenabler DSP MOD - CheatEnabler - 2.3.22 + 2.3.24 true latest CheatEnabler diff --git a/CheatEnabler/DysonSphereFunctions.cs b/CheatEnabler/DysonSphereFunctions.cs new file mode 100644 index 0000000..ec7b4f9 --- /dev/null +++ b/CheatEnabler/DysonSphereFunctions.cs @@ -0,0 +1,121 @@ +using HarmonyLib; +using UXAssist.Common; + +namespace CheatEnabler; + +public static class DysonSphereFunctions +{ + public static void Init() + { + I18N.Add("You are not in any system.", "You are not in any system.", "你不在任何星系中"); + I18N.Add("There is no Dyson Sphere shell on \"{0}\".", "There is no Dyson Sphere shell on \"{0}\".", "“{0}”上没有可建造的戴森壳"); + I18N.Add("This will complete all Dyson Sphere shells on \"{0}\" instantly. Are you sure?", "This will complete all Dyson Sphere shells on \"{0}\" instantly. Are you sure?", "这将立即完成“{0}”上的所有戴森壳。你确定吗?"); + } + + public static void CompleteShellsInstantly() + { + StarData star = null; + var dysonEditor = UIRoot.instance?.uiGame?.dysonEditor; + if (dysonEditor != null && dysonEditor.gameObject.activeSelf) + { + star = dysonEditor.selection.viewStar; + } + if (star == null) + { + star = GameMain.data?.localStar; + if (star == null) + { + UIMessageBox.Show("CheatEnabler".Translate(), "You are not in any system.".Translate(), "确定".Translate(), 3, null); + return; + } + } + var dysonSphere = GameMain.data?.dysonSpheres[star.index]; + if (dysonSphere == null || dysonSphere.layerCount == 0) + { + UIMessageBox.Show("CheatEnabler".Translate(), string.Format("There is no Dyson Sphere shell on \"{0}\".".Translate(), star.displayName), "确定".Translate(), 3, null); + return; + } + + UIMessageBox.Show("CheatEnabler".Translate(), string.Format("This will complete all Dyson Sphere shells on \"{0}\" instantly. Are you sure?".Translate(), star.displayName), "取消".Translate(), "确定".Translate(), 2, null, () => + { + var totalNodeSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalNodeSP"); + var totalFrameSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalFrameSP"); + var totalCpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalCP"); + + var rocketCount = 0; + var solarSailCount = 0; + foreach (var dysonSphereLayer in dysonSphere.layersIdBased) + { + if (dysonSphereLayer == null) continue; + long totalNodeSp = 0; + long totalFrameSp = 0; + long totalCp = 0; + for (var i = dysonSphereLayer.frameCursor - 1; i >= 0; i--) + { + var dysonFrame = dysonSphereLayer.framePool[i]; + if (dysonFrame == null || dysonFrame.id != i) continue; + totalFrameSp += dysonFrame.spMax; + var spMax = dysonFrame.spMax / 2; + if (dysonFrame.spA < spMax) + { + rocketCount += spMax - dysonFrame.spA; + dysonFrame.spA = spMax; + dysonSphere.UpdateProgress(dysonFrame); + } + if (dysonFrame.spB < spMax) + { + rocketCount += spMax - dysonFrame.spB; + dysonFrame.spB = spMax; + dysonSphere.UpdateProgress(dysonFrame); + } + } + for (var i = dysonSphereLayer.nodeCursor - 1; i >= 0; i--) + { + var dysonNode = dysonSphereLayer.nodePool[i]; + if (dysonNode == null || dysonNode.id != i) continue; + dysonNode.spOrdered = 0; + dysonNode._spReq = 0; + totalNodeSp += dysonNode.spMax; + var diff = dysonNode.spMax - dysonNode.sp; + if (diff > 0) + { + rocketCount += diff; + dysonNode.sp = dysonNode.spMax; + dysonSphere.UpdateProgress(dysonNode); + } + dysonNode._cpReq = 0; + dysonNode.cpOrdered = 0; + foreach (var shell in dysonNode.shells) + { + var nodeIndex = shell.nodeIndexMap[dysonNode.id]; + var cpMax = (shell.vertsqOffset[nodeIndex + 1] - shell.vertsqOffset[nodeIndex]) * shell.cpPerVertex; + totalCp += cpMax; + diff = cpMax - shell.nodecps[nodeIndex]; + shell.nodecps[nodeIndex] = cpMax; + shell.nodecps[shell.nodecps.Length - 1] += diff; + solarSailCount += diff; + if (totalCpInfo != null) + { + shell.SetMaterialDynamicVars(); + } + } + } + + totalNodeSpInfo?.SetValue(dysonSphereLayer, totalNodeSp); + totalFrameSpInfo?.SetValue(dysonSphereLayer, totalFrameSp); + totalCpInfo?.SetValue(dysonSphereLayer, totalCp); + } + dysonSphere.CheckAutoNodes(); + + var productRegister = dysonSphere.productRegister; + if (productRegister != null) + { + lock (productRegister) + { + if (rocketCount > 0) productRegister[11902] += rocketCount; + if (solarSailCount > 0) productRegister[11903] += solarSailCount; + } + } + }); + } +} diff --git a/CheatEnabler/README.md b/CheatEnabler/README.md index 7be57e8..ec32512 100644 --- a/CheatEnabler/README.md +++ b/CheatEnabler/README.md @@ -43,6 +43,7 @@ + Skip absorption period + Quick absorb + Eject anyway + + Complete Dyson Sphere Shells instantly + Mecha/Combat: + Mecha and Drones/Fleets invicible + Buildings invicible @@ -100,6 +101,7 @@ + 跳过吸收阶段 + 快速吸收 + 全球弹射 + + 立即完成戴森壳建造 + 战斗: + 机甲和战斗无人机无敌 + 建筑无敌 diff --git a/CheatEnabler/UIConfigWindow.cs b/CheatEnabler/UIConfigWindow.cs index 1832221..3d36b89 100644 --- a/CheatEnabler/UIConfigWindow.cs +++ b/CheatEnabler/UIConfigWindow.cs @@ -61,6 +61,7 @@ public static class UIConfigWindow I18N.Add("Eject anyway", "Eject anyway", "全球弹射"); I18N.Add("Overclock Ejectors", "Overclock Ejectors (10x)", "高速弹射器(10倍射速)"); I18N.Add("Overclock Silos", "Overclock Silos (10x)", "高速发射井(10倍射速)"); + I18N.Add("Complete Dyson Sphere shells instantly", "Complete Dyson Sphere shells instantly", "立即完成戴森壳建造"); I18N.Add("Terraform without enough soil piles", "Terraform without enough soil piles", "沙土不够时依然可以整改地形"); I18N.Add("Instant teleport (like that in Sandbox mode)", "Instant teleport (like that in Sandbox mode)", "快速传送(和沙盒模式一样)"); I18N.Add("Mecha and Drones/Fleets invicible", "Mecha and Drones/Fleets invicible", "机甲和战斗无人机无敌"); @@ -204,6 +205,9 @@ public static class UIConfigWindow wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.OverclockEjectorEnabled, "Overclock Ejectors"); y += 36f; wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.OverclockSiloEnabled, "Overclock Silos"); + x = 300f; + y = 10f; + wnd.AddButton(x, y, 300f, tab4, "Complete Dyson Sphere shells instantly", 16, "button-complete-dyson-sphere-shells-instantly", DysonSphereFunctions.CompleteShellsInstantly); var tab5 = wnd.AddTab(_windowTrans, "Mecha/Combat"); x = 0f; diff --git a/CheatEnabler/package/manifest.json b/CheatEnabler/package/manifest.json index 2ae2b19..657eee7 100644 --- a/CheatEnabler/package/manifest.json +++ b/CheatEnabler/package/manifest.json @@ -1,6 +1,6 @@ { "name": "CheatEnabler", - "version_number": "2.3.22", + "version_number": "2.3.24", "website_url": "https://github.com/soarqin/DSP_Mods/tree/master/CheatEnabler", "description": "Add various cheat functions while disabling abnormal determinants / 添加一些作弊功能,同时屏蔽异常检测", "dependencies": [ diff --git a/UXAssist/CHANGELOG.md b/UXAssist/CHANGELOG.md index 1f2fa00..282adb1 100644 --- a/UXAssist/CHANGELOG.md +++ b/UXAssist/CHANGELOG.md @@ -6,11 +6,13 @@ - Quick-set item filter while right-clicking item icons in storage list on the panel + New feature: `Dyson Sphere "Auto Fast Build" speed multiplier` - Note: this only applies to `Dyson Sphere "Auto Fast Build"` in sandbox mode + + New feature: `Mod manager profile based save folder` + - Save files are stored in `Save\` folder. + - Will use original save location if matching default profile name. + `Quick build and dismantle stacking labs`: works for storages and tanks now + `Enable game window resize`: Keep window resizable on applying game options. + `Remember window position and size on last exit`: Do not resize window on applying game options if resolution related config entries are not changed. + Auto resize panel to fit content, for better support of multilanguages and mods dependent on UX Assist config panel functions. - + Fix a crash when config panel is opened before game is fully loaded * 1.1.4 + Fix `Remove some build conditions` * 1.1.3 @@ -157,12 +159,14 @@ - 打开面板时自动将鼠标指向物品设为筛选条件 - 在控制面板物流塔列表中右键点击物品图标快速设置为筛选条件 + 新功能:`戴森球自动快速建造速度倍率` - - 注意:这仅适用于沙盒模式下的`戴森球自动快速建造`功能 + - 注意:这仅适用于沙盒模式下的`戴森球自动快速建造`功能 + + 新功能:`基于mod管理器配置档案名的存档文件夹` + - 存档文件会存储在`Save\`文件夹中 + - 如果匹配默认配置档案名则使用原始存档位置 + `快速建造和拆除堆叠研究站`:现在也支持储物仓和储液罐 + `允许调整游戏窗口大小`:在应用游戏选项时保持窗口可调整大小 + `记住上次退出时的窗口位置和大小`:如果分辨率相关的配置项未改变,则在应用游戏选项时不调整窗口大小 + 自动调整面板大小适应内容,以更好地支持多语言和依赖于UX助手配置面板功能的mod - + 修复了在游戏完全加载前打开配置面板可能导致的崩溃问题 * 1.1.4 + 修复了`移除部分不影响游戏逻辑的建造条件` * 1.1.3 diff --git a/UXAssist/DysonSpherePatch.cs b/UXAssist/DysonSpherePatch.cs index 2658b88..898cd84 100644 --- a/UXAssist/DysonSpherePatch.cs +++ b/UXAssist/DysonSpherePatch.cs @@ -28,7 +28,7 @@ public static class DysonSpherePatch _totalFrameSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalFrameSP"); _totalCpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalCP"); } - + public static void Uninit() { StopEjectOnNodeComplete.Enable(false); @@ -62,6 +62,7 @@ public static class DysonSpherePatch if (pool[id].nodeLayerId != index) continue; ds.RemoveDysonRocket(id); } + ds.RemoveLayer(index); } @@ -69,10 +70,9 @@ public static class DysonSpherePatch [HarmonyPatch(typeof(DysonSwarm), nameof(DysonSwarm.AutoConstruct))] private static bool DysonSwarm_AutoConstruct_Prefix(DysonSwarm __instance) { - return false; + return __instance.dysonSphere.autoNodeCount == 0; } - [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), nameof(DysonSphere.AutoConstruct))] private static bool DysonSphere_AutoConstruct_Prefix(DysonSphere __instance) @@ -85,160 +85,160 @@ public static class DysonSpherePatch { var dysonNode = dysonSphereLayer.nodePool[j]; if (dysonNode == null || dysonNode.id != j) continue; - lock (dysonNode) + var count = dysonNode._spReq - dysonNode.spOrdered; + int todoCount; + int[] productRegister; + if (count > 0) { - var count = dysonNode._spReq - dysonNode.spOrdered; - int todoCount; - int[] productRegister; - if (count > 0) + if (count > totalCount) { - - if (count > totalCount) - { - count = totalCount; - } - - todoCount = count; - if (dysonNode.sp < dysonNode.spMax) - { - int diff; - if (dysonNode.sp + count > dysonNode.spMax) - { - diff = dysonNode.spMax - dysonNode.sp; - count -= diff; - dysonNode._spReq -= diff; - - dysonNode.sp = dysonNode.spMax; - } - else - { - diff = count; - dysonNode._spReq -= diff; - - dysonNode.sp += diff; - count = 0; - } - // Make compatible with DSPOptimizations - if (_totalNodeSpInfo != null) - _totalNodeSpInfo.SetValue(dysonSphereLayer, (long)_totalNodeSpInfo.GetValue(dysonSphereLayer) + diff - 1); - __instance.UpdateProgress(dysonNode); - } - - if (count > 0) - { - var frameCount = dysonNode.frames.Count; - var frameIndex = dysonNode.frameTurn % frameCount; - for (var i = frameCount; i > 0 && count > 0; i--) - { - var dysonFrame = dysonNode.frames[frameIndex]; - var spMax = dysonFrame.spMax >> 1; - if (dysonFrame.nodeA == dysonNode && dysonFrame.spA < spMax) - { - int diff; - if (dysonFrame.spA + count > spMax) - { - diff = spMax - dysonFrame.spA; - count -= diff; - dysonNode._spReq -= diff; - - dysonFrame.spA = spMax; - } - else - { - diff = count; - dysonNode._spReq -= diff; - - dysonFrame.spA += diff; - count = 0; - } - // Make compatible with DSPOptimizations - if (_totalFrameSpInfo != null) - _totalFrameSpInfo.SetValue(dysonSphereLayer, (long)_totalFrameSpInfo.GetValue(dysonSphereLayer) + diff - 1); - __instance.UpdateProgress(dysonFrame); - } - - if (count > 0 && dysonFrame.nodeB == dysonNode && dysonFrame.spB < spMax) - { - int diff; - if (dysonFrame.spB + count > spMax) - { - diff = spMax - dysonFrame.spB; - count -= diff; - dysonNode._spReq -= diff; - - dysonFrame.spB = spMax; - } - else - { - diff = count; - dysonNode._spReq -= diff; - - dysonFrame.spB += diff; - count = 0; - } - // Make compatible with DSPOptimizations - if (_totalFrameSpInfo != null) - _totalFrameSpInfo.SetValue(dysonSphereLayer, (long)_totalFrameSpInfo.GetValue(dysonSphereLayer) + diff - 1); - __instance.UpdateProgress(dysonFrame); - } - - frameIndex = (frameIndex + 1) % frameCount; - } - dysonNode.frameTurn = frameIndex; - } - if (dysonNode.spOrdered >= dysonNode._spReq) - { - __instance.RemoveAutoNode(dysonNode); - __instance.PickAutoNode(); - } - productRegister = __instance.productRegister; - if (productRegister != null) - { - lock (productRegister) - { - productRegister[11902] += todoCount - count; - } - } + count = totalCount; + } + + todoCount = count; + if (dysonNode.sp < dysonNode.spMax) + { + int diff; + if (dysonNode.sp + count > dysonNode.spMax) + { + diff = dysonNode.spMax - dysonNode.sp; + count -= diff; + dysonNode._spReq -= diff; + + dysonNode.sp = dysonNode.spMax; + } + else + { + diff = count; + dysonNode._spReq -= diff; + + dysonNode.sp += diff; + count = 0; + } + + // Make compatible with DSPOptimizations + if (_totalNodeSpInfo != null) + _totalNodeSpInfo.SetValue(dysonSphereLayer, (long)_totalNodeSpInfo.GetValue(dysonSphereLayer) + diff - 1); + __instance.UpdateProgress(dysonNode); } - count = dysonNode._cpReq - dysonNode.cpOrdered; if (count > 0) { - if (count > totalCount) count = totalCount; - todoCount = count; - var shellCount = dysonNode.shells.Count; - var shellIndex = dysonNode.shellTurn % shellCount; - for (var i = shellCount; i > 0 && count > 0; i--) + var frameCount = dysonNode.frames.Count; + var frameIndex = dysonNode.frameTurn % frameCount; + for (var i = frameCount; i > 0 && count > 0; i--) { - var dysonShell = dysonNode.shells[shellIndex]; - lock (dysonShell) + var dysonFrame = dysonNode.frames[frameIndex]; + var spMax = dysonFrame.spMax >> 1; + if (dysonFrame.nodeA == dysonNode && dysonFrame.spA < spMax) { - var nodeIndex = dysonShell.nodeIndexMap[dysonNode.id]; - var diff = (dysonShell.vertsqOffset[nodeIndex + 1] - dysonShell.vertsqOffset[nodeIndex]) * dysonShell.cpPerVertex - dysonShell.nodecps[nodeIndex]; - if (diff > count) - diff = count; - count -= diff; - dysonNode._cpReq -= diff; - dysonShell.nodecps[nodeIndex] += diff; - dysonShell.nodecps[dysonShell.nodecps.Length - 1] += diff; - // Make compatible with DSPOptimizations - if (_totalCpInfo != null) + int diff; + if (dysonFrame.spA + count > spMax) { - _totalCpInfo.SetValue(dysonSphereLayer, (long)_totalCpInfo.GetValue(dysonSphereLayer) + diff); - dysonShell.SetMaterialDynamicVars(); - } - } - shellIndex = (shellIndex + 1) % shellCount; - } - dysonNode.shellTurn = shellIndex; + diff = spMax - dysonFrame.spA; + count -= diff; + dysonNode._spReq -= diff; - productRegister = __instance.productRegister; - if (productRegister != null) - { - lock (productRegister) - { - productRegister[11903] += todoCount - count; + dysonFrame.spA = spMax; + } + else + { + diff = count; + dysonNode._spReq -= diff; + + dysonFrame.spA += diff; + count = 0; + } + + // Make compatible with DSPOptimizations + if (_totalFrameSpInfo != null) + _totalFrameSpInfo.SetValue(dysonSphereLayer, (long)_totalFrameSpInfo.GetValue(dysonSphereLayer) + diff - 1); + __instance.UpdateProgress(dysonFrame); } + + if (count > 0 && dysonFrame.nodeB == dysonNode && dysonFrame.spB < spMax) + { + int diff; + if (dysonFrame.spB + count > spMax) + { + diff = spMax - dysonFrame.spB; + count -= diff; + dysonNode._spReq -= diff; + + dysonFrame.spB = spMax; + } + else + { + diff = count; + dysonNode._spReq -= diff; + + dysonFrame.spB += diff; + count = 0; + } + + // Make compatible with DSPOptimizations + if (_totalFrameSpInfo != null) + _totalFrameSpInfo.SetValue(dysonSphereLayer, (long)_totalFrameSpInfo.GetValue(dysonSphereLayer) + diff - 1); + __instance.UpdateProgress(dysonFrame); + } + + frameIndex = (frameIndex + 1) % frameCount; + } + + dysonNode.frameTurn = frameIndex; + } + + if (dysonNode.spOrdered >= dysonNode._spReq) + { + __instance.RemoveAutoNode(dysonNode); + __instance.PickAutoNode(); + } + + productRegister = __instance.productRegister; + if (productRegister != null) + { + lock (productRegister) + { + productRegister[11902] += todoCount - count; + } + } + } + + count = dysonNode._cpReq - dysonNode.cpOrdered; + if (count > 0) + { + if (count > totalCount) count = totalCount; + todoCount = count; + var shellCount = dysonNode.shells.Count; + var shellIndex = dysonNode.shellTurn % shellCount; + for (var i = shellCount; i > 0 && count > 0; i--) + { + var dysonShell = dysonNode.shells[shellIndex]; + var nodeIndex = dysonShell.nodeIndexMap[dysonNode.id]; + var diff = (dysonShell.vertsqOffset[nodeIndex + 1] - dysonShell.vertsqOffset[nodeIndex]) * dysonShell.cpPerVertex - dysonShell.nodecps[nodeIndex]; + if (diff > count) + diff = count; + count -= diff; + dysonNode._cpReq -= diff; + dysonShell.nodecps[nodeIndex] += diff; + dysonShell.nodecps[dysonShell.nodecps.Length - 1] += diff; + // Make compatible with DSPOptimizations + if (_totalCpInfo != null) + { + _totalCpInfo.SetValue(dysonSphereLayer, (long)_totalCpInfo.GetValue(dysonSphereLayer) + diff); + dysonShell.SetMaterialDynamicVars(); + } + shellIndex = (shellIndex + 1) % shellCount; + } + + dysonNode.shellTurn = shellIndex; + + productRegister = __instance.productRegister; + if (productRegister != null) + { + lock (productRegister) + { + productRegister[11903] += todoCount - count; } } } @@ -329,6 +329,7 @@ public static class DysonSpherePatch } } } + _initialized = true; } @@ -464,7 +465,7 @@ public static class DysonSpherePatch ); return matcher.InstructionEnumeration(); } - + [HarmonyTranspiler] [HarmonyPatch(typeof(UIEjectorWindow), nameof(UIEjectorWindow._OnUpdate))] static IEnumerable UIEjectorWindow__OnUpdate_Transpiler(IEnumerable instructions, ILGenerator generator) @@ -498,7 +499,7 @@ public static class DysonSpherePatch private static class OnlyConstructNodes { private static Harmony _patch; - + public static void Enable(bool on) { if (on) @@ -543,4 +544,4 @@ public static class DysonSpherePatch return matcher.InstructionEnumeration(); } } -} +} \ No newline at end of file diff --git a/UXAssist/GamePatch.cs b/UXAssist/GamePatch.cs index 076d7a5..5000da3 100644 --- a/UXAssist/GamePatch.cs +++ b/UXAssist/GamePatch.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection.Emit; using BepInEx.Configuration; using HarmonyLib; @@ -13,11 +14,15 @@ public static class GamePatch private const string GameWindowClass = "UnityWndClass"; private static string _gameWindowTitle = "Dyson Sphere Program"; + public static string ProfileName { get; private set; } + public static ConfigEntry EnableWindowResizeEnabled; public static ConfigEntry LoadLastWindowRectEnabled; // public static ConfigEntry AutoSaveOptEnabled; public static ConfigEntry ConvertSavesFromPeaceEnabled; public static ConfigEntry LastWindowRect; + public static ConfigEntry ProfileBasedSaveFolderEnabled; + public static ConfigEntry DefaultProfileName; private static Harmony _gamePatch; public static void Init() @@ -39,6 +44,7 @@ public static class GamePatch arg = arg.Substring(index + profileSuffix.Length); var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle); if (wnd == IntPtr.Zero) return; + ProfileName = arg; _gameWindowTitle = $"Dyson Sphere Program - {arg}"; WinApi.SetWindowText(wnd, _gameWindowTitle); break; @@ -48,6 +54,14 @@ public static class GamePatch LoadLastWindowRectEnabled.SettingChanged += (_, _) => LoadLastWindowRect.Enable(LoadLastWindowRectEnabled.Value); // AutoSaveOptEnabled.SettingChanged += (_, _) => AutoSaveOpt.Enable(AutoSaveOptEnabled.Value); ConvertSavesFromPeaceEnabled.SettingChanged += (_, _) => ConvertSavesFromPeace.Enable(ConvertSavesFromPeaceEnabled.Value); + ProfileBasedSaveFolderEnabled.SettingChanged += (_, _) => + { + RefreshSavePath(); + }; + DefaultProfileName.SettingChanged += (_, _) => + { + RefreshSavePath(); + }; EnableWindowResize.Enable(EnableWindowResizeEnabled.Value); LoadLastWindowRect.Enable(LoadLastWindowRectEnabled.Value); // AutoSaveOpt.Enable(AutoSaveOptEnabled.Value); @@ -65,6 +79,32 @@ public static class GamePatch _gamePatch = null; } + private static void RefreshSavePath() + { + if (ProfileName == null) return; + + if (UIRoot.instance.loadGameWindow.gameObject.activeSelf) + { + UIRoot.instance.loadGameWindow._Close(); + } + if (UIRoot.instance.saveGameWindow.gameObject.activeSelf) + { + UIRoot.instance.saveGameWindow._Close(); + } + + string gameSavePath; + if (ProfileBasedSaveFolderEnabled.Value && string.Compare(DefaultProfileName.Value, ProfileName, StringComparison.OrdinalIgnoreCase) != 0) + gameSavePath = $"{GameConfig.overrideDocumentFolder}{GameConfig.gameName}/Save/{ProfileName}/"; + else + gameSavePath = $"{GameConfig.overrideDocumentFolder}{GameConfig.gameName}/Save/"; + if (string.Compare(GameConfig.gameSavePath, gameSavePath, StringComparison.OrdinalIgnoreCase) == 0) return; + GameConfig.gameSavePath = gameSavePath; + if (!Directory.Exists(GameConfig.gameSavePath)) + { + Directory.CreateDirectory(GameConfig.gameSavePath); + } + } + [HarmonyPrefix, HarmonyPatch(typeof(GameMain), nameof(GameMain.HandleApplicationQuit))] private static void GameMain_HandleApplicationQuit_Prefix() { @@ -180,7 +220,7 @@ public static class GamePatch var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle); if (wnd == IntPtr.Zero) return; var rect = LastWindowRect.Value; - if (rect.z == 0f && rect.w == 0f) return; + if (rect is { z: 0f, w: 0f }) return; var x = Mathf.RoundToInt(rect.x); var y = Mathf.RoundToInt(rect.y); WinApi.SetWindowPos(wnd, IntPtr.Zero, x, y, 0, 0, 0x0235); @@ -192,7 +232,7 @@ public static class GamePatch { if (fullscreenMode is FullScreenMode.ExclusiveFullScreen or FullScreenMode.FullScreenWindow or FullScreenMode.MaximizedWindow || GameMain.isRunning) return; var rect = LastWindowRect.Value; - if (rect.z == 0f && rect.w == 0f) return; + if (rect is { z: 0f, w: 0f }) return; var w = Mathf.RoundToInt(rect.z); var h = Mathf.RoundToInt(rect.w); width = w; @@ -213,7 +253,7 @@ public static class GamePatch var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle); if (wnd == IntPtr.Zero) return; var rect = LastWindowRect.Value; - if (rect.z == 0f && rect.w == 0f) return; + if (rect is { z: 0f, w: 0f }) return; var x = Mathf.RoundToInt(rect.x); var y = Mathf.RoundToInt(rect.y); var w = Mathf.RoundToInt(rect.z); diff --git a/UXAssist/README.md b/UXAssist/README.md index 0850956..7f5fdc1 100644 --- a/UXAssist/README.md +++ b/UXAssist/README.md @@ -21,6 +21,11 @@ - Enable game window resize - Remember window position and size on last exit - Convert Peace-Mode saves to Combat-Mode on loading + - Mod manager profile based save folder + - Save files are stored in `Save\` folder. + - Will use original save location if matching default profile name. + - Increase maximum count of Metadata Instantiations to 20000 (from 2000) + - Increase capacity of player order queue to 128 (from 16) + Planet/Factory - Sunlight at night - Remove some build conditions @@ -117,6 +122,9 @@ - 可调整游戏窗口大小(可最大化和拖动边框) - 记住上次退出时的窗口位置和大小 - 在加载和平模式存档时将其转换为战斗模式 + - 基于mod管理器配置档案名的存档文件夹 + - 存档文件会存储在`Save\`文件夹中 + - 如果匹配默认配置档案名则使用原始存档位置 - 将元数据提取的最大数量增加到20000(原来为2000) - 将玩家指令队列的容量增加到128(原来为16) + 行星/工厂 diff --git a/UXAssist/UI/MyWindow.cs b/UXAssist/UI/MyWindow.cs index b231a4e..2d7a410 100644 --- a/UXAssist/UI/MyWindow.cs +++ b/UXAssist/UI/MyWindow.cs @@ -14,9 +14,6 @@ namespace UXAssist.UI; public class MyWindow : ManualBehaviour { - private readonly Dictionary, UnityAction>> _inputFields = new(); - private readonly Dictionary _buttons = new(); - protected bool EventRegistered { get; private set; } private float _maxX; protected float MaxY; protected const float TitleHeight = 48f; @@ -141,15 +138,10 @@ public class MyWindow : ManualBehaviour } t.fontSize = fontSize; - btn.button.onClick.RemoveAllListeners(); btn.tip = null; btn.tips = new UIButton.TipSettings(); - _buttons[btn] = onClick; - if (EventRegistered) - { - if (onClick != null) - btn.button.onClick.AddListener(onClick); - } + btn.button.onClick.RemoveAllListeners(); + if (onClick != null) btn.button.onClick.AddListener(onClick); _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); @@ -184,11 +176,7 @@ public class MyWindow : ManualBehaviour } btn.button.onClick.RemoveAllListeners(); - _buttons[btn] = onClick; - if (EventRegistered && onClick != null) - { - btn.button.onClick.AddListener(onClick); - } + if (onClick != null) btn.button.onClick.AddListener(onClick); _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); @@ -305,67 +293,39 @@ public class MyWindow : ManualBehaviour inputField.GetComponent().color = new Color(1f, 1f, 1f, 0.05f); var rect = Util.NormalizeRectWithTopLeft(inputField, x, y, parent); rect.sizeDelta = new Vector2(210, rect.sizeDelta.y); - inputField.textComponent.text = text; + inputField.text = text; inputField.textComponent.fontSize = fontSize; + inputField.onValueChanged.RemoveAllListeners(); + if (onChanged != null) inputField.onValueChanged.AddListener(onChanged); inputField.onEndEdit.RemoveAllListeners(); - _inputFields[inputField] = Tuple.Create(onChanged, onEditEnd); - if (EventRegistered) - { - if (onChanged != null) - inputField.onValueChanged.AddListener(onChanged); - if (onEditEnd != null) - inputField.onEndEdit.AddListener(onEditEnd); - } + if (onEditEnd != null) inputField.onEndEdit.AddListener(onEditEnd); _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); return inputField; } - - public override void _OnRegEvent() + + public InputField AddInputField(float x, float y, float width, RectTransform parent, ConfigEntry config, int fontSize = 16, string objName = "input") { - base._OnRegEvent(); - if (EventRegistered) return; - foreach (var t in _inputFields) - { - var inputField = t.Key; - if (t.Value.Item1 != null) - inputField.onValueChanged.AddListener(t.Value.Item1); - if (t.Value.Item2 != null) - inputField.onEndEdit.AddListener(t.Value.Item2); - } + var stationWindow = UIRoot.instance.uiGame.stationWindow; + //public InputField nameInput; + var inputField = Instantiate(stationWindow.nameInput); + inputField.gameObject.name = objName; + Destroy(inputField.GetComponent()); + inputField.GetComponent().color = new Color(1f, 1f, 1f, 0.05f); + var rect = Util.NormalizeRectWithTopLeft(inputField, x, y, parent); + rect.sizeDelta = new Vector2(width, rect.sizeDelta.y); + inputField.text = config.Value; + inputField.textComponent.fontSize = fontSize; - foreach (var t in _buttons) - { - var btn = t.Key; - if (t.Value != null) - btn.button.onClick.AddListener(t.Value); - } + inputField.onValueChanged.RemoveAllListeners(); + inputField.onEndEdit.RemoveAllListeners(); + inputField.onEndEdit.AddListener(value => config.Value = value); - EventRegistered = true; - } - - public override void _OnUnregEvent() - { - base._OnUnregEvent(); - if (!EventRegistered) return; - EventRegistered = false; - foreach (var t in _buttons) - { - var btn = t.Key; - if (t.Value != null) - btn.button.onClick.RemoveListener(t.Value); - } - - foreach (var t in _inputFields) - { - var inputField = t.Key; - if (t.Value.Item1 != null) - inputField.onValueChanged.RemoveListener(t.Value.Item1); - if (t.Value.Item2 != null) - inputField.onEndEdit.RemoveListener(t.Value.Item2); - } + _maxX = Math.Max(_maxX, x + rect.sizeDelta.x); + MaxY = Math.Max(MaxY, y + rect.sizeDelta.y); + return inputField; } } @@ -411,10 +371,7 @@ public class MyWindowWithTabs : MyWindow btn.data = index; _tabs.Add(Tuple.Create(tabRect, btn)); - if (EventRegistered) - { - btn.onClick += OnTabButtonClick; - } + btn.onClick += OnTabButtonClick; MaxY = Math.Max(MaxY, y + TabHeight); return tabRect; @@ -443,32 +400,6 @@ public class MyWindowWithTabs : MyWindow _tabY += 28f; } - public override void _OnRegEvent() - { - if (!EventRegistered) - { - foreach (var t in _tabs) - { - t.Item2.onClick += OnTabButtonClick; - } - } - - base._OnRegEvent(); - } - - public override void _OnUnregEvent() - { - if (EventRegistered) - { - foreach (var t in _tabs) - { - t.Item2.onClick -= OnTabButtonClick; - } - } - - base._OnUnregEvent(); - } - protected void SetCurrentTab(int index) => OnTabButtonClick(index); private void OnTabButtonClick(int index) @@ -524,7 +455,7 @@ public static class MyWindowManager { var btn = child.GetComponentInChildren