From 2c4d1b8b0dbda1757d5eed308e9ce15f6784c6e5 Mon Sep 17 00:00:00 2001 From: Soar Qin Date: Wed, 4 Jun 2025 18:10:49 +0800 Subject: [PATCH] CheatEnabler: illegal dyson shell functions --- CheatEnabler/CHANGELOG.md | 8 + CheatEnabler/CheatEnabler.cs | 4 + .../Functions/DysonSphereFunctions.cs | 1118 ++++++++++++++++- CheatEnabler/Functions/PlayerFunctions.cs | 10 +- CheatEnabler/README.md | 10 + CheatEnabler/UIConfigWindow.cs | 69 +- 6 files changed, 1207 insertions(+), 12 deletions(-) diff --git a/CheatEnabler/CHANGELOG.md b/CheatEnabler/CHANGELOG.md index 55c7b5c..2896af2 100644 --- a/CheatEnabler/CHANGELOG.md +++ b/CheatEnabler/CHANGELOG.md @@ -6,6 +6,10 @@ * 2.3.31 + New feature: `Unlock Dyson Sphere max orbit radius` + `Remove metadata consumption record in current game`: Fix implementation + + Add 3 buttons for creating illegal Dyson Sphere Shells, you must enable `IllegalDysonShellFunctionsEnabled` of `DysonSphere` section in config to see them. + - `Generate an illegal dyson shell` + - `Keep max production shells and remove others` + - `Duplicate shells from that with highest production` * 2.3.30 + Fix a warning issue while `No condition build` or `No collision` is enabled. + Increase performance for `Finish build immediately` greatly on pasting large blueprints. @@ -159,6 +163,10 @@ * 2.3.31 + 新功能:`解锁戴森球最大轨道半径` + `移除当前存档的元数据消耗记录`:修复实现 + + 增加了3个用于制作仙术戴森壳的按钮,你必须在设置文件里开启`DysonSphere`分类的`IllegalDysonShellFunctionsEnabled`才能看到它们 + - `生成单层仙术戴森壳` + - `保留发电量最高的戴森壳并移除其他戴森壳` + - `从发电量最高的壳复制戴森壳` * 2.3.30 + 修复了启用`无条件建造`或`无碰撞`时的警告问题 + 粘贴大规模蓝图时大幅提升`立即完成建造`的性能表现 diff --git a/CheatEnabler/CheatEnabler.cs b/CheatEnabler/CheatEnabler.cs index 7c55603..d557f9f 100644 --- a/CheatEnabler/CheatEnabler.cs +++ b/CheatEnabler/CheatEnabler.cs @@ -87,6 +87,10 @@ public class CheatEnabler : BaseUnityPlugin "Unlock Dyson Sphere max orbit radius"); DysonSpherePatch.UnlockMaxOrbitRadiusValue = Config.Bind("DysonSphere", "MaxOrbitRadiusValue", 10_000_000f, "Unlocked Dyson Sphere max orbit radius value"); + Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled = Config.Bind("DysonSphere", "IllegalDysonShellFunctions", false, + "Enable illegal dyson shell functions"); + Functions.DysonSphereFunctions.ShellsCountForFunctions = Config.Bind("DysonSphere", "ShellsCountForFunctions", 2048, + "Shells count for various functions"); CombatPatch.MechaInvincibleEnabled = Config.Bind("Battle", "MechaInvincible", false, "Mecha and Drones/Fleets invincible"); CombatPatch.BuildingsInvincibleEnabled = Config.Bind("Battle", "BuildingsInvincible", false, diff --git a/CheatEnabler/Functions/DysonSphereFunctions.cs b/CheatEnabler/Functions/DysonSphereFunctions.cs index ba682e1..d7ca6ae 100644 --- a/CheatEnabler/Functions/DysonSphereFunctions.cs +++ b/CheatEnabler/Functions/DysonSphereFunctions.cs @@ -1,10 +1,20 @@ -using HarmonyLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BepInEx.Configuration; +using HarmonyLib; +using UnityEngine; using UXAssist.Common; namespace CheatEnabler.Functions; public static class DysonSphereFunctions { + public static ConfigEntry IllegalDysonShellFunctionsEnabled; + public static ConfigEntry ShellsCountForFunctions; + public static void Init() { I18N.Add("You are not in any system.", "You are not in any system.", "你不在任何星系中"); @@ -25,18 +35,18 @@ public static class DysonSphereFunctions star = GameMain.data?.localStar; if (star == null) { - UIMessageBox.Show("CheatEnabler".Translate(), "You are not in any system.".Translate(), "确定".Translate(), 3, null); + UIMessageBox.Show("CheatEnabler".Translate(), "You are not in any system.".Translate(), "确定".Translate(), UIMessageBox.ERROR, 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); + UIMessageBox.Show("CheatEnabler".Translate(), string.Format("There is no Dyson Sphere shell on \"{0}\".".Translate(), star.displayName), "确定".Translate(), UIMessageBox.ERROR, 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, () => + UIMessageBox.Show("CheatEnabler".Translate(), string.Format("This will complete all Dyson Sphere shells on \"{0}\" instantly. Are you sure?".Translate(), star.displayName), "取消".Translate(), "确定".Translate(), UIMessageBox.QUESTION, () => { var totalNodeSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalNodeSP"); var totalFrameSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalFrameSP"); @@ -149,4 +159,1104 @@ public static class DysonSphereFunctions } }); } + + private static DysonNode QuickAddDysonNode(this DysonSphereLayer layer, int protoId, Vector3 pos) + { + int nodeId; + if (layer.nodeRecycleCursor > 0) + { + int[] array = layer.nodeRecycle; + int num = layer.nodeRecycleCursor - 1; + layer.nodeRecycleCursor = num; + nodeId = array[num]; + } + else + { + int nodePoolIndex = layer.nodeCursor; + layer.nodeCursor = nodePoolIndex + 1; + nodeId = nodePoolIndex; + if (nodeId == layer.nodeCapacity) + { + layer.SetNodeCapacity(layer.nodeCapacity * 2); + } + } + DysonNode node = null; + if (layer.nodePool[nodeId] == null) + { + node = new DysonNode(); + layer.nodePool[nodeId] = node; + } + else + { + node = layer.nodePool[nodeId]; + node.SetEmpty(); + } + node.id = nodeId; + node.protoId = protoId; + node.layerId = layer.id; + node.pos = pos; + node.reserved = false; + node.sp = 0; + node.spMax = DysonNode.kSpPerNode; + layer.dysonSphere.AddDysonNodeRData(node, true); + return node; + } + + private static DysonFrame QuickAddDysonFrame(this DysonSphereLayer layer, int protoId, DysonNode nodeA, DysonNode nodeB, bool euler) + { + int newId; + if (layer.frameRecycleCursor > 0) + { + var array = layer.frameRecycle; + var index = layer.frameRecycleCursor - 1; + layer.frameRecycleCursor = index; + newId = array[index]; + } + else + { + var index = layer.frameCursor; + layer.frameCursor = index + 1; + newId = index; + if (newId == layer.frameCapacity) + { + layer.SetFrameCapacity(layer.frameCapacity * 2); + } + } + DysonFrame frame = layer.framePool[newId]; + if (frame == null) + { + frame = new DysonFrame(); + layer.framePool[newId] = frame; + } + else + { + frame = layer.framePool[newId]; + frame.SetEmpty(); + } + frame.id = newId; + frame.layerId = layer.id; + frame.protoId = protoId + DysonSphereSegmentRenderer.nodeProtoCount; + frame.reserved = false; + frame.nodeA = nodeA; + frame.nodeB = nodeB; + frame.euler = euler; + frame.spA = 0; + frame.spB = 0; + frame.spMax = frame.segCount * DysonFrame.kSpPerSeg; + nodeA.frames.Add(frame); + nodeB.frames.Add(frame); + return frame; + } + + private static readonly ThreadLocal> _vmap = new(() => new(16384)); + private static int CalculateTriangleVertCount(DysonNode[] nodes) + { + if (nodes.Length != 3) return -1; + VectorLF3[] polygon = [.. nodes.Select(node => node.pos)]; + VectorLF3 sum = VectorLF3.zero; + double num = 0.0; + for (int i = 0; i < 3; i++) + { + var nodeA = nodes[i]; + var nodeB = nodes[(i + 1) % 3]; + float num2 = Vector3.Distance(nodeA.pos, nodeB.pos); + VectorLF3 vectorLF2 = (VectorLF3)(nodeA.pos + nodeB.pos) * 0.5; + sum += vectorLF2 * (double)num2; + num += (double)num2; + } + var radius = polygon[0].magnitude; + radius = Math.Round(radius * 10.0) / 10.0; + for (int j = 0; j < 3; j++) + { + polygon[j] = polygon[j].normalized * radius; + } + var center = (sum / num).normalized * radius; + float num3 = 0f; + for (int k = 0; k < 3; k++) + { + float num4 = Vector3.Distance(center, polygon[k]); + if (num4 > num3) + { + num3 = num4; + } + } + var gridScale = (int)(Math.Pow(radius / 4000.0, 0.75) + 0.5); + gridScale = ((gridScale < 1) ? 1 : gridScale); + var gridSize = (float)gridScale * 80f; + var cpPerVertex = gridScale * gridScale * 2; + var num5 = (int)((double)num3 / 0.8660254037844386 / (double)gridSize + 2.5); + var xaxis = VectorLF3.Cross(center, Vector3.up).normalized; + if (xaxis.magnitude < 0.1) + { + xaxis = new VectorLF3(0f, 0f, 1f); + } + var yaxis = VectorLF3.Cross(xaxis, center).normalized; + var raydir = xaxis * 0.915662593339561 + yaxis * 0.40194777665596015; + var w1axis = xaxis * (0.5 * (double)gridSize) - yaxis * (0.8660254037844386 * (double)gridSize); + var w2axis = xaxis * (0.5 * (double)gridSize) + yaxis * (0.8660254037844386 * (double)gridSize); + var w0axis = xaxis * (double)gridSize; + double num6 = 0.5773502691896258; + var t1axis = yaxis * ((double)gridSize * num6 * 0.5) - xaxis * ((double)gridSize * 0.5); + var t2axis = yaxis * ((double)gridSize * num6 * 0.5) + xaxis * ((double)gridSize * 0.5); + var t0axis = yaxis * ((double)gridSize / 0.8660254037844386 * 0.5); + var polyn = new VectorLF3[3]; + var polynu = new double[3]; + for (int l = 0; l < 3; l++) + { + Vector3 vector = polygon[l]; + Vector3 vector2 = polygon[(l + 1) % 3]; + polyn[l] = VectorLF3.Cross(vector, vector2).normalized; + polynu[l] = polyn[l].x * raydir.x + polyn[l].y * raydir.y + polyn[l].z * raydir.z; + } + var vmap = _vmap.Value; + vmap.Clear(); + double num7 = (double)gridSize * 0.5; + for (int m = -num5; m <= num5; m++) + { + for (int n = -num5; n <= num5; n++) + { + if (m - n <= num5 && m - n >= -num5) + { + VectorLF3 vectorLF3; + vectorLF3.x = center.x + w0axis.x * (double)m - w1axis.x * (double)n; + vectorLF3.y = center.y + w0axis.y * (double)m - w1axis.y * (double)n; + vectorLF3.z = center.z + w0axis.z * (double)m - w1axis.z * (double)n; + double num8 = radius / Math.Sqrt(vectorLF3.x * vectorLF3.x + vectorLF3.y * vectorLF3.y + vectorLF3.z * vectorLF3.z); + vectorLF3.x *= num8; + vectorLF3.y *= num8; + vectorLF3.z *= num8; + int num9 = 0; + for (int num10 = 0; num10 < 3; num10++) + { + double num11 = -(polyn[num10].x * vectorLF3.x + polyn[num10].y * vectorLF3.y + polyn[num10].z * vectorLF3.z) / polynu[num10]; + if (num11 >= 0.0) + { + VectorLF3 normalized2 = new VectorLF3(vectorLF3.x + num11 * raydir.x, vectorLF3.y + num11 * raydir.y, vectorLF3.z + num11 * raydir.z).normalized; + normalized2.x *= radius; + normalized2.y *= radius; + normalized2.z *= radius; + VectorLF3 vectorLF4 = polygon[num10] - normalized2; + VectorLF3 vectorLF5 = polygon[(num10 + 1) % 3] - normalized2; + double num12 = vectorLF4.x * vectorLF5.x + vectorLF4.y * vectorLF5.y + vectorLF4.z * vectorLF5.z; + if (num12 < 0.0 || (num12 == 0.0 && vectorLF4.x == 0.0 && vectorLF4.y == 0.0 && vectorLF4.z == 0.0)) + { + num9++; + } + } + } + if ((num9 & 1) == 1) + { + int num13 = DysonShell._get_key(m, n); + vmap[num13] = vectorLF3; + } + else + { + for (int num14 = 0; num14 < 3; num14++) + { + VectorLF3 vectorLF6 = polygon[num14]; + VectorLF3 vectorLF7 = polyn[num14]; + VectorLF3 vectorLF8 = vectorLF3 - vectorLF6; + double num15 = vectorLF7.x * vectorLF8.x + vectorLF7.y * vectorLF8.y + vectorLF7.z * vectorLF8.z; + double num16 = Math.Abs(num15); + if (num16 <= num7) + { + VectorLF3 vectorLF9 = polygon[(num14 + 1) % 3]; + VectorLF3 vectorLF10 = vectorLF3 - vectorLF7 * num15; + VectorLF3 vectorLF11 = vectorLF9 - vectorLF6; + double magnitude = vectorLF11.magnitude; + VectorLF3 vectorLF12 = vectorLF11 / magnitude; + VectorLF3 vectorLF13 = vectorLF10 - vectorLF6; + double num17 = vectorLF12.x * vectorLF13.x + vectorLF12.y * vectorLF13.y + vectorLF12.z * vectorLF13.z; + double num18; + if (num17 < 0.0) + { + num18 = vectorLF8.magnitude; + } + else if (num17 > magnitude) + { + num18 = (vectorLF3 - vectorLF9).magnitude; + } + else + { + num18 = num16; + } + if (num18 <= num7) + { + int num19 = DysonShell._get_key(m, n); + vmap[num19] = vectorLF3; + break; + } + } + } + } + } + } + } + return vmap.Count; + } + + private static bool MyGenerateGeometry(this DysonShell shell) + { + VectorLF3 sum = VectorLF3.zero; + double num = 0.0; + for (int i = 0; i < shell.frames.Count; i++) + { + float num2 = Vector3.Distance(shell.frames[i].nodeA.pos, shell.frames[i].nodeB.pos); + VectorLF3 vectorLF2 = (VectorLF3)(shell.frames[i].nodeA.pos + shell.frames[i].nodeB.pos) * 0.5; + sum += vectorLF2 * (double)num2; + num += (double)num2; + } + shell.radius = shell.polygon[0].magnitude; + shell.radius = Math.Round(shell.radius * 10.0) / 10.0; + for (int j = 0; j < shell.polygon.Count; j++) + { + shell.polygon[j] = shell.polygon[j].normalized * shell.radius; + } + var normalized = (sum / num).normalized; + shell.center = normalized * shell.radius; + float num3 = 0f; + for (int k = 0; k < shell.polygon.Count; k++) + { + float num4 = Vector3.Distance(shell.center, shell.polygon[k]); + if (num4 > num3) + { + num3 = num4; + } + } + shell.gridScale = (int)(Math.Pow(shell.radius / 4000.0, 0.75) + 0.5); + shell.gridScale = ((shell.gridScale < 1) ? 1 : shell.gridScale); + shell.gridSize = (float)shell.gridScale * 80f; + shell.cpPerVertex = shell.gridScale * shell.gridScale * 2; + int num5 = (int)((double)num3 / 0.8660254037844386 / (double)shell.gridSize + 2.5); + shell.xaxis = VectorLF3.Cross(normalized, Vector3.up).normalized; + if (shell.xaxis.magnitude < 0.1) + { + shell.xaxis = new VectorLF3(0f, 0f, 1f); + } + shell.yaxis = VectorLF3.Cross(shell.xaxis, normalized).normalized; + shell.raydir = shell.xaxis * 0.915662593339561 + shell.yaxis * 0.40194777665596015; + shell.w1axis = shell.xaxis * (0.5 * (double)shell.gridSize) - shell.yaxis * (0.8660254037844386 * (double)shell.gridSize); + shell.w2axis = shell.xaxis * (0.5 * (double)shell.gridSize) + shell.yaxis * (0.8660254037844386 * (double)shell.gridSize); + shell.w0axis = shell.xaxis * (double)shell.gridSize; + double num6 = 0.5773502691896258; + shell.t1axis = shell.yaxis * ((double)shell.gridSize * num6 * 0.5) - shell.xaxis * ((double)shell.gridSize * 0.5); + shell.t2axis = shell.yaxis * ((double)shell.gridSize * num6 * 0.5) + shell.xaxis * ((double)shell.gridSize * 0.5); + shell.t0axis = shell.yaxis * ((double)shell.gridSize / 0.8660254037844386 * 0.5); + int count = shell.polygon.Count; + shell.polyn = new VectorLF3[count]; + shell.polynu = new double[count]; + for (int l = 0; l < count; l++) + { + Vector3 vector = shell.polygon[l]; + Vector3 vector2 = shell.polygon[(l + 1) % count]; + shell.polyn[l] = VectorLF3.Cross(vector, vector2).normalized; + shell.polynu[l] = shell.polyn[l].x * shell.raydir.x + shell.polyn[l].y * shell.raydir.y + shell.polyn[l].z * shell.raydir.z; + } + DysonShell.s_vmap.Clear(); + DysonShell.s_outvmap.Clear(); + DysonShell.s_ivmap.Clear(); + double num7 = (double)shell.gridSize * 0.5; + for (int m = -num5; m <= num5; m++) + { + for (int n = -num5; n <= num5; n++) + { + if (m - n <= num5 && m - n >= -num5) + { + VectorLF3 vectorLF3; + vectorLF3.x = shell.center.x + shell.w0axis.x * (double)m - shell.w1axis.x * (double)n; + vectorLF3.y = shell.center.y + shell.w0axis.y * (double)m - shell.w1axis.y * (double)n; + vectorLF3.z = shell.center.z + shell.w0axis.z * (double)m - shell.w1axis.z * (double)n; + double num8 = shell.radius / Math.Sqrt(vectorLF3.x * vectorLF3.x + vectorLF3.y * vectorLF3.y + vectorLF3.z * vectorLF3.z); + vectorLF3.x *= num8; + vectorLF3.y *= num8; + vectorLF3.z *= num8; + int num9 = 0; + for (int num10 = 0; num10 < count; num10++) + { + double num11 = -(shell.polyn[num10].x * vectorLF3.x + shell.polyn[num10].y * vectorLF3.y + shell.polyn[num10].z * vectorLF3.z) / shell.polynu[num10]; + if (num11 >= 0.0) + { + VectorLF3 normalized2 = new VectorLF3(vectorLF3.x + num11 * shell.raydir.x, vectorLF3.y + num11 * shell.raydir.y, vectorLF3.z + num11 * shell.raydir.z).normalized; + normalized2.x *= shell.radius; + normalized2.y *= shell.radius; + normalized2.z *= shell.radius; + VectorLF3 vectorLF4 = shell.polygon[num10] - normalized2; + VectorLF3 vectorLF5 = shell.polygon[(num10 + 1) % count] - normalized2; + double num12 = vectorLF4.x * vectorLF5.x + vectorLF4.y * vectorLF5.y + vectorLF4.z * vectorLF5.z; + if (num12 < 0.0 || (num12 == 0.0 && vectorLF4.x == 0.0 && vectorLF4.y == 0.0 && vectorLF4.z == 0.0)) + { + num9++; + } + } + } + if ((num9 & 1) == 1) + { + int num13 = DysonShell._get_key(m, n); + DysonShell.s_vmap[num13] = vectorLF3; + } + else + { + for (int num14 = 0; num14 < count; num14++) + { + VectorLF3 vectorLF6 = shell.polygon[num14]; + VectorLF3 vectorLF7 = shell.polyn[num14]; + VectorLF3 vectorLF8 = vectorLF3 - vectorLF6; + double num15 = vectorLF7.x * vectorLF8.x + vectorLF7.y * vectorLF8.y + vectorLF7.z * vectorLF8.z; + double num16 = Math.Abs(num15); + if (num16 <= num7) + { + VectorLF3 vectorLF9 = shell.polygon[(num14 + 1) % count]; + VectorLF3 vectorLF10 = vectorLF3 - vectorLF7 * num15; + VectorLF3 vectorLF11 = vectorLF9 - vectorLF6; + double magnitude = vectorLF11.magnitude; + VectorLF3 vectorLF12 = vectorLF11 / magnitude; + VectorLF3 vectorLF13 = vectorLF10 - vectorLF6; + double num17 = vectorLF12.x * vectorLF13.x + vectorLF12.y * vectorLF13.y + vectorLF12.z * vectorLF13.z; + double num18; + if (num17 < 0.0) + { + num18 = vectorLF8.magnitude; + } + else if (num17 > magnitude) + { + num18 = (vectorLF3 - vectorLF9).magnitude; + } + else + { + num18 = num16; + } + if (num18 <= num7) + { + int num19 = DysonShell._get_key(m, n); + DysonShell.s_vmap[num19] = vectorLF3; + DysonShell.s_outvmap[num19] = vectorLF3; + break; + } + } + } + } + } + } + } + int count2 = DysonShell.s_vmap.Count; + if (count2 > 32767) + { + return false; + } + shell.verts = new Vector3[count2]; + shell.uvs = new Vector2[count2]; + shell.uv2s = new Vector2[count2]; + shell.vkeys = new int[count2]; + shell._gen_points_topo_indices(count2); + shell.vAdjs = new short[count2 * 6]; + for (int num20 = 0; num20 < shell.vAdjs.Length; num20++) + { + shell.vAdjs[num20] = -1; + } + int num21 = 0; + foreach (KeyValuePair keyValuePair in DysonShell.s_vmap) + { + Vector3 value = keyValuePair.Value; + DysonShell.s_ivmap[keyValuePair.Key] = num21; + shell.verts[num21] = value; + shell.uv2s[num21].x = (float)(DysonShell.s_outvmap.ContainsKey(keyValuePair.Key) ? 0 : 1); + shell.vkeys[num21] = keyValuePair.Key; + num21++; + } + foreach (KeyValuePair keyValuePair2 in DysonShell.s_ivmap) + { + int key = keyValuePair2.Key; + int num22 = DysonShell.s_ivmap[key]; + int num23 = key + 65536; + int num24 = key - 1; + int num25 = key - 65537; + int num26 = key - 65536; + int num27 = key + 1; + int num28 = key + 65537; + bool flag = DysonShell.s_ivmap.ContainsKey(num23); + bool flag2 = DysonShell.s_ivmap.ContainsKey(num24); + bool flag3 = DysonShell.s_ivmap.ContainsKey(num25); + bool flag4 = DysonShell.s_ivmap.ContainsKey(num26); + bool flag5 = DysonShell.s_ivmap.ContainsKey(num27); + bool flag6 = DysonShell.s_ivmap.ContainsKey(num28); + shell.vAdjs[num22 * 6] = (short)(flag ? DysonShell.s_ivmap[num23] : (-1)); + shell.vAdjs[num22 * 6 + 1] = (short)(flag2 ? DysonShell.s_ivmap[num24] : (-1)); + shell.vAdjs[num22 * 6 + 2] = (short)(flag3 ? DysonShell.s_ivmap[num25] : (-1)); + shell.vAdjs[num22 * 6 + 3] = (short)(flag4 ? DysonShell.s_ivmap[num26] : (-1)); + shell.vAdjs[num22 * 6 + 4] = (short)(flag5 ? DysonShell.s_ivmap[num27] : (-1)); + shell.vAdjs[num22 * 6 + 5] = (short)(flag6 ? DysonShell.s_ivmap[num28] : (-1)); + } + int num29 = 0; + int num30 = 0; + for (int num31 = 0; num31 < count2; num31++) + { + double num32 = shell.radius * 2.0; + int num33 = -1; + VectorLF3 vectorLF14 = shell.verts[num31]; + for (int num34 = 0; num34 < count; num34++) + { + VectorLF3 vectorLF15 = shell.polygon[num34]; + VectorLF3 vectorLF16 = shell.polygon[(num34 + 1) % count]; + VectorLF3 vectorLF17 = shell.polyn[num34]; + VectorLF3 vectorLF18 = vectorLF14 - vectorLF15; + double num35 = vectorLF17.x * vectorLF18.x + vectorLF17.y * vectorLF18.y + vectorLF17.z * vectorLF18.z; + VectorLF3 vectorLF19 = vectorLF14 - vectorLF17 * num35; + VectorLF3 vectorLF20 = vectorLF14 - vectorLF16; + double num36 = vectorLF17.x * vectorLF20.x + vectorLF17.y * vectorLF20.y + vectorLF17.z * vectorLF20.z; + VectorLF3 vectorLF21 = vectorLF16 - vectorLF15; + double magnitude2 = vectorLF21.magnitude; + VectorLF3 vectorLF22 = vectorLF21 / magnitude2; + VectorLF3 vectorLF23 = vectorLF19 - vectorLF15; + double num37 = vectorLF22.x * vectorLF23.x + vectorLF22.y * vectorLF23.y + vectorLF22.z * vectorLF23.z; + double num38; + if (num37 < 0.0) + { + num38 = (vectorLF14 - vectorLF15).magnitude; + num38 -= Math.Abs(num35) * 0.001; + } + else if (num37 > magnitude2) + { + num38 = (vectorLF14 - vectorLF16).magnitude; + num38 -= Math.Abs(num36) * 0.001; + } + else + { + num38 = Math.Abs(num35); + num38 -= Math.Abs(num35) * 0.001; + } + if (num38 < num32) + { + num32 = num38; + num33 = num34; + } + } + shell.uv2s[num31].y = (float)num33; + if (num29 + num30 < 49 && shell._is_point_in_shell(vectorLF14)) + { + double num39 = VectorLF3.Dot(vectorLF14 - shell.polygon[num33], shell.polyn[num33]); + if (num39 > 0.1) + { + num29++; + } + else if (num39 < -0.1) + { + num30++; + } + } + } + if (num29 > num30) + { + shell.clockwise = true; + } + else + { + shell.clockwise = false; + } + shell.vertAttr = new int[count2]; + shell.vertsq = new short[count2]; + shell.vertsqOffset = new int[shell.nodes.Count + 1]; + int count3 = shell.nodes.Count; + int num40 = count3 / 2; + for (int num41 = 0; num41 < count2; num41++) + { + Vector3 vector3 = shell.verts[num41]; + double num42 = double.MaxValue; + int num43 = 0; + int num44 = 0; + int num45 = num41 + 479001600; + for (int num46 = 0; num46 < count3; num46++) + { + int num47 = num45 % count3 - num46; + if (num47 < 0) + { + num47 = -num47; + } + if (num47 > num40) + { + num47 = count3 - num47; + } + double num48 = (double)(vector3 - shell.nodes[num46].pos).sqrMagnitude; + num48 += (double)num47; + if (num48 < num42) + { + num42 = num48; + num43 = shell.nodes[num46].id; + num44 = num46; + } + } + shell.vertAttr[num41] = num43; + shell.vertsqOffset[num44]++; + } + int num49 = 0; + for (int num50 = 0; num50 < shell.vertsqOffset.Length; num50++) + { + num49 += shell.vertsqOffset[num50]; + } + Assert.True(num49 == count2); + for (int num51 = shell.vertsqOffset.Length - 1; num51 >= 0; num51--) + { + shell.vertsqOffset[num51] = num49; + if (num51 > 0) + { + num49 -= shell.vertsqOffset[num51 - 1]; + } + } + Assert.Zero(num49); + shell._openListPrepare(); + int num52 = shell.randSeed; + int num53 = 0; + while (num53 < count3) + { + Vector3 pos = shell.nodes[num53].pos; + int num54 = shell.nodes[num53].id; + float num55 = float.MaxValue; + int num56 = -1; + for (int num57 = 0; num57 < count2; num57++) + { + if (shell.vertAttr[num57] == num54 && (shell.vAdjs[num57 * 6] >= 0 || shell.vAdjs[num57 * 6 + 1] >= 0 || shell.vAdjs[num57 * 6 + 2] >= 0 || shell.vAdjs[num57 * 6 + 3] >= 0 || shell.vAdjs[num57 * 6 + 4] >= 0 || shell.vAdjs[num57 * 6 + 5] >= 0)) + { + float sqrMagnitude = (shell.verts[num57] - pos).sqrMagnitude; + if (sqrMagnitude < num55) + { + num55 = sqrMagnitude; + num56 = num57; + } + } + } + if (num56 >= 0) + { + shell._openListAdd(num56); + } + int num58 = shell.vertsqOffset[num53]; + int num59 = shell.vertsqOffset[num53 + 1] - shell.vertsqOffset[num53]; + double num60 = 0.0; + for (; ; ) + { + int num61 = shell._traverseRandomVertex(shell.nodes[num53].id, ref num52); + if (num61 < 0) + { + break; + } + shell.vertsq[num58++] = (short)num61; + num60 += 1.0; + shell.uvs[num61].x = (float)num53; + shell.uvs[num61].y = (float)(num60 / (double)num59); + if (num58 == shell.vertsqOffset[num53 + 1]) + { + goto Block_57; + } + } + IL_1329: + if (num58 < shell.vertsqOffset[num53 + 1]) + { + for (int num62 = 0; num62 < count2; num62++) + { + if (shell.vertAttr[num62] == num54 && !shell._tmp_marked[num62]) + { + shell.vertsq[num58++] = (short)num62; + num60 += 1.0; + shell.uvs[num62].x = (float)num53; + shell.uvs[num62].y = (float)(num60 / (double)num59); + } + } + } + Assert.False(num58 > shell.vertsqOffset[num53 + 1]); + Assert.False(num58 < shell.vertsqOffset[num53 + 1]); + shell._openListClear(); + num53++; + continue; + Block_57: + Assert.Zero(shell._tmp_openCount); + goto IL_1329; + } + shell._openListFree(); + shell.vertexCount = count2; + return true; + } + + private static int QuickAddDysonShell(this DysonSphereLayer layer, int protoId, DysonNode[] nodes, DysonFrame[] frames, bool limit) + { + int shellId = 0; + if (layer.shellRecycleCursor > 0) + { + int[] array = layer.shellRecycle; + int index = layer.shellRecycleCursor - 1; + layer.shellRecycleCursor = index; + shellId = array[index]; + } + else + { + int index = layer.shellCursor; + layer.shellCursor = index + 1; + shellId = index; + if (shellId == layer.shellCapacity) + { + layer.SetShellCapacity(layer.shellCapacity * 2); + } + } + var shell = layer.shellPool[shellId]; + if (shell == null) + { + shell = new DysonShell(layer); + layer.shellPool[shellId] = shell; + } + else + { + shell.SetEmpty(); + } + shell.id = shellId; + shell.layerId = layer.id; + shell.protoId = protoId; + shell.randSeed = layer.id * 10000 + shellId; + for (int j = 0; j < nodes.Length; j++) + { + DysonNode dysonNode = nodes[j]; + DysonFrame dysonFrame = frames[j]; + List segments = dysonFrame.GetSegments(); + if (dysonNode == dysonFrame.nodeA) + { + for (int k = 0; k < segments.Count - 1; k++) + { + shell.polygon.Add(segments[k]); + } + } + else + { + for (int l = segments.Count - 1; l >= 1; l--) + { + shell.polygon.Add(segments[l]); + } + } + shell.nodeIndexMap[dysonNode.id] = shell.nodes.Count; + shell.nodes.Add(dysonNode); + shell.frames.Add(dysonFrame); + } + if (!shell.MyGenerateGeometry() || (limit && DysonShell.s_vmap.Count < 32000)) + { + CheatEnabler.Logger.LogDebug($"Stripped VertCount: {DysonShell.s_vmap.Count}"); + shell.Free(); + layer.shellPool[shellId] = null; + int recycleIndex = layer.shellRecycleCursor; + layer.shellRecycleCursor = recycleIndex + 1; + layer.shellRecycle[recycleIndex] = shellId; + return 0; + } + CheatEnabler.Logger.LogDebug($"Shell {shellId} VertCount: {DysonShell.s_vmap.Count}"); + for (int j = 0; j < shell.nodes.Count; j++) + { + shell.nodes[j].shells.Add(shell); + } + shell.GenerateModelObjects(); + return shellId; + } + + private static void QuickRemoveDysonNode(this DysonSphereLayer layer, int nodeId) + { + var node = layer.nodePool[nodeId]; + if (node == null || node.id != nodeId) return; + var dysonSphere = layer.dysonSphere; + dysonSphere.swarm.OnNodeRemove(layer.id, nodeId); + dysonSphere.RemoveAutoNode(node); + dysonSphere.RemoveNodeRocket(node); + dysonSphere.RemoveDysonNodeRData(node); + node.Free(); + layer.nodePool[nodeId] = null; + int recycleIndex = layer.nodeRecycleCursor; + layer.nodeRecycleCursor = recycleIndex + 1; + layer.nodeRecycle[recycleIndex] = nodeId; + } + + private static void QuickRemoveDysonFrame(this DysonSphereLayer layer, int frameId) + { + var frame = layer.framePool[frameId]; + frame.nodeA.frames.Remove(frame); + frame.nodeB.frames.Remove(frame); + frame.Free(); + layer.framePool[frameId] = null; + int recycleIndex = layer.frameRecycleCursor; + layer.frameRecycleCursor = recycleIndex + 1; + layer.frameRecycle[recycleIndex] = frameId; + } + + public static void DuplicateShellsWithHighestProduction() + { + 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(), UIMessageBox.ERROR, 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(), UIMessageBox.ERROR, null); + return; + } + DysonShell.s_vmap ??= new Dictionary(16384); + DysonShell.s_outvmap ??= new Dictionary(16384); + DysonShell.s_ivmap ??= new Dictionary(16384); + DysonSphereLayer layer = null; + var nodePos = new List(); + var isEuler = new List(); + DysonShell shell = null; + for (var i = 1; i < dysonSphere.layersIdBased.Length; i++) + { + layer = dysonSphere.layersIdBased[i]; + if (layer == null || layer.id != i) continue; + for (var j = 1; j < layer.shellCursor; j++) + { + shell = layer.shellPool[j]; + if (shell == null) continue; + if (shell.id != j) + { + shell = null; + continue; + } + nodePos.AddRange(shell.nodes.Select(node => node.pos)); + isEuler.AddRange(shell.frames.Select(frame => frame.euler)); + break; + } + if (nodePos.Count > 0) break; + } + if (nodePos.Count == 0) + { + UIMessageBox.Show("CheatEnabler".Translate(), string.Format("There is no Dyson Sphere shell on \"{0}\".".Translate(), star.displayName), "确定".Translate(), UIMessageBox.ERROR, null); + return; + } + var currentShellCount = layer.shellCount; + var keepCount = ShellsCountForFunctions.Value; + if (currentShellCount >= keepCount) return; + CheatEnabler.Logger.LogDebug($"NodePositions: {nodePos[0]}, {nodePos[1]}, {nodePos[2]}"); + var nodeCount = nodePos.Count; + DysonNode[] nodes = [.. shell.nodes]; + DysonFrame[] frames = [.. shell.frames]; + var cpMax = new long[nodeCount]; + for (var i = 0; i < nodeCount; i++) + { + cpMax[i] = (shell.vertsqOffset[i + 1] - shell.vertsqOffset[i]) * shell.cpPerVertex; + } + long[] totalCpMax = [.. nodes.Select(node => node.totalCpMax)]; + var dirtyFrames = new HashSet(); + for (var i = currentShellCount; i < keepCount; i++) + { + dirtyFrames.Clear(); + for (var j = 0; j < nodeCount; j++) + { + totalCpMax[j] += cpMax[j]; + if (totalCpMax[j] > int.MaxValue) + { + totalCpMax[j] = cpMax[j]; + dirtyFrames.Add(j > 0 ? j - 1 : nodeCount - 1); + dirtyFrames.Add(j); + nodes[j] = layer.QuickAddDysonNode(0, nodePos[j]); + } + } + foreach (var frameId in dirtyFrames) + { + frames[frameId] = layer.QuickAddDysonFrame(0, nodes[frameId], nodes[(frameId + 1) % nodeCount], isEuler[frameId]); + } + layer.QuickAddDysonShell(0, nodes, frames, false); + } + foreach (var node in nodes) + { + node.RecalcSpReq(); + node.RecalcCpReq(); + } + dysonSphere.CheckAutoNodes(); + if (dysonSphere.autoNodeCount <= 0) + { + dysonSphere.PickAutoNode(); + } + dysonSphere.modelRenderer.RebuildModels(); + GameMain.gameScenario.NotifyOnPlanDysonShell(); + dysonSphere.inEditorRenderMaskS = 0; + dysonSphere.inEditorRenderMaskL = 0; + dysonSphere.inGameRenderMaskS = 0; + dysonSphere.inGameRenderMaskL = 0; + } + + public static void KeepMaxProductionShells() + { + 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(), UIMessageBox.ERROR, 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(), UIMessageBox.ERROR, null); + return; + } + int retainCount = ShellsCountForFunctions.Value; + for (var i = 1; i < dysonSphere.layersIdBased.Length; i++) + { + var layer = dysonSphere.layersIdBased[i]; + if (layer == null || layer.id != i) continue; + var shells = layer.shellPool.Where(shell => shell != null).OrderByDescending(shell => shell.vertexCount).ToArray(); + if (shells.Length < 1) continue; + for (var j = retainCount; j < shells.Length; j++) + { + var shell = shells[j]; + var id = shell.id; + layer.shellPool[id] = null; + for (var k = 0; k < shell.nodes.Count; k++) + { + shell.nodes[k].shells.Remove(shell); + } + shell.Free(); + shells[j] = null; + } + var poolCapacity = AlignUpToPowerOfTwo(retainCount + 1); + if (poolCapacity < 64) poolCapacity = 64; + layer.shellPool = new DysonShell[poolCapacity]; + layer.shellRecycle = new int[poolCapacity]; + layer.shellRecycleCursor = 0; + layer.shellCapacity = poolCapacity; + layer.shellCursor = retainCount + 1; + HashSet retainNodes = []; + HashSet<(int, int)> retainFrames = []; + for (var j = 0; j < retainCount; j++) + { + var shell = shells[j]; + retainNodes.UnionWith(shell.nodes.Select(node => node.id)); + layer.shellPool[1] = shell; + shell.id = 1; + for (var k = 0; k < shell.nodes.Count; k++) + { + var idA = shell.nodes[k].id; + var idB = shell.nodes[(k + 1) % shell.nodes.Count].id; + retainFrames.Add((idA, idB)); + retainFrames.Add((idB, idA)); + } + } + var nodes = layer.nodePool.Where(node => node != null && retainNodes.Contains(node.id)).ToArray(); + var frames = layer.framePool.Where(frame => frame != null && retainFrames.Contains((frame.nodeA.id, frame.nodeB.id))).ToArray(); + poolCapacity = AlignUpToPowerOfTwo(frames.Length + 1); + if (poolCapacity < 64) poolCapacity = 64; + layer.framePool = new DysonFrame[poolCapacity]; + layer.frameRecycle = new int[poolCapacity]; + layer.frameRecycleCursor = 0; + layer.frameCapacity = poolCapacity; + layer.frameCursor = frames.Length + 1; + for (var j = 0; j < frames.Length; j++) + { + int id = j + 1; + layer.framePool[id] = frames[j]; + frames[j].id = id; + } + foreach (var node in nodes) + { + if (node != null && node.id > 0) + { + dysonSphere.RemoveDysonNodeRData(node); + } + } + poolCapacity = AlignUpToPowerOfTwo(nodes.Length + 1); + if (poolCapacity < 64) poolCapacity = 64; + layer.nodePool = new DysonNode[poolCapacity]; + layer.nodeRecycle = new int[poolCapacity]; + layer.nodeRecycleCursor = 0; + layer.nodeCapacity = poolCapacity; + layer.nodeCursor = nodes.Length + 1; + for (var j = 0; j < nodes.Length; j++) + { + int id = j + 1; + layer.nodePool[id] = nodes[j]; + nodes[j].id = id; + } + for (var j = 1; j < layer.shellCursor; j++) + { + var shell = layer.shellPool[j]; + if (shell == null || shell.id != j) continue; + shell.nodeIndexMap.Clear(); + for (var k = 0; k < shell.nodes.Count; k++) + { + shell.nodeIndexMap[shell.nodes[k].id] = k; + } + } + for (var j = 1; j < layer.nodeCursor; j++) + { + var node = layer.nodePool[j]; + if (node == null || node.id != j) continue; + dysonSphere.AddDysonNodeRData(node, true); + node.RecalcSpReq(); + node.RecalcCpReq(); + } + } + dysonSphere.CheckAutoNodes(); + if (dysonSphere.autoNodeCount <= 0) + { + dysonSphere.PickAutoNode(); + } + dysonSphere.modelRenderer.RebuildModels(); + } + + public static void CreatePossibleFramesAndShells() + { + 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(), UIMessageBox.ERROR, 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(), UIMessageBox.ERROR, null); + return; + } + DysonShell.s_vmap ??= new Dictionary(16384); + DysonShell.s_outvmap ??= new Dictionary(16384); + DysonShell.s_ivmap ??= new Dictionary(16384); + var shellsChanged = false; + var mutex = new object(); + for (var i = 1; i < dysonSphere.layersIdBased.Length; i++) + { + Dictionary<(int, int), int> availableFrames = []; + HashSet unusedFrameIds = []; + var layer = dysonSphere.layersIdBased[i]; + if (layer == null || layer.id != i) continue; + int nodeCount = layer.nodeCursor; + + List supposedShells = []; + int j; + for (j = 1; j < nodeCount; j++) + { + var nodeA = layer.nodePool[j]; + if (nodeA == null || nodeA.id != j) continue; + for (var k = j + 1; k < nodeCount; k++) + { + var nodeB = layer.nodePool[k]; + if (nodeB == null || nodeB.id != k) continue; + for (var l = k + 1; l < nodeCount; l++) + { + var nodeC = layer.nodePool[l]; + if (nodeC == null || nodeC.id != l) continue; + var area = Vector3.Cross(nodeB.pos - nodeA.pos, nodeC.pos - nodeA.pos).sqrMagnitude; + supposedShells.Add(new SupposedShell { nodeA = nodeA, nodeB = nodeB, nodeC = nodeC, area = area }); + } + } + } + supposedShells.Sort((a, b) => b.area.CompareTo(a.area)); + CheatEnabler.Logger.LogDebug($"Finished Area Sort"); + var maxVertCount = -1; + var maxJ = -1; + var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1 }; + Parallel.For(0, supposedShells.Count, options, (j, loopState) => + { + var sshell = supposedShells[j]; + var vertCount = CalculateTriangleVertCount([sshell.nodeA, sshell.nodeB, sshell.nodeC]); + if (vertCount < 32768) + { + lock (mutex) + { + if (loopState.ShouldExitCurrentIteration) return; + if (vertCount > maxVertCount) + { + maxVertCount = vertCount; + maxJ = j; + if (maxVertCount >= 32000) + { + CheatEnabler.Logger.LogDebug($"!!STOP!! Triangle {j}[{sshell.nodeA.pos:F2} {sshell.nodeB.pos:F2} {sshell.nodeC.pos:F2}] has {vertCount} vertices"); + loopState.Stop(); + return; + } + CheatEnabler.Logger.LogDebug($"Triangle {j}[{sshell.nodeA.pos:F2} {sshell.nodeB.pos:F2} {sshell.nodeC.pos:F2}] has {vertCount} vertices"); + } + } + } + }); + if (maxJ >= 0) + { + foreach (var node in layer.nodePool) + { + if (node == null || node.id != j) continue; + dysonSphere.RemoveDysonNodeRData(node); + } + layer.nodePool = new DysonNode[64]; + layer.nodeRecycle = new int[64]; + layer.nodeRecycleCursor = 0; + layer.nodeCapacity = 64; + layer.nodeCursor = 1; + layer.framePool = new DysonFrame[64]; + layer.frameRecycle = new int[64]; + layer.frameRecycleCursor = 0; + layer.frameCapacity = 64; + layer.frameCursor = 1; + layer.shellPool = new DysonShell[64]; + layer.shellRecycle = new int[64]; + layer.shellRecycleCursor = 0; + layer.shellCapacity = 64; + layer.shellCursor = 1; + var sshell = supposedShells[maxJ]; + DysonNode[] newNodes = [layer.QuickAddDysonNode(0, sshell.nodeA.pos), layer.QuickAddDysonNode(0, sshell.nodeB.pos), layer.QuickAddDysonNode(0, sshell.nodeC.pos)]; + DysonFrame[] newFrames = [layer.QuickAddDysonFrame(0, newNodes[0], newNodes[1], false), layer.QuickAddDysonFrame(0, newNodes[1], newNodes[2], false), layer.QuickAddDysonFrame(0, newNodes[2], newNodes[0], false)]; + layer.QuickAddDysonShell(0, newNodes, newFrames, false); + foreach (var node in newNodes) + { + dysonSphere.AddDysonNodeRData(node, true); + node.RecalcSpReq(); + node.RecalcCpReq(); + } + shellsChanged = true; + } + } + dysonSphere.CheckAutoNodes(); + if (dysonSphere.autoNodeCount <= 0) dysonSphere.PickAutoNode(); + dysonSphere.modelRenderer.RebuildModels(); + if (shellsChanged) GameMain.gameScenario.NotifyOnPlanDysonShell(); + dysonSphere.inEditorRenderMaskS = 0; + dysonSphere.inEditorRenderMaskL = 0; + dysonSphere.inGameRenderMaskS = 0; + dysonSphere.inGameRenderMaskL = 0; + } + + private static int AlignUpToPowerOfTwo(int value) + { + value--; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + return value + 1; + } + + private class SupposedShell + { + public DysonNode nodeA; + public DysonNode nodeB; + public DysonNode nodeC; + + public float area; + } } diff --git a/CheatEnabler/Functions/PlayerFunctions.cs b/CheatEnabler/Functions/PlayerFunctions.cs index d622207..a22d5a4 100644 --- a/CheatEnabler/Functions/PlayerFunctions.cs +++ b/CheatEnabler/Functions/PlayerFunctions.cs @@ -106,7 +106,7 @@ public static class PlayerFunctions if (itemCnt.All(cnt => cnt == 0)) { - UIMessageBox.Show("Remove all metadata consumption records".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), 0); + UIMessageBox.Show("Remove all metadata consumption records".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), UIMessageBox.INFO); return; } var msg = "ClearAllMetadataConsumptionDetails".Translate(); @@ -117,7 +117,7 @@ public static class PlayerFunctions msg += $"\n {LDB.items.Select(i + 6001).propertyName} x{itemCnt[i]}"; } } - UIMessageBox.Show("Remove all metadata consumption records".Translate(), msg, "取消".Translate(), "确定".Translate(), 2, null, () => + UIMessageBox.Show("Remove all metadata consumption records".Translate(), msg, "取消".Translate(), "确定".Translate(), UIMessageBox.QUESTION, null, () => { foreach (var data in propertySystem.propertyDatas) { @@ -143,7 +143,7 @@ public static class PlayerFunctions var clusterPropertyData = propertySystem.propertyDatas.FirstOrDefault(cpd => cpd.seedKey == seedKey); if (clusterPropertyData == null) { - UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), 0); + UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), UIMessageBox.INFO); return; } var currentGamePropertyData = GameMain.data.history.propertyData; @@ -154,7 +154,7 @@ public static class PlayerFunctions if (itemCnt.All(cnt => cnt == 0)) { - UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), 0); + UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), UIMessageBox.INFO); return; } var msg = "ClearCurrentMetadataConsumptionDetails".Translate(); @@ -165,7 +165,7 @@ public static class PlayerFunctions msg += $"\n {LDB.items.Select(i + 6001).propertyName} x{itemCnt[i]}"; } } - UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), msg, "取消".Translate(), "确定".Translate(), 2, null, () => + UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), msg, "取消".Translate(), "确定".Translate(), UIMessageBox.QUESTION, null, () => { for (var i = 0; i < clusterPropertyData.totalConsumption.Count; i++) { diff --git a/CheatEnabler/README.md b/CheatEnabler/README.md index 6ef553f..69dd01d 100644 --- a/CheatEnabler/README.md +++ b/CheatEnabler/README.md @@ -47,7 +47,12 @@ + Skip absorption period + Quick absorb + Eject anyway + + Unlock Dyson Sphere max orbit radius + Complete Dyson Sphere Shells instantly + + Buttons for creating illegal Dyson Sphere Shells, you must enable `IllegalDysonShellFunctionsEnabled` of `DysonSphere` section in config to see them. + - Generate an illegal dyson shell + - Keep max production shells and remove others + - Duplicate shells from that with highest production + Mecha/Combat: + Mecha and Drones/Fleets invicible + Buildings invicible @@ -114,7 +119,12 @@ + 跳过吸收阶段 + 快速吸收 + 全球弹射 + + 解锁戴森球最大轨道半径 + 立即完成戴森壳建造 + + 用于制作仙术戴森壳的按钮,你必须在设置文件里开启`DysonSphere`分类的`IllegalDysonShellFunctionsEnabled`才能看到它们 + - 生成单层仙术戴森壳 + - 保留发电量最高的戴森壳并移除其他戴森壳 + - 从发电量最高的壳复制戴森壳 + 机甲/战斗: + 机甲和战斗无人机无敌 + 建筑无敌 diff --git a/CheatEnabler/UIConfigWindow.cs b/CheatEnabler/UIConfigWindow.cs index 22f7d23..216e609 100644 --- a/CheatEnabler/UIConfigWindow.cs +++ b/CheatEnabler/UIConfigWindow.cs @@ -68,6 +68,11 @@ public static class UIConfigWindow I18N.Add("Overclock Silos", "Overclock Silos (10x)", "高速发射井(10倍射速)"); I18N.Add("Unlock Dyson Sphere max orbit radius", "Unlock Dyson Sphere max orbit radius", "解锁戴森球最大轨道半径"); I18N.Add("Complete Dyson Sphere shells instantly", "Complete Dyson Sphere shells instantly", "立即完成戴森壳建造"); + I18N.Add("Generate illegal dyson shell", "Generate an illegal dyson shell (Put/Paste nodes first)", "生成单层仙术戴森壳(请先设置/粘贴节点)"); + I18N.Add("Keep max production shells and remove others", "Keep max production shells and remove others", "保留发电量最高的戴森壳并移除其他戴森壳"); + I18N.Add("Duplicate shells from that with highest production", "Duplicate shells from that with highest production", "从发电量最高的壳复制戴森壳"); + I18N.Add("WARNING: This operation can be very slow, continue?", "WARNING: This operation can be very slow, continue?", "警告:此操作可能非常慢,继续吗?"); + I18N.Add("WARNING: This operation is DANGEROUS, continue?", "WARNING: This operation is DANGEROUS, continue?", "警告:此操作非常危险,继续吗?"); I18N.Add("Terraform without enough soil piles", "Terraform without enough soil piles", "沙土不够时依然可以整改地形"); I18N.Add("Instant hand-craft", "Instant hand-craft", "快速手动制造"); I18N.Add("Instant teleport (like that in Sandbox mode)", "Instant teleport (like that in Sandbox mode)", "快速传送(和沙盒模式一样)"); @@ -101,6 +106,37 @@ public static class UIConfigWindow } } + class ShellsCountMapper : MyWindow.RangeValueMapper + { + public ShellsCountMapper() : base(1, 139) + { + } + + public override int ValueToIndex(int value) + { + return value switch + { + < 4 => value, + < 64 => value / 4 + 3, + < 256 => value / 16 + 15, + < 4096 => value / 64 + 27, + _ => value / 256 + 75, + }; + } + + public override int IndexToValue(int index) + { + return index switch + { + < 4 => index, + < 19 => (index - 3) * 4, + < 31 => (index - 15) * 16, + < 91 => (index - 27) * 64, + _ => (index - 75) * 256, + }; + } + } + private static void CreateUI(MyConfigWindow wnd, RectTransform trans) { _windowTrans = trans; @@ -166,7 +202,6 @@ public static class UIConfigWindow FactoryPatch.BeltSignalGeneratorEnabled.SettingChanged += OnBeltSignalChanged; wnd.OnFree += () => { FactoryPatch.BeltSignalGeneratorEnabled.SettingChanged -= OnBeltSignalChanged; }; OnBeltSignalChanged(null, null); - void OnBeltSignalChanged(object o, EventArgs e) { var on = FactoryPatch.BeltSignalGeneratorEnabled.Value; @@ -260,12 +295,40 @@ public static class UIConfigWindow { slider.slider.enabled = DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.Value; } - - ; } x = 300f; y = 10f; wnd.AddButton(x, y, 300f, tab4, "Complete Dyson Sphere shells instantly", 16, "button-complete-dyson-sphere-shells-instantly", DysonSphereFunctions.CompleteShellsInstantly); + { + y += 72f; + var btn1 = wnd.AddButton(x, y, 300f, tab4, "Generate illegal dyson shell", 16, "button-generate-illegal-dyson-shells", () => { + UIMessageBox.Show("Generate illegal dyson shell".Translate(), "WARNING: This operation can be very slow, continue?".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.WARNING, null, + () => { DysonSphereFunctions.CreatePossibleFramesAndShells(); }); + }); + y += 36f; + var btn2 = wnd.AddButton(x, y, 300f, tab4, "Keep max production shells and remove others", 16, "button-keep-max-production-shells", () => { + UIMessageBox.Show("Keep max production shells and remove others".Translate(), "WARNING: This operation is DANGEROUS, continue?".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.WARNING, null, + () => { DysonSphereFunctions.KeepMaxProductionShells(); }); + }); + y += 36f; + var btn3 = wnd.AddButton(x, y, 300f, tab4, "Duplicate shells from that with highest production", 16, "button-duplicate-shells-from-the-highest-production", () => { + UIMessageBox.Show("Duplicate shells from that with highest production".Translate(), "WARNING: This operation can be very slow, continue?".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.WARNING, null, + () => { DysonSphereFunctions.DuplicateShellsWithHighestProduction(); }); + }); + y += 30f; + var slider1 = wnd.AddSlider(x + 20f, y, tab4, DysonSphereFunctions.ShellsCountForFunctions, new ShellsCountMapper()); + Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled.SettingChanged += onIllegalDysonShellFunctionsChanged; + wnd.OnFree += () => { Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled.SettingChanged -= onIllegalDysonShellFunctionsChanged; }; + onIllegalDysonShellFunctionsChanged(null, null); + void onIllegalDysonShellFunctionsChanged(object o, EventArgs e) + { + var enabled = Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled.Value; + btn1.gameObject.SetActive(enabled); + btn2.gameObject.SetActive(enabled); + btn3.gameObject.SetActive(enabled); + slider1.gameObject.SetActive(enabled); + } + } var tab5 = wnd.AddTab(_windowTrans, "Mecha/Combat"); x = 0f;