diff --git a/DSP_Mods.sln b/DSP_Mods.sln
index 74a81d6..2b12884 100644
--- a/DSP_Mods.sln
+++ b/DSP_Mods.sln
@@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dustbin", "Dustbin\Dustbin.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompressSave", "CompressSave\CompressSave.csproj", "{A283A918-207F-4DD7-A098-F99EBE610558}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OCBatchBuild", "OCBatchBuild\OCBatchBuild.csproj", "{E8FB30A0-29BF-4CF0-8E08-9784962A8656}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -36,5 +38,9 @@ Global
{A283A918-207F-4DD7-A098-F99EBE610558}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A283A918-207F-4DD7-A098-F99EBE610558}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A283A918-207F-4DD7-A098-F99EBE610558}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/OCBatchBuild/OCBatchBuild.csproj b/OCBatchBuild/OCBatchBuild.csproj
new file mode 100644
index 0000000..db2c07f
--- /dev/null
+++ b/OCBatchBuild/OCBatchBuild.csproj
@@ -0,0 +1,27 @@
+
+
+
+ netstandard2.0
+ OCBatchBuild
+ org.soardev.ocbatchbuild
+ DSP MOD - OCBatchBuild
+ 1.0.0
+ true
+ latest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OCBatchBuild/OrbitalCollectorBatchBuild.cs b/OCBatchBuild/OrbitalCollectorBatchBuild.cs
new file mode 100644
index 0000000..1025562
--- /dev/null
+++ b/OCBatchBuild/OrbitalCollectorBatchBuild.cs
@@ -0,0 +1,99 @@
+using System;
+using BepInEx;
+using BepInEx.Configuration;
+using HarmonyLib;
+using UnityEngine;
+
+namespace OCBatchBuild;
+
+[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
+public class OrbitalCollectorBatchBuild : BaseUnityPlugin
+{
+ private new static readonly BepInEx.Logging.ManualLogSource Logger =
+ BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
+
+ private bool _cfgEnabled = true;
+ private static int _maxBuildCount;
+
+ private void Awake()
+ {
+ _cfgEnabled = Config.Bind("General", "Enabled", _cfgEnabled, "enable/disable this plugin").Value;
+ _maxBuildCount = Config.Bind("General", "MaxBuildCount", _maxBuildCount,
+ new ConfigDescription("Maximum Orbital Collectors to build once, set to 0 to build as many as possible",
+ new AcceptableValueRange(0, 40), new {}))
+ .Value;
+ Harmony.CreateAndPatchAll(typeof(OrbitalCollectorBatchBuild));
+ }
+
+ [HarmonyPostfix]
+ [HarmonyPatch(typeof(BuildTool_Click), "CreatePrebuilds")]
+ private static void CreatePrebuilds(BuildTool_Click __instance)
+ {
+ /* Check Gas Planet */
+ if (__instance.planet.type != EPlanetType.Gas) return;
+ if (__instance.buildPreviews.Count == 0) return;
+
+ var buildPreview = __instance.buildPreviews[0];
+ /* Check if is collector station */
+ if (!buildPreview.desc.isCollectStation) return;
+
+ var factory = __instance.factory;
+ var stationPool = factory.transport.stationPool;
+ var entityPool = factory.entityPool;
+ var stationCursor = factory.transport.stationCursor;
+ var pos = buildPreview.lpos;
+ var pos2 = buildPreview.lpos2;
+ var itemId = buildPreview.item.ID;
+ var countToBuild = _maxBuildCount - 1;
+ for (var i = 0; i < 39 && countToBuild != 0; i++)
+ {
+ /* rotate for 1/40 on sphere */
+ pos = Maths.RotateLF(0.0, 1.0, 0.0, Math.PI / 40.0, pos);
+ pos2 = Maths.RotateLF(0.0, 1.0, 0.0, Math.PI / 40.0, pos2);
+
+ /* Check for collision */
+ var collide = false;
+ for (var j = 1; j < stationCursor; j++)
+ {
+ if (stationPool[j] == null || stationPool[j].id != j) continue;
+ if ((entityPool[stationPool[j].entityId].pos - pos).sqrMagnitude >= 14297f) continue;
+ collide = true;
+ break;
+ }
+ if (collide) continue;
+
+ var player = __instance.player;
+ if (player.inhandItemId == itemId && player.inhandItemCount > 0)
+ {
+ player.UseHandItems(1, out var _);
+ }
+ else
+ {
+ var count = 1;
+ player.package.TakeTailItems(ref itemId, ref count, out var _);
+ if (count == 0) break;
+ }
+
+ var rot = Maths.SphericalRotation(pos, 0f);
+ var rot2 = Maths.SphericalRotation(pos2, 0f);
+ var prebuild = default(PrebuildData);
+ prebuild.protoId = (short)buildPreview.item.ID;
+ prebuild.modelIndex = (short)buildPreview.desc.modelIndex;
+ prebuild.pos = pos;
+ prebuild.pos2 = pos2;
+ prebuild.rot = rot;
+ prebuild.rot2 = rot2;
+ prebuild.pickOffset = (short)buildPreview.inputOffset;
+ prebuild.insertOffset = (short)buildPreview.outputOffset;
+ prebuild.recipeId = buildPreview.recipeId;
+ prebuild.filterId = buildPreview.filterId;
+ prebuild.InitParametersArray(buildPreview.paramCount);
+ for (var j = 0; j < buildPreview.paramCount; j++)
+ {
+ prebuild.parameters[j] = buildPreview.parameters[j];
+ }
+ factory.AddPrebuildDataWithComponents(prebuild);
+ countToBuild--;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OCBatchBuild/README.md b/OCBatchBuild/README.md
new file mode 100644
index 0000000..94be401
--- /dev/null
+++ b/OCBatchBuild/README.md
@@ -0,0 +1,14 @@
+# OrbitalCollectorBatchBuild
+
+#### Batch build Orbital Collectors
+#### 轨道采集器快速批量建造
+
+## Usage
+* Build any orbital collector on a Gas Giant to trigger building all placable orbital collectors.
+* Can set maximum orbital collectors to build once in config.
+* Note: They are placed as prebuilt status, you still need to fly around the Gas Giant to complete building. This is designed not to break much game logic.
+
+## 使用说明
+* 在气态星球上建造任何一个轨道采集器触发所有可建造采集器的放置。
+* 可以在设置文件中配置一次批量建造的最大轨道采集器数量。
+* 提示:轨道采集器会处于待建造状态,你仍然需要绕行气态行星一圈以完成建造。这个机制是为了尽可能减少对原有游戏逻辑的破坏。
\ No newline at end of file
diff --git a/OCBatchBuild/package/icon.png b/OCBatchBuild/package/icon.png
new file mode 100644
index 0000000..136d47c
Binary files /dev/null and b/OCBatchBuild/package/icon.png differ
diff --git a/OCBatchBuild/package/manifest.json b/OCBatchBuild/package/manifest.json
new file mode 100644
index 0000000..b746624
--- /dev/null
+++ b/OCBatchBuild/package/manifest.json
@@ -0,0 +1,9 @@
+{
+ "name": "OrbitalCollectorBatchBuild",
+ "version_number": "1.0.0",
+ "website_url": "https://github.com/soarqin/DSP_Mods/tree/master/OCBatchBuild",
+ "description": "Batch build Orbital Collectors / 轨道采集器快速批量建造",
+ "dependencies": [
+ "xiaoye97-BepInEx-5.4.17"
+ ]
+}
diff --git a/README.md b/README.md
index b1897f0..792afbf 100644
--- a/README.md
+++ b/README.md
@@ -23,4 +23,9 @@ Hide/Disable various tutorial tips/messages
# [Dustbin](Dustbin)
Storages can destroy incoming items while capacity limited to zero
-空间限制为0的储物仓可以销毁送进来的物品
\ No newline at end of file
+空间限制为0的储物仓可以销毁送进来的物品
+
+# [OrbitalCollectorBatchBuild](OCBatchBuild)
+
+Batch build Orbital Collectors
+轨道采集器快速批量建造