mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-05 07:40:12 +08:00
Compare commits
6
Commits
93e60cd4f0
...
7a8f4af31d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a8f4af31d | ||
|
|
44efbdbb4f | ||
|
|
b7180afff2 | ||
|
|
e5cb52c3f4 | ||
|
|
ca4244384c | ||
|
|
19629eae97 |
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,10 @@
|
||||
|
||||
## Changlog
|
||||
|
||||
* 2.4.4
|
||||
* New button `Generate illegal dyson shells for all layers without nodes and shells`, which is used to extend dyson layers.
|
||||
* You must enable `IllegalDysonShellFunctionsEnabled` of `DysonSphere` section in config to see it.
|
||||
* `Finish build immediately`: Fix a possible crash.
|
||||
* 2.4.3
|
||||
* `Duplicate shells from that with highest production`: Fix crash on using with frameless shells.
|
||||
* `Keep max production shells and remove others`: Fix wrong behaviour when left count > 1.
|
||||
@@ -185,6 +189,10 @@
|
||||
|
||||
## 更新日志
|
||||
|
||||
* 2.4.4
|
||||
* 新按钮 `为所有没有节点和壳的层级生成仙术戴森壳`,用于扩展新戴森壳层面的时候。
|
||||
* 你必须在设置文件里开启`DysonSphere`分类的`IllegalDysonShellFunctionsEnabled`才能看到它。
|
||||
* `立即完成建造`: 修复一个可能的崩溃问题。
|
||||
* 2.4.3
|
||||
* `从发电量最高的壳复制戴森壳`:修复在无框壳体时可能崩溃的问题。
|
||||
* `保留发电量最高的戴森壳并移除其他戴森壳`:修复当剩余壳体数量大于1时的异常行为。
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<BepInExPluginGuid>org.soardev.cheatenabler</BepInExPluginGuid>
|
||||
<Description>DSP MOD - CheatEnabler</Description>
|
||||
<Version>2.4.3</Version>
|
||||
<Version>2.4.4</Version>
|
||||
<PackageId>CheatEnabler</PackageId>
|
||||
<RootNamespace>CheatEnabler</RootNamespace>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
|
||||
@@ -1334,46 +1334,13 @@ public static class DysonSphereFunctions
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateIllegalDysonShellWithMaxOutput()
|
||||
private static bool CreateIllegalDysonShellWithMaxOutputForLayer(DysonSphereLayer layer)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
UXAssist.Functions.DysonSphereFunctions.InitCurrentDysonLayer(star, 0);
|
||||
var dysonSphere = GameMain.data?.dysonSpheres[star.index];
|
||||
if (dysonSphere == null)
|
||||
{
|
||||
UIMessageBox.Show("CheatEnabler".Translate(), string.Format("There is no Dyson Sphere data on \"{0}\".".Translate(), star.displayName), "确定".Translate(), UIMessageBox.ERROR, null);
|
||||
return;
|
||||
}
|
||||
DysonShell.s_vmap ??= new Dictionary<int, Vector3>(16384);
|
||||
DysonShell.s_outvmap ??= new Dictionary<int, Vector3>(16384);
|
||||
DysonShell.s_ivmap ??= new Dictionary<int, int>(16384);
|
||||
var shellsChanged = false;
|
||||
var mutex = new object();
|
||||
Dictionary<(int, int), int> availableFrames = [];
|
||||
HashSet<int> unusedFrameIds = [];
|
||||
var layer = dysonSphere.layersIdBased[1];
|
||||
if (layer != null)
|
||||
{
|
||||
dysonSphere.RemoveLayer(1);
|
||||
}
|
||||
var maxOrbitRadius = Patches.DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.Value ? Patches.DysonSpherePatch.UnlockMaxOrbitRadiusValue.Value : dysonSphere.maxOrbitRadius;
|
||||
layer = dysonSphere.AddLayerOnId(1, maxOrbitRadius, Quaternion.Euler(0f, 0f, 0f), Mathf.Sqrt(dysonSphere.gravity / maxOrbitRadius) / maxOrbitRadius * 57.2957802f);
|
||||
if (layer == null) return;
|
||||
|
||||
var supposedShells = new List<SupposedShell>(60 * 59 * 58);
|
||||
Vector3[] nodePos = new Vector3[60];
|
||||
for (var i = 0; i < 60; i++)
|
||||
@@ -1397,7 +1364,7 @@ public static class DysonSphereFunctions
|
||||
var maxJ = -1;
|
||||
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1 };
|
||||
|
||||
var gridScale = (int)(Math.Pow(maxOrbitRadius / 4000.0, 0.75) + 0.5);
|
||||
var gridScale = (int)(Math.Pow(layer.orbitRadius / 4000.0, 0.75) + 0.5);
|
||||
gridScale = (gridScale < 1) ? 1 : gridScale;
|
||||
var cpPerVertex = gridScale * gridScale * 2;
|
||||
var barrier = 0x7FFFFFFF / cpPerVertex;
|
||||
@@ -1457,6 +1424,85 @@ public static class DysonSphereFunctions
|
||||
}
|
||||
shellsChanged = true;
|
||||
}
|
||||
return shellsChanged;
|
||||
}
|
||||
|
||||
public static void CreateIllegalDysonShellWithMaxOutput()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
UXAssist.Functions.DysonSphereFunctions.InitCurrentDysonLayer(star, 0);
|
||||
var dysonSphere = GameMain.data?.dysonSpheres[star.index];
|
||||
if (dysonSphere == null)
|
||||
{
|
||||
UIMessageBox.Show("CheatEnabler".Translate(), string.Format("There is no Dyson Sphere data on \"{0}\".".Translate(), star.displayName), "确定".Translate(), UIMessageBox.ERROR, null);
|
||||
return;
|
||||
}
|
||||
var layer = dysonSphere.layersIdBased[1];
|
||||
if (layer != null)
|
||||
{
|
||||
dysonSphere.RemoveLayer(1);
|
||||
}
|
||||
var maxOrbitRadius = Patches.DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.Value ? Patches.DysonSpherePatch.UnlockMaxOrbitRadiusValue.Value : dysonSphere.maxOrbitRadius;
|
||||
layer = dysonSphere.AddLayerOnId(1, maxOrbitRadius, Quaternion.Euler(0f, 0f, 0f), Mathf.Sqrt(dysonSphere.gravity / maxOrbitRadius) / maxOrbitRadius * 57.2957802f);
|
||||
if (layer == null) return;
|
||||
|
||||
var shellsChanged = CreateIllegalDysonShellWithMaxOutputForLayer(layer);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static void CreateIllegalDysonShellWithMaxOutput2()
|
||||
{
|
||||
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)
|
||||
{
|
||||
UIMessageBox.Show("CheatEnabler".Translate(), string.Format("There is no Dyson Sphere data on \"{0}\".".Translate(), star.displayName), "确定".Translate(), UIMessageBox.ERROR, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var shellsChanged = false;
|
||||
for (int i = dysonSphere.layersSorted.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var layer = dysonSphere.layersSorted[i];
|
||||
if (layer == null) continue;
|
||||
shellsChanged = CreateIllegalDysonShellWithMaxOutputForLayer(layer) || shellsChanged;
|
||||
}
|
||||
|
||||
dysonSphere.CheckAutoNodes();
|
||||
if (dysonSphere.autoNodeCount <= 0) dysonSphere.PickAutoNode();
|
||||
|
||||
@@ -446,7 +446,9 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
var time = __instance.timei;
|
||||
if (time % 6 != 0) return;
|
||||
var factory = GameMain.localPlanet?.factory;
|
||||
var planet = GameMain.localPlanet;
|
||||
if (planet == null || !planet.factoryLoaded) return;
|
||||
var factory = planet.factory;
|
||||
if (factory == null || factory.prebuildCount <= 0) return;
|
||||
var player = GameMain.mainPlayer;
|
||||
if (player == null) return;
|
||||
|
||||
@@ -74,6 +74,7 @@ public static class UIConfigWindow
|
||||
I18N.Add("Complete Dyson Sphere shells instantly", "Complete Dyson Sphere shells instantly", "立即完成戴森壳建造");
|
||||
I18N.Add("Remove all frames on Dyson Sphere", "Remove all frames on Dyson Sphere", "移除戴森球上的所有框架");
|
||||
I18N.Add("Generate illegal dyson shell", "Generate an illegal dyson shell (!!1st shell layer will be replaced!!)", "生成单层仙术戴森壳(!!会先删除第一层戴森壳!!)");
|
||||
I18N.Add("Generate illegal dyson shell 2", "Generate illegal dyson shells for all layers without nodes and shells", "为所有没有节点和壳的层级生成仙术戴森壳");
|
||||
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("Generate illegal dyson shell quickly", "Generate illegal dyson shell quickly", "快速生成仙术戴森壳");
|
||||
@@ -316,12 +317,18 @@ public static class UIConfigWindow
|
||||
{
|
||||
y += 72f;
|
||||
var originalY = y;
|
||||
var btn1 = wnd.AddButton(x, y, 300f, tab4, "Generate illegal dyson shell", 16, "button-generate-illegal-dyson-shells", () =>
|
||||
var btn0 = 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.CreateIllegalDysonShellWithMaxOutput(); });
|
||||
});
|
||||
y += 36f;
|
||||
var btn1 = wnd.AddButton(x, y, 300f, tab4, "Generate illegal dyson shell 2", 16, "button-generate-illegal-dyson-shells", () =>
|
||||
{
|
||||
UIMessageBox.Show("Generate illegal dyson shell 2".Translate(), "WARNING: This operation can be very slow, continue?".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.WARNING, null,
|
||||
() => { DysonSphereFunctions.CreateIllegalDysonShellWithMaxOutput2(); });
|
||||
});
|
||||
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,
|
||||
@@ -352,6 +359,7 @@ public static class UIConfigWindow
|
||||
void onIllegalDysonShellFunctionsChanged(object o, EventArgs e)
|
||||
{
|
||||
var enabled = Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled.Value;
|
||||
btn0.gameObject.SetActive(enabled);
|
||||
btn1.gameObject.SetActive(enabled);
|
||||
btn2.gameObject.SetActive(enabled);
|
||||
btn3.gameObject.SetActive(enabled);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "CheatEnabler",
|
||||
"version_number": "2.4.3",
|
||||
"version_number": "2.4.4",
|
||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/CheatEnabler",
|
||||
"description": "Add various cheat functions while disabling abnormal determinants / 添加一些作弊功能,同时屏蔽异常检测",
|
||||
"dependencies": [
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
## Changlog
|
||||
|
||||
* 1.5.8
|
||||
* `Initialize This Planet`: Fix a possible crash.
|
||||
* `Remember window position and size on last exit`: Remove a window hook that are not useful anymore.
|
||||
* `Real-time logistic stations info panel`: Fix display issue (finally!) when count of logistic towers > 128.
|
||||
* 1.5.7
|
||||
* Fix compatibility with game update 0.10.34.28505.
|
||||
* 1.5.6
|
||||
@@ -397,6 +401,10 @@
|
||||
|
||||
## 更新日志
|
||||
|
||||
* 1.5.8
|
||||
* `初始化本行星`:修复可能的崩溃。
|
||||
* `记住上次退出时的窗口位置和大小`:移除不再有用的窗口钩子。
|
||||
* `物流站实时信息面板`:修复物流塔数量 > 128 时的显示问题。
|
||||
* 1.5.7
|
||||
* 修复了与游戏更新0.10.34.28505的兼容性。
|
||||
* 1.5.6
|
||||
|
||||
@@ -75,12 +75,14 @@ public static class LogisticsPatch
|
||||
RealtimeLogisticsInfoPanel.EnableBars(RealtimeLogisticsInfoPanelBarsEnabled.Value);
|
||||
|
||||
GameLogicProc.OnGameBegin += RealtimeLogisticsInfoPanel.OnGameBegin;
|
||||
GameLogicProc.OnGameEnd += RealtimeLogisticsInfoPanel.OnGameEnd;
|
||||
GameLogicProc.OnDataLoaded += RealtimeLogisticsInfoPanel.OnDataLoaded;
|
||||
}
|
||||
|
||||
public static void Uninit()
|
||||
{
|
||||
GameLogicProc.OnDataLoaded -= RealtimeLogisticsInfoPanel.OnDataLoaded;
|
||||
GameLogicProc.OnGameEnd -= RealtimeLogisticsInfoPanel.OnGameEnd;
|
||||
GameLogicProc.OnGameBegin -= RealtimeLogisticsInfoPanel.OnGameBegin;
|
||||
|
||||
AutoConfigLogistics.Enable(false);
|
||||
@@ -798,12 +800,13 @@ public static class LogisticsPatch
|
||||
|
||||
public static void Enable(bool on)
|
||||
{
|
||||
// Toggle the defensive localPlanet setter hook regardless of whether the GUI
|
||||
// root has been initialized yet (InitGUI may run later via OnDataLoaded).
|
||||
LocalPlanetWatcher.Enable(on);
|
||||
if (_stationTipsRoot == null) return;
|
||||
if (!on)
|
||||
{
|
||||
RecycleStationTips();
|
||||
_lastPlanetId = 0;
|
||||
_stationTipsRoot.SetActive(false);
|
||||
HideAndRecycleStationTips();
|
||||
return;
|
||||
}
|
||||
if (DSPGame.IsMenuDemo || !GameMain.isRunning)
|
||||
@@ -827,9 +830,12 @@ public static class LogisticsPatch
|
||||
|
||||
public static void OnGameBegin()
|
||||
{
|
||||
RecycleStationTips();
|
||||
_lastPlanetId = 0;
|
||||
_stationTipsRoot?.SetActive(false);
|
||||
HideAndRecycleStationTips();
|
||||
}
|
||||
|
||||
public static void OnGameEnd()
|
||||
{
|
||||
HideAndRecycleStationTips();
|
||||
}
|
||||
|
||||
public static void OnDataLoaded()
|
||||
@@ -1065,22 +1071,32 @@ public static class LogisticsPatch
|
||||
StateSprite[2] = Util.LoadEmbeddedSprite("assets/icon/in.png");
|
||||
}
|
||||
|
||||
private static void ReleaseStationTip(StationTip stationTip)
|
||||
{
|
||||
if (!stationTip) return;
|
||||
var go = stationTip.gameObject;
|
||||
if (_stationTipsRecycleCount < StationTipsRecycle.Length)
|
||||
{
|
||||
stationTip.ResetStationTip();
|
||||
go.SetActive(false);
|
||||
StationTipsRecycle[_stationTipsRecycleCount++] = stationTip;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recycle pool is full: destroy the cloned UI GameObject (not just the
|
||||
// StationTip MonoBehaviour). Destroying only the component would leave the
|
||||
// GameObject and all its UI children orphaned under _stationTipsRoot,
|
||||
// causing "ghost" tips to remain visible whenever the root is reactivated.
|
||||
go.SetActive(false);
|
||||
Object.Destroy(go);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RecycleStationTips()
|
||||
{
|
||||
foreach (var stationTip in _stationTips)
|
||||
{
|
||||
if (!stationTip) continue;
|
||||
if (_stationTipsRecycleCount < 128)
|
||||
{
|
||||
stationTip.ResetStationTip();
|
||||
stationTip.gameObject.SetActive(false);
|
||||
StationTipsRecycle[_stationTipsRecycleCount] = stationTip;
|
||||
_stationTipsRecycleCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(stationTip);
|
||||
}
|
||||
ReleaseStationTip(stationTip);
|
||||
}
|
||||
_stationTips = new StationTip[16];
|
||||
}
|
||||
@@ -1089,19 +1105,17 @@ public static class LogisticsPatch
|
||||
{
|
||||
var stationTip = _stationTips[index];
|
||||
if (!stationTip) return;
|
||||
if (_stationTipsRecycleCount < 128)
|
||||
{
|
||||
stationTip.ResetStationTip();
|
||||
stationTip.gameObject.SetActive(false);
|
||||
StationTipsRecycle[_stationTipsRecycleCount++] = stationTip;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(stationTip);
|
||||
}
|
||||
ReleaseStationTip(stationTip);
|
||||
_stationTips[index] = null;
|
||||
}
|
||||
|
||||
private static void HideAndRecycleStationTips()
|
||||
{
|
||||
_stationTipsRoot?.SetActive(false);
|
||||
RecycleStationTips();
|
||||
_lastPlanetId = 0;
|
||||
}
|
||||
|
||||
private static StationTip AllocateStationTip()
|
||||
{
|
||||
if (_stationTipsRecycleCount > 0)
|
||||
@@ -1247,6 +1261,26 @@ public static class LogisticsPatch
|
||||
}
|
||||
}
|
||||
|
||||
// Defensive Harmony hook on GameData.localPlanet setter.
|
||||
// It guarantees tips are hidden and recycled when the local planet id changes,
|
||||
// even if UXAssist.Update() is skipped that frame (e.g. by VFInput.inputing
|
||||
// while the player is typing while transitioning between planets, or by a brief
|
||||
// !GameMain.isRunning state during loading). _lastPlanetId is reset to 0 here so
|
||||
// the next StationInfoPanelsUpdate() re-validates factoryLoaded/transport/viewMode
|
||||
// and re-allocates fresh tips for the new planet.
|
||||
private class LocalPlanetWatcher : PatchImpl<LocalPlanetWatcher>
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameData), nameof(GameData.localPlanet), MethodType.Setter)]
|
||||
private static void GameData_localPlanet_Setter_Prefix(GameData __instance, PlanetData value)
|
||||
{
|
||||
var oldId = __instance.localPlanet?.id ?? 0;
|
||||
var newId = value?.id ?? 0;
|
||||
if (oldId == newId) return;
|
||||
HideAndRecycleStationTips();
|
||||
}
|
||||
}
|
||||
|
||||
public class StationTip : MonoBehaviour
|
||||
{
|
||||
[FormerlySerializedAs("RectTransform")]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<BepInExPluginGuid>org.soardev.uxassist</BepInExPluginGuid>
|
||||
<Description>DSP MOD - UXAssist</Description>
|
||||
<Version>1.5.7</Version>
|
||||
<Version>1.5.8</Version>
|
||||
<PackageId>UXAssist</PackageId>
|
||||
<RootNamespace>UXAssist</RootNamespace>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "UXAssist",
|
||||
"version_number": "1.5.7",
|
||||
"version_number": "1.5.8",
|
||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/UXAssist",
|
||||
"description": "Some functions and patches for better user experience / 一些提升用户体验的功能和补丁",
|
||||
"dependencies": [
|
||||
|
||||
Reference in New Issue
Block a user