diff --git a/UXAssist/Common/WinApi.cs b/UXAssist/Common/WinApi.cs index 19cf9bb..d3eb19e 100644 --- a/UXAssist/Common/WinApi.cs +++ b/UXAssist/Common/WinApi.cs @@ -73,4 +73,7 @@ public static class WinApi [DllImport("user32", ExactSpelling = true)] public static extern bool SetWindowPos(IntPtr hwnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags); + + [DllImport("user32", ExactSpelling = true)] + public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint); } \ No newline at end of file diff --git a/UXAssist/FactoryPatch.cs b/UXAssist/FactoryPatch.cs index 0a7e1a6..089fc1e 100644 --- a/UXAssist/FactoryPatch.cs +++ b/UXAssist/FactoryPatch.cs @@ -15,6 +15,7 @@ public static class FactoryPatch public static ConfigEntry RemoveBuildRangeLimitEnabled; public static ConfigEntry LargerAreaForUpgradeAndDismantleEnabled; public static ConfigEntry LargerAreaForTerraformEnabled; + public static ConfigEntry OffGridBuildingEnabled; private static Harmony _factoryPatch; @@ -26,12 +27,14 @@ public static class FactoryPatch RemoveBuildRangeLimitEnabled.SettingChanged += (_, _) => RemoveBuildRangeLimit.Enable(RemoveBuildRangeLimitEnabled.Value); LargerAreaForUpgradeAndDismantleEnabled.SettingChanged += (_, _) => LargerAreaForUpgradeAndDismantle.Enable(LargerAreaForUpgradeAndDismantleEnabled.Value); LargerAreaForTerraformEnabled.SettingChanged += (_, _) => LargerAreaForTerraform.Enable(LargerAreaForTerraformEnabled.Value); + OffGridBuildingEnabled.SettingChanged += (_, _) => OffGridBuilding.Enable(OffGridBuildingEnabled.Value); UnlimitInteractive.Enable(UnlimitInteractiveEnabled.Value); RemoveSomeConditionBuild.Enable(RemoveSomeConditionEnabled.Value); NightLight.Enable(NightLightEnabled.Value); RemoveBuildRangeLimit.Enable(RemoveBuildRangeLimitEnabled.Value); LargerAreaForUpgradeAndDismantle.Enable(LargerAreaForUpgradeAndDismantleEnabled.Value); LargerAreaForTerraform.Enable(LargerAreaForTerraformEnabled.Value); + OffGridBuilding.Enable(OffGridBuildingEnabled.Value); _factoryPatch ??= Harmony.CreateAndPatchAll(typeof(FactoryPatch)); } @@ -44,6 +47,7 @@ public static class FactoryPatch RemoveBuildRangeLimit.Enable(false); LargerAreaForUpgradeAndDismantle.Enable(false); LargerAreaForTerraform.Enable(false); + OffGridBuilding.Enable(false); _factoryPatch?.UnpatchSelf(); _factoryPatch = null; @@ -519,4 +523,147 @@ public static class FactoryPatch return matcher.InstructionEnumeration(); } } + + public class OffGridBuilding + { + private static Harmony _patch; + private const float SteppedRotationDegrees = 15f; + + public static void Enable(bool enable) + { + if (enable) + { + _patch ??= Harmony.CreateAndPatchAll(typeof(OffGridBuilding)); + return; + } + + _patch?.UnpatchSelf(); + _patch = null; + } + + private static void MatchIgnoreGridAndCheckIfRotatable(CodeMatcher matcher, out Label? ifBlockEntryLabel, out Label? elseBlockEntryLabel) + { + Label? thisIfBlockEntryLabel = null; + Label? thisElseBlockEntryLabel = null; + + matcher.MatchForward( + false + , new CodeMatch(ci => ci.Calls(AccessTools.PropertyGetter(typeof(VFInput), nameof(VFInput._ignoreGrid)))) + , new CodeMatch(ci => ci.Branches(out thisElseBlockEntryLabel)) + , new CodeMatch(ci => ci.IsLdarg()) + , new CodeMatch(OpCodes.Ldfld) + , new CodeMatch(OpCodes.Ldfld) + , new CodeMatch(ci => ci.LoadsConstant(EMinerType.Vein)) + , new CodeMatch(ci => ci.Branches(out thisIfBlockEntryLabel)) + , new CodeMatch(ci => ci.IsLdarg()) + , new CodeMatch(OpCodes.Ldfld) + , new CodeMatch(OpCodes.Ldfld) + , new CodeMatch(ci => ci.Branches(out _)) + ); + + ifBlockEntryLabel = thisIfBlockEntryLabel; + elseBlockEntryLabel = thisElseBlockEntryLabel; + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.UpdateRaycast))] + [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.DeterminePreviews))] + public static IEnumerable AllowOffGridConstruction(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + + MatchIgnoreGridAndCheckIfRotatable(matcher, out var entryLabel, out _); + + if (matcher.IsInvalid) + return instructions; + + matcher.Advance(2); + matcher.Insert(new CodeInstruction(OpCodes.Br, entryLabel.Value)); + + return matcher.InstructionEnumeration(); + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.DeterminePreviews))] + public static IEnumerable PreventDraggingWhenOffGrid(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + + Label? exitLabel = null; + + matcher.MatchForward( + false + , new CodeMatch(ci => ci.Branches(out exitLabel)) + , new CodeMatch(OpCodes.Ldarg_0) + , new CodeMatch(ci => ci.LoadsConstant(1)) + , new CodeMatch(ci => ci.StoresField(AccessTools.Field(typeof(BuildTool_Click), nameof(BuildTool_Click.isDragging)))) + ); + + if (matcher.IsInvalid) + return instructions; + + matcher.Advance(1); + matcher.Insert( + new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(VFInput), nameof(VFInput._ignoreGrid))) + , new CodeInstruction(OpCodes.Brtrue, exitLabel) + ); + + return matcher.InstructionEnumeration(); + } + + public static IEnumerable PatchToPerformSteppedRotate(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + + MatchIgnoreGridAndCheckIfRotatable(matcher, out var ifBlockEntryLabel, out var elseBlockEntryLabel); + + if (matcher.IsInvalid) + return instructions; + + while (!matcher.Labels.Contains(elseBlockEntryLabel.Value)) + matcher.Advance(1); + + Label? ifBlockExitLabel = null; + + matcher.MatchBack(false, new CodeMatch(ci => ci.Branches(out ifBlockExitLabel))); + + if (matcher.IsInvalid) + return instructions; + + while (!matcher.Labels.Contains(ifBlockEntryLabel.Value)) + matcher.Advance(-1); + + var instructionToClone = matcher.Instruction.Clone(); + var overwriteWith = CodeInstruction.LoadField(typeof(VFInput), nameof(VFInput.control)); + + matcher.SetAndAdvance(overwriteWith.opcode, overwriteWith.operand); + matcher.Insert(instructionToClone); + matcher.CreateLabel(out var existingEntryLabel); + matcher.InsertAndAdvance( + new CodeInstruction(OpCodes.Brfalse, existingEntryLabel) + , new CodeInstruction(OpCodes.Ldarg_0) + , CodeInstruction.Call(typeof(OffGridBuilding), nameof(OffGridBuilding.RotateStepped)) + , new CodeInstruction(OpCodes.Br, ifBlockExitLabel) + ); + + return matcher.InstructionEnumeration(); + } + + public static void RotateStepped(BuildTool_Click instance) + { + if (VFInput._rotate.onDown) + { + instance.yaw += SteppedRotationDegrees; + instance.yaw = Mathf.Repeat(instance.yaw, 360f); + instance.yaw = Mathf.Round(instance.yaw / SteppedRotationDegrees) * SteppedRotationDegrees; + } + + if (VFInput._counterRotate.onDown) + { + instance.yaw -= SteppedRotationDegrees; + instance.yaw = Mathf.Repeat(instance.yaw, 360f); + instance.yaw = Mathf.Round(instance.yaw / SteppedRotationDegrees) * SteppedRotationDegrees; + } + } + } } \ No newline at end of file diff --git a/UXAssist/GamePatch.cs b/UXAssist/GamePatch.cs index a3ecaf7..8dd5d47 100644 --- a/UXAssist/GamePatch.cs +++ b/UXAssist/GamePatch.cs @@ -60,17 +60,31 @@ public static class GamePatch private static class LoadLastWindowRect { private static Harmony _patch; + private static bool _loaded; public static void Enable(bool on) { if (on) { _patch ??= Harmony.CreateAndPatchAll(typeof(LoadLastWindowRect)); + MoveWindowPosition(); return; } _patch?.UnpatchSelf(); _patch = null; } + private static void MoveWindowPosition() + { + if (Screen.fullScreenMode is FullScreenMode.ExclusiveFullScreen or FullScreenMode.FullScreenWindow or FullScreenMode.MaximizedWindow || GameMain.isRunning) return; + var wnd = WinApi.FindWindow(GameWindowClass, GameWindowTitle); + if (wnd == IntPtr.Zero) return; + var rect = LastWindowRect.Value; + if (rect.z == 0f && rect.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); + } + [HarmonyPrefix] [HarmonyPatch(typeof(Screen), nameof(Screen.SetResolution), typeof(int), typeof(int), typeof(FullScreenMode), typeof(int))] private static void Screen_SetResolution_Prefix(ref int width, ref int height, FullScreenMode fullscreenMode) @@ -83,17 +97,29 @@ public static class GamePatch width = w; height = h; } - + [HarmonyPostfix] [HarmonyPatch(typeof(Screen), nameof(Screen.SetResolution), typeof(int), typeof(int), typeof(FullScreenMode), typeof(int))] - private static void Screen_SetResolution_Postfix() + private static void Screen_SetResolution_Postfix(FullScreenMode fullscreenMode) { + MoveWindowPosition(); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(VFPreload), "InvokeOnLoadWorkEnded")] + private static void VFPreload_InvokeOnLoadWorkEnded_Postfix() + { + if (_loaded || Screen.fullScreenMode is FullScreenMode.ExclusiveFullScreen or FullScreenMode.FullScreenWindow or FullScreenMode.MaximizedWindow) return; + _loaded = true; var wnd = WinApi.FindWindow(GameWindowClass, GameWindowTitle); if (wnd == IntPtr.Zero) return; var rect = LastWindowRect.Value; if (rect.z == 0f && rect.w == 0f) return; var x = Mathf.RoundToInt(rect.x); var y = Mathf.RoundToInt(rect.y); + var w = Mathf.RoundToInt(rect.z); + var h = Mathf.RoundToInt(rect.w); + Screen.SetResolution(w, h, false); WinApi.SetWindowPos(wnd, IntPtr.Zero, x, y, 0, 0, 0x0235); if (EnableWindowResizeEnabled.Value) WinApi.SetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE, diff --git a/UXAssist/README.md b/UXAssist/README.md index d057ba5..9d8fd6f 100644 --- a/UXAssist/README.md +++ b/UXAssist/README.md @@ -4,11 +4,14 @@ #### 一些提升用户体验的功能和补丁 ## Changlog +* 1.0.4 + + Add new function: `Off-grid building and stepped rotation` + + Fix an issue that window position not restored and can not be resized when function is enabled but game is started with different mod profiles. * 1.0.3 + Add new function: `Quick build Orbital Collectors`. + Add confirmation popup for `Re-intialize planet`, `Quick dismantle all buildings`, `Re-initialize Dyson Spheres` and `Quick dismantle Dyson Shells`. + Fix error on `Remove build count and range limit` when building a large amount of belts. - + Fix an issue that windows position not saved correctly when quit game without using in-game menu. + + Fix an issue that window position not saved correctly when quit game without using in-game menu. * 1.0.2 + Redesign config tabs, for clearer layout. + Add 2 new options: @@ -60,8 +63,12 @@ * [Dyson Sphere Program](https://store.steampowered.com/app/1366540): The great game * [Multifunction_mod](https://github.com/blacksnipebiu/Multifunction_mod): Some cheat functions * [LSTM](https://github.com/hetima/DSP_LSTM) & [PlanetFinder](https://github.com/hetima/DSP_PlanetFinder): UI implementations +* [OffGridConstruction](https://github.com/Velociraptor115-DSPModding/OffGridConstruction): Off-grid building & stepped rotation implementations ## 更新日志 +* 1.0.4 + + 添加了新功能:`脱离网格建造和小角度旋转` + + 修复了当功能启用但游戏使用不同的mod配置文件启动时窗口位置无法正确恢复和不可拖动改变大小的问题 * 1.0.3 + 添加了新功能:`快速建造轨道采集器` + 为`初始化行星`,`快速拆除所有建筑`,`初始化戴森球`和`快速拆除戴森壳`添加了确认弹窗 @@ -118,3 +125,4 @@ * [戴森球计划](https://store.steampowered.com/app/1366540): 伟大的游戏 * [BepInEx](https://bepinex.dev/): 基础模组框架 * [LSTM](https://github.com/hetima/DSP_LSTM) & [PlanetFinder](https://github.com/hetima/DSP_PlanetFinder): UI实现 +* [OffGridConstruction](https://github.com/Velociraptor115-DSPModding/OffGridConstruction): 脱离网格建造以及小角度旋转的实现 diff --git a/UXAssist/UIConfigWindow.cs b/UXAssist/UIConfigWindow.cs index d752685..255128f 100644 --- a/UXAssist/UIConfigWindow.cs +++ b/UXAssist/UIConfigWindow.cs @@ -24,6 +24,7 @@ public static class UIConfigWindow I18N.Add("Remove build range limit", "Remove build count and range limit", "移除建造数量和距离限制"); I18N.Add("Larger area for upgrade and dismantle", "Larger area for upgrade and dismantle", "范围升级和拆除的最大区域扩大"); I18N.Add("Larger area for terraform", "Larger area for terraform", "范围铺设地基的最大区域扩大"); + I18N.Add("Off-grid building and stepped rotation", "Off-grid building and stepped rotation (Hold Shift)", "脱离网格建造以及小角度旋转(按住Shift)"); I18N.Add("Enable player actions in globe view", "Enable player actions in globe view", "在行星视图中允许玩家操作"); I18N.Add("Enhanced count control for hand-make", "Enhanced count control for hand-make", "手动制造物品的数量控制改进"); I18N.Add("Enhanced count control for hand-make tips", "Maximum count is increased to 1000.\nHold Ctrl/Shift/Alt to change the count rapidly.", "最大数量提升至1000\n按住Ctrl/Shift/Alt可快速改变数量"); @@ -74,6 +75,8 @@ public static class UIConfigWindow y += 36f; MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.LargerAreaForTerraformEnabled, "Larger area for terraform"); y += 36f; + MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.OffGridBuildingEnabled, "Off-grid building and stepped rotation"); + y += 36f; MyCheckBox.CreateCheckBox(x, y, tab2, PlanetPatch.PlayerActionsInGlobeViewEnabled, "Enable player actions in globe view"); y += 36f; MyCheckBox.CreateCheckBox(x, y, tab2, PlayerPatch.EnhancedMechaForgeCountControlEnabled, "Enhanced count control for hand-make"); diff --git a/UXAssist/UXAssist.cs b/UXAssist/UXAssist.cs index 08da02a..55c563b 100644 --- a/UXAssist/UXAssist.cs +++ b/UXAssist/UXAssist.cs @@ -45,6 +45,8 @@ public class UXAssist : BaseUnityPlugin "Increase maximum area size for upgrade and dismantle to 31x31 (from 11x11)"); FactoryPatch.LargerAreaForTerraformEnabled = Config.Bind("Factory", "LargerAreaForTerraform", false, "Increase maximum area size for terraform to 30x30 (from 10x10)\nNote: this may impact game performance while using large area"); + FactoryPatch.OffGridBuildingEnabled = Config.Bind("Factory", "OffGridBuilding", false, + "Enable off grid building and stepped rotation"); PlanetFunctions.OrbitalCollectorMaxBuildCount = Config.Bind("Factory", "OCMaxBuildCount", 0, "Maximum Orbital Collectors to build once, set to 0 to build as many as possible"); PlayerPatch.EnhancedMechaForgeCountControlEnabled = Config.Bind("Player", "EnhancedMechaForgeCountControl", false, "Enhanced count control for hand-make, increases maximum of count to 1000, and you can hold Ctrl/Shift/Alt to change the count rapidly"); diff --git a/UXAssist/UXAssist.csproj b/UXAssist/UXAssist.csproj index 7f34190..1fac70c 100644 --- a/UXAssist/UXAssist.csproj +++ b/UXAssist/UXAssist.csproj @@ -4,7 +4,7 @@ net472 org.soardev.uxassist DSP MOD - UXAssist - 1.0.3 + 1.0.4 true latest UXAssist diff --git a/UXAssist/package/manifest.json b/UXAssist/package/manifest.json index 61f4563..e11d184 100644 --- a/UXAssist/package/manifest.json +++ b/UXAssist/package/manifest.json @@ -1,6 +1,6 @@ { "name": "UXAssist", - "version_number": "1.0.3", + "version_number": "1.0.4", "website_url": "https://github.com/soarqin/DSP_Mods/tree/master/UXAssist", "description": "Some functions and patches for better user experience / 一些提升用户体验的功能和补丁", "dependencies": [