mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-06 22:20:13 +08:00
Compare commits
97
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ed33b2638 | ||
|
|
ee7ea6ec35 | ||
|
|
64f9aee06b | ||
|
|
cc783937e6 | ||
|
|
f1cfc5619f | ||
|
|
ffd8b91930 | ||
|
|
79dea142de | ||
|
|
c3f3c2e96e | ||
|
|
63aaceda6f | ||
|
|
33921e7177 | ||
|
|
7a8f4af31d | ||
|
|
44efbdbb4f | ||
|
|
b7180afff2 | ||
|
|
e5cb52c3f4 | ||
|
|
ca4244384c | ||
|
|
19629eae97 | ||
|
|
93e60cd4f0 | ||
|
|
be86aebf7c | ||
|
|
69b028d706 | ||
|
|
93c39e2133 | ||
|
|
a894c34987 | ||
|
|
d7f8dc55d4 | ||
|
|
2e6950afb3 | ||
|
|
a5b2bdedd4 | ||
|
|
a346778db9 | ||
|
|
109c6afd90 | ||
|
|
e2848b4f97 | ||
|
|
f69a90d452 | ||
|
|
e91271e137 | ||
|
|
524e2b62f0 | ||
|
|
2487a099c1 | ||
|
|
7e9f9ee1ce | ||
|
|
f7fc9aaab0 | ||
|
|
c823e72c67 | ||
|
|
669ce9f88c | ||
|
|
a9ad961bd3 | ||
|
|
d6b00b1b78 | ||
|
|
ad99b49bad | ||
|
|
5e501ea649 | ||
|
|
d98d87af48 | ||
|
|
6ab286bb0b | ||
|
|
6f33669163 | ||
|
|
91184ccc3a | ||
|
|
2e13206346 | ||
|
|
3e24461ef0 | ||
|
|
097a5c8e8a | ||
|
|
63fb13bf92 | ||
|
|
e758209d99 | ||
|
|
a5009496d5 | ||
|
|
29b30996e6 | ||
|
|
60d14c9401 | ||
|
|
f0ee1aaea9 | ||
|
|
358fd4cf23 | ||
|
|
80aa2f9b70 | ||
|
|
5914f02d09 | ||
|
|
d9d1e0108f | ||
|
|
2456280151 | ||
|
|
0d090ddfb0 | ||
|
|
39578559aa | ||
|
|
157c86112b | ||
|
|
d0c20693e3 | ||
|
|
8ae88f4b41 | ||
|
|
c1428f6aee | ||
|
|
260e419855 | ||
|
|
6e0484f035 | ||
|
|
6e4416389d | ||
|
|
71c0fe75db | ||
|
|
aa775bd05f | ||
|
|
9787636d08 | ||
|
|
256faeee19 | ||
|
|
78e86aeafe | ||
|
|
3156f0ffb5 | ||
|
|
2377f92589 | ||
|
|
788ed4275e | ||
|
|
ed8d7d61ff | ||
|
|
6eb9161af1 | ||
|
|
2201de2b1b | ||
|
|
b537ff22be | ||
|
|
0049629fd1 | ||
|
|
c339041824 | ||
|
|
0d7941387f | ||
|
|
f237789fa0 | ||
|
|
b2c04c1dff | ||
|
|
29ee32b11b | ||
|
|
3f7c384284 | ||
|
|
556493b2b6 | ||
|
|
269cc3b801 | ||
|
|
cacbfd6d5f | ||
|
|
45445f82a1 | ||
|
|
1a242af84e | ||
|
|
1467a6010d | ||
|
|
6f5b779d58 | ||
|
|
d8fa46d495 | ||
|
|
af3b46be11 | ||
|
|
96f160926c | ||
|
|
ee812bbc79 | ||
|
|
052c23d3b7 |
@@ -4,9 +4,14 @@
|
||||
# Rider project files
|
||||
/.idea/
|
||||
|
||||
# VS Code project files
|
||||
/.vscode/
|
||||
|
||||
# C# generated folders
|
||||
bin/
|
||||
obj/
|
||||
*.dll
|
||||
!/AssemblyFromGame/*.dll
|
||||
|
||||
# C++ build folders
|
||||
build/
|
||||
@@ -15,3 +20,7 @@ build/
|
||||
/*/package/*.zip
|
||||
/*/package/patchers/
|
||||
/*/package/plugins/
|
||||
|
||||
# Agent files
|
||||
/.omo/
|
||||
/.worktrees/
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
# Agent Guidelines
|
||||
|
||||
## Rules
|
||||
|
||||
- Update `AGENTS.md` after completing every task.
|
||||
- Do not record a changelog in `AGENTS.md`; modify the document content directly instead.
|
||||
- All documentation and code comments must be written in English.
|
||||
- When you need to inspect game method implementations, decompile the **original** game DLL rather than the publicized copy in `AssemblyFromGame/` (which was built with `--strip` and has all method bodies removed). Locate the original DLL using the same logic as `UpdateGameDlls.ps1`: read the Steam installation path from the Windows registry (`HKCU\Software\Valve\Steam`), parse `steamapps/libraryfolders.vdf` to find the library containing DSP (AppID `1366540`), then decompile `<game_root>/DSPGAME_Data/Managed/Assembly-CSharp.dll` directly.
|
||||
- When looking up in-game terminology, use the localization files under `<game_root>/Locale/` (located via the same Steam registry + `libraryfolders.vdf` method). The `Names` directory contains the dictionary keys; `1033` is the English translation directory; `2052` is the Simplified Chinese translation directory.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This repository is a collection of **BepInEx mods** for the game **Dyson Sphere Program (DSP)**, a factory/automation game on Steam. Each subdirectory is an independent mod plugin loaded by the BepInEx framework at game startup. Mods use **HarmonyLib** to patch the game's compiled C# methods at runtime (prefix, postfix, and transpiler patches).
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Language:** C# (`net472` / `netstandard2.1`, latest LangVersion)
|
||||
- **Modding Framework:** BepInEx 5.x
|
||||
- **Patching Library:** HarmonyLib (runtime IL patching via `[HarmonyPatch]` attributes)
|
||||
- **Build System:** Visual Studio solution (`DSP_Mods.sln`), SDK-style `.csproj` per mod
|
||||
- **Package Manager:** NuGet (standard feed + BepInEx dev feed)
|
||||
- **Packaging:** `ZipMod` MSBuild target (explicit, not post-build) produces Thunderstore-ready `.zip` files via `powershell.exe Compress-Archive`
|
||||
- **Game DLL references:** `AssemblyFromGame/Assembly-CSharp.dll` and `UnityEngine.UI.dll`
|
||||
- **Notable dependencies:** DSPModSave, NebulaMultiplayer API, CommonAPI, NLua, obs-websocket-dotnet, Mono.Cecil
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
DSP_Mods/
|
||||
├── DSP_Mods.sln # Visual Studio solution
|
||||
├── AssemblyFromGame/ # Game DLLs used as compile-time references
|
||||
├── UXAssist/ # Core UX mod + shared library (largest mod)
|
||||
├── CheatEnabler/ # Cheat functions mod (depends on UXAssist)
|
||||
├── Dustbin/ # Storage/tank dustbin mod
|
||||
├── DustbinPreloader/ # BepInEx preloader for Dustbin
|
||||
├── HideTips/ # Hides tutorial/tip popups
|
||||
├── LabOpt/ # Lab performance optimizations
|
||||
├── LabOptPreloader/ # BepInEx preloader for LabOpt
|
||||
├── LogisticMiner/ # Logistic stations auto-mine ores
|
||||
├── LuaScriptEngine/ # Lua scripting support for the game
|
||||
├── MechaDronesTweaks/ # Mecha drone speed/energy tweaks
|
||||
├── OverclockEverything/ # Speed/power multipliers for all buildings
|
||||
├── PoolOpt/ # Memory pool optimization on save loading
|
||||
├── UniverseGenTweaks/ # Universe generator parameter tweaks
|
||||
├── UserCloak/ # Hides/fakes Steam account info
|
||||
├── UpdateGameDlls/ # MSBuild helper project; runs UpdateGameDlls.ps1 before any mod compiles
|
||||
└── CompressSave/ # Stub only (moved to external repo)
|
||||
```
|
||||
|
||||
## Mods Summary
|
||||
|
||||
| Mod | GUID | Description |
|
||||
|-----|------|-------------|
|
||||
| **UXAssist** | `org.soardev.uxassist` | Core QoL mod and shared library. Window resize, profile-based saves, FPS control, factory/logistics/navigation/Dyson Sphere tweaks, UI improvements, config panel UI, and `Common/` + `UI/` widget library shared by other mods. The Logistics tab can also push auto-config values to all existing facilities of a type on the current planet (per-setting `Apply` and per-category `Apply All` buttons; logic in `LogisticsPatch.Apply*`/`ForEach*`, wired in `UIConfigWindow`). |
|
||||
| **CheatEnabler** | `org.soardev.cheatenabler` | Cheat pack (depends on UXAssist). Instant build, architect mode, infinite resources, power boosts, Dyson Sphere cheats, mecha invincibility, and more. |
|
||||
| **LogisticMiner** | — | Makes logistic stations automatically mine ores and water from the current planet. |
|
||||
| **HideTips** | — | Suppresses all tutorial popups, random tips, achievement/milestone cards, and skips the prologue cutscene. |
|
||||
| **MechaDronesTweaks** | — | Configurable drone speed multiplier, skip stage-1 animation, reduce energy consumption. Successor to FastDrones. |
|
||||
| **OverclockEverything** | — | Multiplies speed and power consumption of belts, sorters, assemblers, labs, miners, generators, ejectors, and silos. |
|
||||
| **PoolOpt** | — | Shrinks all object pool arrays to actual used size on save load, then forces GC to reduce memory footprint. |
|
||||
| **UniverseGenTweaks** | — | Adds Epic difficulty, expands max star count to 1024, allows rare veins and flat terrain on birth planet. |
|
||||
| **UserCloak** | — | Prevents Steam leaderboard/achievement uploads; can fake or block Steam user identity. |
|
||||
| **Dustbin** | — | Turns storage boxes and tanks into item-destroying dustbins. Supports Nebula multiplayer and DSPModSave. Requires DustbinPreloader. |
|
||||
| **DustbinPreloader** | — | Mono.Cecil preloader that injects `bool IsDustbin` into `StorageComponent` and `TankComponent` before game load. |
|
||||
| **LabOpt** | — | Optimizes stacked Matrix Lab updates via a `rootLabId` concept. Temporarily marked obsolete. Requires LabOptPreloader. |
|
||||
| **LabOptPreloader** | — | Mono.Cecil preloader that injects `int rootLabId` into `LabComponent` before game load. |
|
||||
| **LuaScriptEngine** | `org.soardev.luascriptengine` | Embeds NLua runtime; loads `.lua` files from `scripts/`; exposes game lifecycle hooks and OBS WebSocket integration. |
|
||||
| **CompressSave** | — | Stub only; functionality moved to external repository `soarqin/DSP_Mods_TO`. |
|
||||
|
||||
## Build System
|
||||
|
||||
### Shared MSBuild Configuration
|
||||
|
||||
Common properties and references are factored into two root-level files that MSBuild automatically imports for every project:
|
||||
|
||||
- **`Directory.Build.props`** — shared `PropertyGroup` defaults (`TargetFramework`, `AllowUnsafeBlocks`, `LangVersion`, `RestoreAdditionalProjectSources`) and shared `ItemGroup`s (BepInEx packages, game DLL references, `Microsoft.NETFramework.ReferenceAssemblies`), and a global `ProjectReference` to the `UpdateGameDlls` helper project (ensuring game DLLs are refreshed before any mod project resolves assembly references).
|
||||
- **`Directory.Build.targets`** — defines the `ZipMod` and `CopyToParentPackage` targets (see below).
|
||||
- **`UpdateGameDlls.ps1`** — PowerShell script invoked by the `UpdateGameDlls` helper project; locates the DSP installation via Steam registry and `libraryfolders.vdf`, compares DLL timestamps, and re-publicizes stale DLLs using `assembly-publicizer`.
|
||||
|
||||
Individual `.csproj` files only declare what is unique to that project (GUID, version, extra packages, embedded resources).
|
||||
|
||||
### Automatic Game DLL Update
|
||||
|
||||
`AssemblyFromGame/` holds publicized copies of two game DLLs used as compile-time references. They are refreshed automatically before any mod project compiles by the `UpdateGameDlls` helper project.
|
||||
|
||||
The helper project (`UpdateGameDlls/UpdateGameDlls.csproj`) uses the `Microsoft.Build.NoTargets` SDK and is declared as a global `ProjectReference` in `Directory.Build.props` with `ReferenceOutputAssembly=false`, `SkipGetTargetFrameworkProperties=true`, and `Private=false`. This ensures that MSBuild's dependency graph guarantees the helper project completes before any mod project resolves assembly references, with no need for file locks or conditional triggers.
|
||||
|
||||
The `UpdateGameDlls.ps1` script:
|
||||
1. Reads the Steam installation path from the Windows registry (`HKCU\Software\Valve\Steam`).
|
||||
2. Parses `steamapps/libraryfolders.vdf` to find the library that contains DSP (AppID `1366540`).
|
||||
3. Locates `<game_root>/DSPGAME_Data/Managed/`.
|
||||
4. For each DLL (`Assembly-CSharp.dll`, `UnityEngine.UI.dll`): if the game copy is newer than the local copy, runs `assembly-publicizer … --strip --overwrite` to regenerate the local file and stamps it with the source timestamp.
|
||||
|
||||
To explicitly update game DLLs:
|
||||
```
|
||||
dotnet build UpdateGameDlls\UpdateGameDlls.csproj
|
||||
```
|
||||
|
||||
**Prerequisite:** `assembly-publicizer` must be installed as a .NET global tool:
|
||||
```
|
||||
dotnet tool install -g BepInEx.AssemblyPublicizer.Cli
|
||||
```
|
||||
If the tool is missing or DSP is not found, the script prints a warning and continues without failing the build.
|
||||
|
||||
### Packaging
|
||||
|
||||
Packaging is a **separate, explicit build target** — it does not run on every normal build.
|
||||
|
||||
To produce a Thunderstore-ready zip:
|
||||
```
|
||||
dotnet build -t:ZipMod -c Release
|
||||
```
|
||||
|
||||
The `ZipMod` target (defined in `Directory.Build.targets`) uses pure MSBuild tasks (`MakeDir`, `Copy`, `Delete`) plus `powershell.exe -NoProfile -Command` for `Compress-Archive`. Calling `powershell.exe` as an explicit executable path works correctly from any shell environment (cmd, PowerShell, bash/WSL).
|
||||
|
||||
> Note: the target is named `ZipMod` rather than `Pack` because `Pack` is a reserved target name in the .NET SDK (used for NuGet packaging) and would be silently intercepted.
|
||||
|
||||
**Per-project packaging properties** (set in the project's `PropertyGroup`):
|
||||
|
||||
| Property | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `PackHasChangelog` | `false` | Include `CHANGELOG.md` in the zip |
|
||||
| `PackUsePluginsLayout` | `false` | Use `plugins/` + `patchers/` folder layout (Dustbin, LabOpt) |
|
||||
| `PackPreloaderTargetDir` | *(empty)* | Preloader projects: destination folder for `CopyToParentPackage` |
|
||||
|
||||
**Preloader projects** (DustbinPreloader, LabOptPreloader) use `CopyToParentPackage` instead of `ZipMod`:
|
||||
```
|
||||
dotnet build -t:CopyToParentPackage -c Release
|
||||
```
|
||||
This copies the preloader DLL into the sibling main mod's `package/patchers/` directory, ready to be zipped by the main mod's `ZipMod` target.
|
||||
|
||||
### Version Management
|
||||
|
||||
Each mod's `<Version>` property in its `.csproj` file is the **single source of truth** for the version number. The `version_number` field in `package/manifest.json` is automatically synchronized from `<Version>` during the `ZipMod` target — no manual update of `manifest.json` is needed.
|
||||
|
||||
**Release workflow:**
|
||||
1. Update `<Version>` in the mod's `.csproj` file (e.g., `<Version>1.2.3</Version>`)
|
||||
2. Run `dotnet build -t:ZipMod -c Release` — `manifest.json` is updated automatically before packaging
|
||||
|
||||
The sync is implemented as an inline PowerShell `Exec` step inside the `ZipMod` target in `Directory.Build.targets`. It uses a regex replace that preserves the original UTF-8 BOM encoding and CRLF line endings of `manifest.json`. Preloader projects (which have no `manifest.json`) are safely skipped via a `Condition="Exists(...)"` guard.
|
||||
|
||||
## Key Architectural Patterns
|
||||
|
||||
- **Shared library:** `UXAssist` acts as a common library. `CheatEnabler` and `UniverseGenTweaks` reference `UXAssist.csproj` directly to reuse `Common/`, `UI/`, and config panel infrastructure.
|
||||
- **Preloader pattern:** `DustbinPreloader` and `LabOptPreloader` use Mono.Cecil to inject new fields into game assemblies at BepInEx preload time, enabling their corresponding main mods to read/write those fields via normal C# without reflection.
|
||||
- **Internationalization:** `UXAssist/Common/I18N.cs` provides bilingual (EN + ZH) string lookup used across UXAssist and CheatEnabler.
|
||||
- **Transpiler patches:** Performance-critical mods (LabOpt, MechaDronesTweaks) use `[HarmonyTranspiler]` to rewrite IL instructions directly for maximum efficiency.
|
||||
- **Save persistence:** Mods that need to persist data use the `IModCanSave` interface from DSPModSave.
|
||||
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,31 @@
|
||||
|
||||
## Changlog
|
||||
|
||||
* 2.4.5
|
||||
* 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.
|
||||
* 2.4.4
|
||||
* `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.
|
||||
* `Quick absorb`: Fix ant issue that it is not working while `Skip absorption period` is enabled.
|
||||
* `Finish build immediately`: Fixed an issue where prebuilt buildings were not constructed immediately when the building quantity became sufficient.
|
||||
* New option for `Belt signal item generation`: `Use proliferators for raws/intermediates and finished products`
|
||||
* Following items use extra products: `Titanium Alloy`, `Prism`, `Frame Material`, `Proliferator Mk.II`, `Proliferator Mk.III`, `Magnetic Coil`, `Electric Motor`, `Electromagnetic Turbine`, `Super-magnetic Ring`, `Circuit Board`, `Thruster`, `Reinforced Thruster`, `Plasma Exciter`, `Particle Broadband`, `Graviton Lens`, `Quantum Chip`, `Annihilation Constraint Sphere`, `Deuteron Fuel Rod`, `Space Warper`, `Dyson Sphere Component`, `Small Carrier Rocket`, `Electromagnetic Matrix`, `Structure Matrix`, `Information Matrix`, `Gravity Matrix`, `Universe Matrix`
|
||||
* Following items does not use proliferators: `Casimir Crystal`, `Energy Matrix`
|
||||
* Other items use speed up production.
|
||||
* Fix some other minor bugs found by LLM AI.
|
||||
* 2.4.2
|
||||
* Fix critical bugs:
|
||||
* Dyson Power is not updated actively when `Skip bullet period` or `Skip absorption period` is enabled and no rocket is in fire.
|
||||
* Dyson Power is not updated actively on clicking `Complete Dyson Sphere Shells instantly` or `Remove all frames on Dyson Sphere`.
|
||||
* 2.4.1
|
||||
* New feature: `Remove all frames on Dyson Sphere`
|
||||
* Can save rockets with very little power generation impact.
|
||||
* Will keep nodes and shells and does not affect solar sails' absorption.
|
||||
* `Terraform without enough soil piles`: Working for blueprint paste and burying Dark Fog Core Driller now.
|
||||
* `Belt signal item generation`: Fix mod compatibility by resolving recursive recipes.
|
||||
* 2.4.0
|
||||
* Support game version 0.10.33
|
||||
* `Generate illegal dyson shell`: This function is open to all users now, enabling certain config entry is not needed any more.
|
||||
@@ -165,6 +190,31 @@
|
||||
|
||||
## 更新日志
|
||||
|
||||
* 2.4.5
|
||||
* 新按钮 `为所有没有节点和壳的层级生成仙术戴森壳`,用于扩展新戴森壳层面的时候。
|
||||
* 你必须在设置文件里开启`DysonSphere`分类的`IllegalDysonShellFunctionsEnabled`才能看到它。
|
||||
* 2.4.4
|
||||
* `立即完成建造`: 修复一个可能的崩溃问题。
|
||||
* 2.4.3
|
||||
* `从发电量最高的壳复制戴森壳`:修复在无框壳体时可能崩溃的问题。
|
||||
* `保留发电量最高的戴森壳并移除其他戴森壳`:修复当剩余壳体数量大于1时的异常行为。
|
||||
* `快速吸收`:修复开启`跳过吸收阶段`时不生效的问题。
|
||||
* `立即完成建造`:修复建筑数量补足时,之前预建造状态的建筑未能立即完成的问题。
|
||||
* `传送带信号物品生成`新增选项:`原料/中间品和成品使用增产剂`
|
||||
* 以下物品会使用额外产出:`钛合金`、`棱镜`、`框架材料`、`增产剂 Mk.II`、`增产剂 Mk.III`、`磁线圈`、`电动机`、`电磁涡轮`、`超级磁场环`、`电路板`、`推进器`、`加力推进器`、`电浆激发器`、`粒子宽带`、`引力透镜`、`量子芯片`、`湮灭约束球`、`氘燃料棒`、`空间翘曲器`、`戴森球组件`、`小型运载火箭`、`电磁矩阵`、`结构矩阵`、`信息矩阵`、`引力矩阵`、`宇宙矩阵`
|
||||
* 以下物品不使用增产剂:`卡西米尔晶体`、`能量矩阵`
|
||||
* 其他物品使用加速生产
|
||||
* 修复一些由 LLM AI 发现的其他小问题。
|
||||
* 2.4.2
|
||||
* 修复了严重的系列BUG:
|
||||
* 在启用`跳过子弹阶段`或`跳过吸收阶段`并且没有火箭发射时,戴森球的发电量未实时更新
|
||||
* 点击`立即完成戴森壳建造`或`移除戴森球上的所有框架`时,戴森球的发电量未实时更新
|
||||
* 2.4.1
|
||||
* 新增功能:`移除戴森球上的所有框架`
|
||||
* 可以节省火箭,且几乎不影响发电效率
|
||||
* 会保留节点和壳面,不影响太阳帆的吸收
|
||||
* `沙土不够时依然可以整改地形`:现在支持蓝图粘贴和掩埋黑雾核心钻机
|
||||
* `传送带信号物品生成`:修复对递归配方的支持,兼容一些mod
|
||||
* 2.4.0
|
||||
* 支持游戏版本 0.10.33
|
||||
* `生成仙术戴森壳`:此功能现在对所有用户开放,不再需要启用特定的配置项。
|
||||
|
||||
@@ -39,6 +39,8 @@ public class CheatEnabler : BaseUnityPlugin
|
||||
"Belt signal count removals as comsumption in statistics");
|
||||
FactoryPatch.BeltSignalCountRecipeEnabled = Config.Bind("Build", "BeltSignalCountRecipe", false,
|
||||
"Belt signal count all raws and intermediates in statistics");
|
||||
FactoryPatch.BeltSignalUseProliferatorEnabled = Config.Bind("Build", "BeltSignalUseProliferator", false,
|
||||
"Belt signal count proliferators used for raws/intermediates and finished products");
|
||||
FactoryPatch.RemovePowerSpaceLimitEnabled = Config.Bind("Build", "RemovePowerDistanceLimit", false,
|
||||
"Remove distance limit for wind turbines and geothermals");
|
||||
FactoryPatch.BoostWindPowerEnabled = Config.Bind("Build", "BoostWindPower", false,
|
||||
@@ -51,8 +53,6 @@ public class CheatEnabler : BaseUnityPlugin
|
||||
"Boost geothermal power");
|
||||
FactoryPatch.WindTurbinesPowerGlobalCoverageEnabled = Config.Bind("Build", "PowerGlobalCoverage", false,
|
||||
"Global power coverage");
|
||||
FactoryPatch.GreaterPowerUsageInLogisticsEnabled = Config.Bind("Build", "GreaterPowerUsageInLogistics", false,
|
||||
"Increase maximum power usage in Logistic Stations and Advanced Mining Machines");
|
||||
FactoryPatch.ControlPanelRemoteLogisticsEnabled = Config.Bind("Build", "ControlPanelRemoteLogistics", false,
|
||||
"Retrieve/Place items from/to remote planets on logistics control panel");
|
||||
ResourcePatch.InfiniteResourceEnabled = Config.Bind("Planet", "AlwaysInfiniteResource", false,
|
||||
|
||||
@@ -1,43 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<BepInExPluginGuid>org.soardev.cheatenabler</BepInExPluginGuid>
|
||||
<Description>DSP MOD - CheatEnabler</Description>
|
||||
<Version>2.4.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>2.4.4</Version>
|
||||
<PackageId>CheatEnabler</PackageId>
|
||||
<RootNamespace>CheatEnabler</RootNamespace>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2022.3.53" IncludeAssets="compile" />
|
||||
<!-- <PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" /> -->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\AssemblyFromGame\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>..\AssemblyFromGame\UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UXAssist\UXAssist.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path '$(TargetPath)', package/icon.png, package/manifest.json, README.md, CHANGELOG.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -78,6 +78,7 @@ public static class DysonSphereFunctions
|
||||
I18N.Add("There is no Dyson Sphere shell on \"{0}\".", "There is no Dyson Sphere shell on \"{0}\".", "“{0}”上没有可建造的戴森壳");
|
||||
I18N.Add("There is no Dyson Sphere data on \"{0}\".", "There is no Dyson Sphere data 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}”上的所有戴森壳。你确定吗?");
|
||||
I18N.Add("This will remove all frames on \"{0}\". Are you sure?", "This will remove all frames on \"{0}\". Are you sure?", "这将移除“{0}”上的所有框架。你确定吗?");
|
||||
I18N.Add("No precalculated shell found for radius {0}.", "No precalculated shell found for radius {0}.", "没有找到适合半径 {0} 的预计算壳面");
|
||||
}
|
||||
|
||||
@@ -216,6 +217,72 @@ public static class DysonSphereFunctions
|
||||
if (count > 0L) consumeRegister[ProductionStatistics.SOLAR_SAIL_ID] += (int)count;
|
||||
}
|
||||
}
|
||||
dysonSphere.needRecalculatePower = true;
|
||||
});
|
||||
}
|
||||
|
||||
public static void RemoveAllFrames()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
UIMessageBox.Show("CheatEnabler".Translate(), string.Format("This will remove all frames on \"{0}\". Are you sure?".Translate(), star.displayName), "取消".Translate(), "确定".Translate(), UIMessageBox.QUESTION, null, () =>
|
||||
{
|
||||
var totalFrameSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalFrameSP");
|
||||
|
||||
foreach (var dysonSphereLayer in dysonSphere.layersIdBased)
|
||||
{
|
||||
if (dysonSphereLayer == null) continue;
|
||||
for (var i = dysonSphereLayer.nodeCursor - 1; i >= 0; i--)
|
||||
{
|
||||
var dysonNode = dysonSphereLayer.nodePool[i];
|
||||
if (dysonNode == null || dysonNode.id != i) continue;
|
||||
if (dysonNode.frames.Count > 0)
|
||||
dysonNode.frames.Clear();
|
||||
dysonNode.RecalcSpReq();
|
||||
}
|
||||
for (var i = dysonSphereLayer.shellCursor - 1; i >= 0; i--)
|
||||
{
|
||||
var dysonShell = dysonSphereLayer.shellPool[i];
|
||||
if (dysonShell == null || dysonShell.id != i) continue;
|
||||
if (dysonShell.frames.Count > 0)
|
||||
dysonShell.frames.Clear();
|
||||
}
|
||||
for (var i = dysonSphereLayer.frameCursor - 1; i >= 0; i--)
|
||||
{
|
||||
var dysonFrame = dysonSphereLayer.framePool[i];
|
||||
if (dysonFrame == null || dysonFrame.id != i) continue;
|
||||
dysonFrame.Free();
|
||||
dysonSphereLayer.framePool[i] = null;
|
||||
}
|
||||
dysonSphereLayer.frameCursor = 1;
|
||||
dysonSphereLayer.frameRecycleCursor = 0;
|
||||
dysonSphereLayer.SetFrameCapacity(64);
|
||||
totalFrameSpInfo?.SetValue(dysonSphereLayer, 0);
|
||||
}
|
||||
dysonSphere.CheckAutoNodes();
|
||||
dysonSphere.PickAutoNode();
|
||||
dysonSphere.modelRenderer.RebuildModels();
|
||||
dysonSphere.needRecalculatePower = true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -986,6 +1053,16 @@ public static class DysonSphereFunctions
|
||||
var nodeCount = nodePos.Count;
|
||||
DysonNode[] nodes = [.. shell.nodes];
|
||||
DysonFrame[] frames = [.. shell.frames];
|
||||
if (frames.Length == 0)
|
||||
{
|
||||
isEuler = new List<bool>(nodeCount);
|
||||
frames = new DysonFrame[nodeCount];
|
||||
for (var i = 0; i < nodeCount; i++)
|
||||
{
|
||||
isEuler.Add(false);
|
||||
frames[i] = layer.QuickAddDysonFrame(0, nodes[i], nodes[(i + 1) % nodeCount], false);
|
||||
}
|
||||
}
|
||||
var cpMax = new long[nodeCount];
|
||||
for (var i = 0; i < nodeCount; i++)
|
||||
{
|
||||
@@ -1024,7 +1101,7 @@ public static class DysonSphereFunctions
|
||||
dysonSphere.PickAutoNode();
|
||||
}
|
||||
dysonSphere.modelRenderer.RebuildModels();
|
||||
GameMain.gameScenario.NotifyOnPlanDysonShell();
|
||||
GameMain.gameScenario?.NotifyOnPlanDysonShell();
|
||||
dysonSphere.inEditorRenderMaskS = 0;
|
||||
dysonSphere.inEditorRenderMaskL = 0;
|
||||
dysonSphere.inGameRenderMaskS = 0;
|
||||
@@ -1086,8 +1163,9 @@ public static class DysonSphereFunctions
|
||||
{
|
||||
var shell = shells[j];
|
||||
retainNodes.UnionWith(shell.nodes.Select(node => node.id));
|
||||
layer.shellPool[1] = shell;
|
||||
shell.id = 1;
|
||||
int shellId = j + 1;
|
||||
layer.shellPool[shellId] = shell;
|
||||
shell.id = shellId;
|
||||
for (var k = 0; k < shell.nodes.Count; k++)
|
||||
{
|
||||
var idA = shell.nodes[k].id;
|
||||
@@ -1251,51 +1329,18 @@ public static class DysonSphereFunctions
|
||||
dysonSphere.CheckAutoNodes();
|
||||
if (dysonSphere.autoNodeCount <= 0) dysonSphere.PickAutoNode();
|
||||
dysonSphere.modelRenderer.RebuildModels();
|
||||
GameMain.gameScenario.NotifyOnPlanDysonShell();
|
||||
GameMain.gameScenario?.NotifyOnPlanDysonShell();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
@@ -1319,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;
|
||||
@@ -1379,11 +1424,90 @@ 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();
|
||||
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();
|
||||
dysonSphere.modelRenderer.RebuildModels();
|
||||
if (shellsChanged) GameMain.gameScenario?.NotifyOnPlanDysonShell();
|
||||
dysonSphere.inEditorRenderMaskS = 0;
|
||||
dysonSphere.inEditorRenderMaskL = 0;
|
||||
dysonSphere.inGameRenderMaskS = 0;
|
||||
@@ -1546,7 +1670,7 @@ public static class DysonSphereFunctions
|
||||
dysonSphere.CheckAutoNodes();
|
||||
if (dysonSphere.autoNodeCount <= 0) dysonSphere.PickAutoNode();
|
||||
dysonSphere.modelRenderer.RebuildModels();
|
||||
if (shellsChanged) GameMain.gameScenario.NotifyOnPlanDysonShell();
|
||||
if (shellsChanged) GameMain.gameScenario?.NotifyOnPlanDysonShell();
|
||||
dysonSphere.inEditorRenderMaskS = 0;
|
||||
dysonSphere.inEditorRenderMaskL = 0;
|
||||
dysonSphere.inGameRenderMaskS = 0;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace CheatEnabler.Functions;
|
||||
|
||||
public static class PlanetFunctions
|
||||
{
|
||||
public static void BuryAllVeins(bool bury)
|
||||
@@ -16,9 +17,15 @@ public static class PlanetFunctions
|
||||
{
|
||||
var pos = array[m].pos;
|
||||
var colliderId = array[m].colliderId;
|
||||
if (colliderId <= 0) continue;
|
||||
var chunkIdx = colliderId >> 20;
|
||||
var poolIdx = colliderId & 0xFFFFF;
|
||||
if (chunkIdx >= physics.colChunks.Length) continue;
|
||||
var chunk = physics.colChunks[chunkIdx];
|
||||
if (chunk == null || poolIdx >= chunk.colliderPool.Length) continue;
|
||||
var colliderData = physics.GetColliderData(colliderId);
|
||||
var vector = colliderData.pos.normalized * (height + 0.4f);
|
||||
physics.colChunks[colliderId >> 20].colliderPool[colliderId & 0xFFFFF].pos = vector;
|
||||
chunk.colliderPool[poolIdx].pos = vector;
|
||||
array[m].pos = pos.normalized * height;
|
||||
var quaternion = Maths.SphericalRotation(array[m].pos, Random.value * 360f);
|
||||
physics.SetPlanetPhysicsColliderDirty();
|
||||
|
||||
@@ -35,6 +35,7 @@ public static class PlayerFunctions
|
||||
{
|
||||
var maxSqrDistance = 0.0;
|
||||
var starPosition = VectorLF3.zero;
|
||||
if (GameMain.galaxy == null) return;
|
||||
foreach (var star in GameMain.galaxy.stars)
|
||||
{
|
||||
var sqrDistance = star.position.sqrMagnitude;
|
||||
|
||||
@@ -134,12 +134,12 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
{
|
||||
UpdateSailLifeTime();
|
||||
UpdateSailsCacheForThisGame();
|
||||
GameLogicProc.OnGameBegin += GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin -= GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
}
|
||||
|
||||
private static void UpdateSailLifeTime()
|
||||
@@ -172,7 +172,7 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
_sailsCacheCapacity[index] = capacity;
|
||||
}
|
||||
|
||||
private static void GameMain_Begin_Postfix()
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
UpdateSailsCacheForThisGame();
|
||||
UpdateSailLifeTime();
|
||||
@@ -337,6 +337,7 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
sphereProductRegister[ProductionStatistics.SOLAR_SAIL_ID] += len;
|
||||
sphereConsumeRegister[ProductionStatistics.SOLAR_SAIL_ID] += len;
|
||||
sphereProductRegister[ProductionStatistics.DYSON_CELL_ID] += len;
|
||||
__instance.dysonSphere.needRecalculatePower = true;
|
||||
return;
|
||||
}
|
||||
idx--;
|
||||
@@ -350,6 +351,7 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
sphereProductRegister[ProductionStatistics.SOLAR_SAIL_ID] += absorbCnt;
|
||||
sphereConsumeRegister[ProductionStatistics.SOLAR_SAIL_ID] += absorbCnt;
|
||||
sphereProductRegister[ProductionStatistics.DYSON_CELL_ID] += absorbCnt;
|
||||
__instance.dysonSphere.needRecalculatePower = true;
|
||||
}
|
||||
}
|
||||
for (; idx >= 0; idx--)
|
||||
@@ -363,12 +365,12 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
{
|
||||
protected override void OnEnable()
|
||||
{
|
||||
_instantAbsorb = QuickAbsorbEnabled.Value;
|
||||
_instantAbsorb = QuickAbsorbEnabled.Value && QuickAbsorbPatch.GetHarmony() != null;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
_instantAbsorb = false;
|
||||
_instantAbsorb = QuickAbsorbEnabled.Value && QuickAbsorbPatch.GetHarmony() != null;
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
@@ -380,30 +382,20 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(ExpiryOrder), nameof(ExpiryOrder.index)))
|
||||
).Advance(1).RemoveInstructions(matcher.Length - matcher.Pos).Insert(
|
||||
// if (node.ConstructCp() != null)
|
||||
// {
|
||||
// this.dysonSphere.productRegister[ProductionStatistics.DYSON_CELL_ID]++;
|
||||
// }
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(DysonNode), nameof(DysonNode.ConstructCp))),
|
||||
new CodeInstruction(OpCodes.Brfalse_S, label1),
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(DysonSwarm), nameof(DysonSwarm.dysonSphere))),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(DysonSphere), nameof(DysonSphere.productRegister))),
|
||||
new CodeInstruction(OpCodes.Ldc_I4, ProductionStatistics.DYSON_CELL_ID),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(int)),
|
||||
new CodeInstruction(OpCodes.Dup),
|
||||
new CodeInstruction(OpCodes.Ldind_I4),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_1),
|
||||
new CodeInstruction(OpCodes.Add),
|
||||
new CodeInstruction(OpCodes.Stind_I4),
|
||||
|
||||
// this.RemoveSolarSail(index);
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(label1),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Ldloc_1),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DysonSwarm), nameof(DysonSwarm.RemoveSolarSail))),
|
||||
|
||||
// return false;
|
||||
Transpilers.EmitDelegate((DysonSwarm swarm, DysonNode node, int index) =>
|
||||
{
|
||||
if (node.ConstructCp() != null)
|
||||
{
|
||||
swarm.dysonSphere.productRegister[ProductionStatistics.DYSON_CELL_ID]++;
|
||||
swarm.dysonSphere.needRecalculatePower = true;
|
||||
}
|
||||
swarm.RemoveSolarSail(index);
|
||||
}),
|
||||
// return true;
|
||||
// to avoid conflict with QuickAbsorbPatch
|
||||
new CodeInstruction(OpCodes.Ldc_I4_1),
|
||||
new CodeInstruction(OpCodes.Ret)
|
||||
);
|
||||
@@ -415,12 +407,12 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
{
|
||||
protected override void OnEnable()
|
||||
{
|
||||
_instantAbsorb = SkipAbsorbEnabled.Value;
|
||||
_instantAbsorb = SkipAbsorbEnabled.Value && SkipAbsorbPatch.GetHarmony() != null;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
_instantAbsorb = false;
|
||||
_instantAbsorb = SkipAbsorbEnabled.Value && SkipAbsorbPatch.GetHarmony() != null;
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
|
||||
@@ -23,13 +23,13 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
public static ConfigEntry<bool> BeltSignalCountGenEnabled;
|
||||
public static ConfigEntry<bool> BeltSignalCountRemEnabled;
|
||||
public static ConfigEntry<bool> BeltSignalCountRecipeEnabled;
|
||||
public static ConfigEntry<bool> BeltSignalUseProliferatorEnabled;
|
||||
public static ConfigEntry<bool> RemovePowerSpaceLimitEnabled;
|
||||
public static ConfigEntry<bool> BoostWindPowerEnabled;
|
||||
public static ConfigEntry<bool> BoostSolarPowerEnabled;
|
||||
public static ConfigEntry<bool> BoostFuelPowerEnabled;
|
||||
public static ConfigEntry<bool> BoostGeothermalPowerEnabled;
|
||||
public static ConfigEntry<bool> WindTurbinesPowerGlobalCoverageEnabled;
|
||||
public static ConfigEntry<bool> GreaterPowerUsageInLogisticsEnabled;
|
||||
public static ConfigEntry<bool> ControlPanelRemoteLogisticsEnabled;
|
||||
|
||||
private static PressKeyBind _noConditionKey;
|
||||
@@ -68,13 +68,13 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
NoCollisionEnabled.SettingChanged += (_, _) => NoCollisionValueChanged();
|
||||
BeltSignalGeneratorEnabled.SettingChanged += (_, _) => BeltSignalGenerator.Enable(BeltSignalGeneratorEnabled.Value);
|
||||
BeltSignalNumberAltFormat.SettingChanged += (_, _) => BeltSignalGenerator.OnAltFormatChanged();
|
||||
BeltSignalUseProliferatorEnabled.SettingChanged += (_, _) => BeltSignalGenerator.OnUseProliferatorChanged();
|
||||
RemovePowerSpaceLimitEnabled.SettingChanged += (_, _) => RemovePowerSpaceLimit.Enable(RemovePowerSpaceLimitEnabled.Value);
|
||||
BoostWindPowerEnabled.SettingChanged += (_, _) => BoostWindPower.Enable(BoostWindPowerEnabled.Value);
|
||||
BoostSolarPowerEnabled.SettingChanged += (_, _) => BoostSolarPower.Enable(BoostSolarPowerEnabled.Value);
|
||||
BoostFuelPowerEnabled.SettingChanged += (_, _) => BoostFuelPower.Enable(BoostFuelPowerEnabled.Value);
|
||||
BoostGeothermalPowerEnabled.SettingChanged += (_, _) => BoostGeothermalPower.Enable(BoostGeothermalPowerEnabled.Value);
|
||||
WindTurbinesPowerGlobalCoverageEnabled.SettingChanged += (_, _) => WindTurbinesPowerGlobalCoverage.Enable(WindTurbinesPowerGlobalCoverageEnabled.Value);
|
||||
GreaterPowerUsageInLogisticsEnabled.SettingChanged += (_, _) => GreaterPowerUsageInLogistics.Enable(GreaterPowerUsageInLogisticsEnabled.Value);
|
||||
ControlPanelRemoteLogisticsEnabled.SettingChanged += (_, _) => ControlPanelRemoteLogistics.Enable(ControlPanelRemoteLogisticsEnabled.Value);
|
||||
}
|
||||
|
||||
@@ -90,18 +90,17 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
BoostSolarPower.Enable(BoostSolarPowerEnabled.Value);
|
||||
BoostFuelPower.Enable(BoostFuelPowerEnabled.Value);
|
||||
BoostGeothermalPower.Enable(BoostGeothermalPowerEnabled.Value);
|
||||
GreaterPowerUsageInLogistics.Enable(GreaterPowerUsageInLogisticsEnabled.Value);
|
||||
ControlPanelRemoteLogistics.Enable(ControlPanelRemoteLogisticsEnabled.Value);
|
||||
Enable(true);
|
||||
CargoTrafficPatch.Enable(true);
|
||||
GameLogicProc.OnGameBegin += GameMain_Begin_Postfix_For_ImmBuild;
|
||||
GameLogicProc.OnGameBegin += OnGameBegin_For_ImmBuild;
|
||||
GameLogicProc.OnDataLoaded += OnDataLoaded;
|
||||
}
|
||||
|
||||
public static void Uninit()
|
||||
{
|
||||
GameLogicProc.OnDataLoaded -= OnDataLoaded;
|
||||
GameLogicProc.OnGameBegin -= GameMain_Begin_Postfix_For_ImmBuild;
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin_For_ImmBuild;
|
||||
CargoTrafficPatch.Enable(false);
|
||||
Enable(false);
|
||||
ImmediateBuild.Enable(false);
|
||||
@@ -114,14 +113,10 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
BoostFuelPower.Enable(false);
|
||||
BoostGeothermalPower.Enable(false);
|
||||
WindTurbinesPowerGlobalCoverage.Enable(false);
|
||||
GreaterPowerUsageInLogistics.Enable(false);
|
||||
ControlPanelRemoteLogistics.Enable(false);
|
||||
}
|
||||
|
||||
private static HashSet<int> _beltIds = [];
|
||||
private static HashSet<int> _alterBeltRendererIds;
|
||||
private static HashSet<int> _alterPathRendererIds;
|
||||
private static HashSet<int> _refreshPathUVIds;
|
||||
|
||||
private static void OnDataLoaded()
|
||||
{
|
||||
@@ -168,16 +163,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var prebuilds = factory.prebuildPool;
|
||||
if (imm)
|
||||
{
|
||||
var anyBelt = false;
|
||||
var anyBuilt = false;
|
||||
_alterBeltRendererIds ??= [];
|
||||
_alterPathRendererIds ??= [];
|
||||
_refreshPathUVIds ??= [];
|
||||
CargoTrafficPatch.IsBatchBuilding = true;
|
||||
factory.BeginFlattenTerrain();
|
||||
factory.cargoTraffic._batch_buffer_no_refresh = true;
|
||||
PlanetFactory.batchBuild = true;
|
||||
CargoTrafficPatch.DisableRefreshBatchesBuffers = true;
|
||||
var player = GameMain.mainPlayer;
|
||||
for (var i = factory.prebuildCursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var pb = ref prebuilds[i];
|
||||
@@ -187,14 +173,49 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
if (!architect) continue;
|
||||
pb.itemRequired = 0;
|
||||
}
|
||||
anyBelt = anyBelt || _beltIds.Contains(pb.protoId);
|
||||
factory.BuildFinally(GameMain.mainPlayer, i, false);
|
||||
anyBuilt = true;
|
||||
CargoTrafficPatch.InstantBuild(player, factory, i);
|
||||
}
|
||||
CargoTrafficPatch.TryEndBatchBuilding(factory);
|
||||
}
|
||||
else if (architect)
|
||||
{
|
||||
for (var i = factory.prebuildCursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var pb = ref prebuilds[i];
|
||||
if (pb.id != i || pb.isDestroyed || pb.itemRequired == 0) continue;
|
||||
pb.itemRequired = 0;
|
||||
factory.AlterPrebuildModelState(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CargoTrafficPatch : PatchImpl<CargoTrafficPatch>
|
||||
{
|
||||
private static bool _isBatchBuilding;
|
||||
private static bool _disableRefreshBatchesBuffers;
|
||||
private static bool _anyBelt;
|
||||
private static readonly HashSet<int> _alterBeltRendererIds = [];
|
||||
private static readonly HashSet<int> _alterPathRendererIds = [];
|
||||
private static readonly HashSet<int> _refreshPathUVIds = [];
|
||||
|
||||
public static bool IsBatchBuilding => _isBatchBuilding;
|
||||
|
||||
public static void StartBatchBuilding(PlanetFactory factory)
|
||||
{
|
||||
factory.BeginFlattenTerrain();
|
||||
factory.cargoTraffic._batch_buffer_no_refresh = true;
|
||||
PlanetFactory.batchBuild = true;
|
||||
_isBatchBuilding = true;
|
||||
_disableRefreshBatchesBuffers = true;
|
||||
_anyBelt = false;
|
||||
}
|
||||
|
||||
public static void EndBatchBuilding(PlanetFactory factory)
|
||||
{
|
||||
PlanetFactory.batchBuild = false;
|
||||
factory.cargoTraffic._batch_buffer_no_refresh = false;
|
||||
factory.EndFlattenTerrain();
|
||||
CargoTrafficPatch.IsBatchBuilding = false;
|
||||
_isBatchBuilding = false;
|
||||
var cargoTraffic = factory.cargoTraffic;
|
||||
var entityPool = factory.entityPool;
|
||||
var colChunks = factory.planet.physics?.colChunks;
|
||||
@@ -213,40 +234,36 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
_alterBeltRendererIds.Clear();
|
||||
_alterPathRendererIds.Clear();
|
||||
_refreshPathUVIds.Clear();
|
||||
CargoTrafficPatch.DisableRefreshBatchesBuffers = false;
|
||||
if (anyBelt)
|
||||
_disableRefreshBatchesBuffers = false;
|
||||
if (_anyBelt)
|
||||
{
|
||||
factory.cargoTraffic.RefreshBeltBatchesBuffers();
|
||||
factory.cargoTraffic.RefreshPathBatchesBuffers();
|
||||
}
|
||||
if (anyBuilt)
|
||||
{
|
||||
factory.planet.physics?.raycastLogic?.NotifyBatchObjectRemove();
|
||||
factory.planet.audio?.SetPlanetAudioDirty();
|
||||
}
|
||||
_anyBelt = false;
|
||||
factory.planet.physics?.raycastLogic?.NotifyBatchObjectRemove();
|
||||
factory.planet.audio?.SetPlanetAudioDirty();
|
||||
}
|
||||
|
||||
public static void TryEndBatchBuilding(PlanetFactory factory)
|
||||
{
|
||||
if (!_isBatchBuilding) return;
|
||||
EndBatchBuilding(factory);
|
||||
}
|
||||
|
||||
public static void InstantBuild(Player player, PlanetFactory factory, int id)
|
||||
{
|
||||
if (!_isBatchBuilding) StartBatchBuilding(factory);
|
||||
_anyBelt = _anyBelt || _beltIds.Contains(factory.prebuildPool[id].protoId);
|
||||
factory.BuildFinally(player, id, false);
|
||||
}
|
||||
else if (architect)
|
||||
{
|
||||
for (var i = factory.prebuildCursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var pb = ref prebuilds[i];
|
||||
if (pb.id != i || pb.isDestroyed || pb.itemRequired == 0) continue;
|
||||
pb.itemRequired = 0;
|
||||
factory.AlterPrebuildModelState(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CargoTrafficPatch : PatchImpl<CargoTrafficPatch>
|
||||
{
|
||||
public static bool IsBatchBuilding;
|
||||
public static bool DisableRefreshBatchesBuffers;
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPriority(Priority.First)]
|
||||
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.AlterBeltRenderer))]
|
||||
private static bool CargoTraffic_AlterBeltRenderer_Prefix(int beltId)
|
||||
{
|
||||
if (!IsBatchBuilding) return true;
|
||||
if (!_isBatchBuilding) return true;
|
||||
_alterBeltRendererIds.Add(beltId);
|
||||
return false;
|
||||
}
|
||||
@@ -256,7 +273,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.AlterPathRenderer))]
|
||||
private static bool CargoTraffic_AlterPathRenderer_Prefix(int pathId)
|
||||
{
|
||||
if (!IsBatchBuilding) return true;
|
||||
if (!_isBatchBuilding) return true;
|
||||
_alterPathRendererIds.Add(pathId);
|
||||
return false;
|
||||
}
|
||||
@@ -266,7 +283,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RefreshPathUV))]
|
||||
private static bool CargoTraffic_RefreshPathUV_Prefix(int pathId)
|
||||
{
|
||||
if (!IsBatchBuilding) return true;
|
||||
if (!_isBatchBuilding) return true;
|
||||
_refreshPathUVIds.Add(pathId);
|
||||
return false;
|
||||
}
|
||||
@@ -277,7 +294,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RefreshPathBatchesBuffers))]
|
||||
private static bool CargoTraffic_RefreshBeltBatchesBuffers_Prefix()
|
||||
{
|
||||
return !DisableRefreshBatchesBuffers;
|
||||
return !_disableRefreshBatchesBuffers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,17 +303,17 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
private static void PlanetData_NotifyFactoryLoaded_Postfix(PlanetData __instance)
|
||||
{
|
||||
var main = GameMain.instance;
|
||||
if (main != null && main._running)
|
||||
if (main != null && main._running && __instance.factory?.planet?.data != null)
|
||||
{
|
||||
ArrivePlanet(__instance.factory);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GameMain_Begin_Postfix_For_ImmBuild()
|
||||
private static void OnGameBegin_For_ImmBuild()
|
||||
{
|
||||
if (DSPGame.IsMenuDemo) return;
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory != null)
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
ArrivePlanet(factory);
|
||||
}
|
||||
@@ -378,7 +395,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory != null)
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
ArrivePlanet(factory);
|
||||
}
|
||||
@@ -419,6 +436,92 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.FactoryConstructionSystemGameTick))]
|
||||
private static void GameLogic_FactoryConstructionSystemGameTick_Prefix(GameLogic __instance)
|
||||
{
|
||||
var time = __instance.timei;
|
||||
if (time % 6 != 0) return;
|
||||
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;
|
||||
var total = factory.prebuildCursor - 1;
|
||||
var stepCount = total switch
|
||||
{
|
||||
< 256 => 1,
|
||||
< 2048 => 3,
|
||||
< 16384 => 10,
|
||||
_ => 20,
|
||||
};
|
||||
var step = (int)(time / 6 % stepCount);
|
||||
var start = 1 + total * step / stepCount;
|
||||
var end = 1 + total * (step + 1) / stepCount;
|
||||
for (var i = start; i < end; i++)
|
||||
{
|
||||
ref var prebuild = ref factory.prebuildPool[i];
|
||||
if (prebuild.id != i || prebuild.isDestroyed) continue;
|
||||
if (prebuild.itemRequired > 0)
|
||||
{
|
||||
int itemId = prebuild.protoId;
|
||||
int count = prebuild.itemRequired;
|
||||
player.package.TakeTailItems(ref itemId, ref count, out var _, false);
|
||||
if (count > 0)
|
||||
{
|
||||
prebuild.itemRequired -= count;
|
||||
if (prebuild.itemRequired <= 0)
|
||||
{
|
||||
CargoTrafficPatch.InstantBuild(player, factory, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CargoTrafficPatch.IsBatchBuilding)
|
||||
{
|
||||
for (var i = start - 1; i > 0; i--)
|
||||
{
|
||||
ref var prebuild = ref factory.prebuildPool[i];
|
||||
if (prebuild.id != i || prebuild.isDestroyed) continue;
|
||||
if (prebuild.itemRequired > 0)
|
||||
{
|
||||
int itemId = prebuild.protoId;
|
||||
int count = prebuild.itemRequired;
|
||||
player.package.TakeTailItems(ref itemId, ref count, out var _, false);
|
||||
if (count > 0)
|
||||
{
|
||||
prebuild.itemRequired -= count;
|
||||
if (prebuild.itemRequired <= 0)
|
||||
{
|
||||
CargoTrafficPatch.InstantBuild(player, factory, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = end; i <= total; i++)
|
||||
{
|
||||
ref var prebuild = ref factory.prebuildPool[i];
|
||||
if (prebuild.id != i || prebuild.isDestroyed) continue;
|
||||
if (prebuild.itemRequired > 0)
|
||||
{
|
||||
int itemId = prebuild.protoId;
|
||||
int count = prebuild.itemRequired;
|
||||
player.package.TakeTailItems(ref itemId, ref count, out var _, false);
|
||||
if (count > 0)
|
||||
{
|
||||
prebuild.itemRequired -= count;
|
||||
if (prebuild.itemRequired <= 0)
|
||||
{
|
||||
CargoTrafficPatch.InstantBuild(player, factory, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CargoTrafficPatch.EndBatchBuilding(factory);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(ConstructionSystem), nameof(ConstructionSystem.AddBuildTargetToModules))]
|
||||
@@ -458,7 +561,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
private static void UXAssist_PlanetFunctions_BuildOrbitalCollectors_Postfix()
|
||||
{
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory != null)
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
ArrivePlanet(factory);
|
||||
}
|
||||
@@ -472,7 +575,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
var factory = GameMain.mainPlayer?.factory;
|
||||
if (factory != null)
|
||||
if (factory?.planet?.data != null)
|
||||
{
|
||||
ArrivePlanet(factory);
|
||||
}
|
||||
@@ -485,7 +588,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
[ArgumentType.Ref, ArgumentType.Ref, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal])]
|
||||
public static bool TakeTailItemsPatch(StorageComponent __instance, int itemId)
|
||||
{
|
||||
if (__instance == null || __instance.id != GameMain.mainPlayer.package.id) return true;
|
||||
if (__instance == null || GameMain.mainPlayer == null || __instance.id != GameMain.mainPlayer.package.id) return true;
|
||||
if (itemId <= 0) return true;
|
||||
if (_canBuildItems == null)
|
||||
{
|
||||
@@ -500,7 +603,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
public static void GetItemCountPatch(StorageComponent __instance, int itemId, ref int __result)
|
||||
{
|
||||
if (__result > 99) return;
|
||||
if (__instance == null || __instance.id != GameMain.mainPlayer.package.id) return;
|
||||
if (__instance == null || GameMain.mainPlayer == null || __instance.id != GameMain.mainPlayer.package.id) return;
|
||||
if (itemId <= 0) return;
|
||||
if (_canBuildItems == null)
|
||||
{
|
||||
@@ -622,19 +725,19 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
public byte Stack;
|
||||
public byte Inc;
|
||||
public int Progress;
|
||||
public Tuple<int, float>[] Sources;
|
||||
public (int itemId, float itemCount, bool isExtra)[] Sources;
|
||||
public float[] SourceProgress;
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
InitSignalBelts();
|
||||
GameLogicProc.OnGameBegin += GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin -= GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
_initialized = false;
|
||||
_signalBelts = null;
|
||||
_signalBeltsCapacity = 0;
|
||||
@@ -673,13 +776,44 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnUseProliferatorChanged()
|
||||
{
|
||||
if (_signalBelts == null) return;
|
||||
var factories = GameMain.data?.factories;
|
||||
if (factories == null) return;
|
||||
var factoryCount = GameMain.data.factoryCount;
|
||||
var altFormat = BeltSignalNumberAltFormat.Value;
|
||||
for (var i = Math.Min(_signalBelts.Length, factoryCount) - 1; i >= 0; i--)
|
||||
{
|
||||
var factory = factories[i];
|
||||
var cargoTraffic = factory?.cargoTraffic;
|
||||
if (cargoTraffic == null) continue;
|
||||
var entitySignPool = factory.entitySignPool;
|
||||
if (entitySignPool == null) continue;
|
||||
var belts = _signalBelts[i];
|
||||
if (belts == null) continue;
|
||||
foreach (var pair in belts)
|
||||
{
|
||||
var beltId = pair.Key;
|
||||
ref var belt = ref cargoTraffic.beltPool[beltId];
|
||||
if (belt.id != beltId) continue;
|
||||
var signalBelt = pair.Value;
|
||||
signalBelt.Progress = 0;
|
||||
signalBelt.Sources = null;
|
||||
signalBelt.SourceProgress = null;
|
||||
AddSourcesToBeltSignal(signalBelt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitSignalBelts()
|
||||
{
|
||||
if (!GameMain.isRunning) return;
|
||||
if (DSPGame.IsMenuDemo) return;
|
||||
InitItemSources();
|
||||
_signalBelts = new Dictionary<int, BeltSignal>[64];
|
||||
_signalBeltsCapacity = 64;
|
||||
_portalFrom = new Dictionary<long, int>();
|
||||
_portalTo = new Dictionary<int, HashSet<long>>();
|
||||
_portalFrom = [];
|
||||
_portalTo = [];
|
||||
|
||||
var factories = GameMain.data?.factories;
|
||||
if (factories == null) return;
|
||||
@@ -735,7 +869,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
if (obj != null) return obj;
|
||||
}
|
||||
|
||||
obj = new Dictionary<int, BeltSignal>();
|
||||
obj = [];
|
||||
_signalBelts[index] = obj;
|
||||
return obj;
|
||||
}
|
||||
@@ -777,13 +911,15 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var signalBelts = GetOrCreateSignalBelts(factory);
|
||||
if (signalBelts.TryGetValue(beltId, out var oldBeltSignal))
|
||||
{
|
||||
if (oldBeltSignal.SignalId == signalId && oldBeltSignal.SpeedLimit == speedLimit && oldBeltSignal.Stack == stack && oldBeltSignal.Inc == inc) return;
|
||||
oldBeltSignal.SpeedLimit = speedLimit;
|
||||
oldBeltSignal.Stack = (byte)stack;
|
||||
oldBeltSignal.Inc = (byte)inc;
|
||||
oldBeltSignal.Progress = 0;
|
||||
if (oldBeltSignal.SignalId == signalId) return;
|
||||
oldBeltSignal.SignalId = signalId;
|
||||
AddSourcesToBeltSignal(oldBeltSignal, signalId);
|
||||
oldBeltSignal.Sources = null;
|
||||
oldBeltSignal.SourceProgress = null;
|
||||
AddSourcesToBeltSignal(oldBeltSignal);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -794,27 +930,47 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
Stack = (byte)stack,
|
||||
Inc = (byte)inc
|
||||
};
|
||||
if (signalId >= 1000)
|
||||
{
|
||||
AddSourcesToBeltSignal(beltSignal, signalId);
|
||||
}
|
||||
|
||||
AddSourcesToBeltSignal(beltSignal);
|
||||
signalBelts[beltId] = beltSignal;
|
||||
}
|
||||
|
||||
private static void AddSourcesToBeltSignal(BeltSignal beltSignal, int itemId)
|
||||
private static void AddSourcesToBeltSignal(BeltSignal beltSignal)
|
||||
{
|
||||
var itemId = beltSignal.SignalId;
|
||||
if (itemId < 1000) return;
|
||||
var result = new Dictionary<int, float>();
|
||||
var extra = new Dictionary<int, float>();
|
||||
CalculateAllProductions(result, extra, itemId);
|
||||
var sprayedCount = 0f;
|
||||
CalculateAllProductions(result, extra, ref sprayedCount, itemId);
|
||||
|
||||
var proliferatorCount = 0f;
|
||||
if (result.TryGetValue(1143, out var pv))
|
||||
{
|
||||
proliferatorCount = pv;
|
||||
result.Remove(1143);
|
||||
}
|
||||
if (BeltSignalUseProliferatorEnabled.Value)
|
||||
{
|
||||
if (beltSignal.Inc / beltSignal.Stack >= 4)
|
||||
{
|
||||
sprayedCount += 1f;
|
||||
}
|
||||
if (sprayedCount > 0)
|
||||
{
|
||||
proliferatorCount += sprayedCount / ProliferatorSpayCount;
|
||||
}
|
||||
}
|
||||
if (proliferatorCount > 0f)
|
||||
{
|
||||
foreach (var p in ProliferatorSources)
|
||||
{
|
||||
result[p.Item1] = (result.TryGetValue(p.Item1, out var v) ? v : 0) + p.Item2 * proliferatorCount / ProliferatorDenom;
|
||||
}
|
||||
}
|
||||
|
||||
result.Remove(itemId);
|
||||
|
||||
foreach (var p in extra)
|
||||
{
|
||||
result[p.Key] = (result.TryGetValue(p.Key, out var v) ? v : 0) + p.Value;
|
||||
}
|
||||
var cnt = result.Count;
|
||||
var cnt = result.Count + extra.Count;
|
||||
if (cnt == 0)
|
||||
{
|
||||
beltSignal.Sources = null;
|
||||
@@ -822,11 +978,15 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
return;
|
||||
}
|
||||
|
||||
var items = new Tuple<int, float>[cnt];
|
||||
var items = new (int itemId, float itemCount, bool isExtra)[cnt];
|
||||
var progress = new float[cnt];
|
||||
foreach (var p in extra)
|
||||
{
|
||||
items[--cnt] = (p.Key, p.Value, true);
|
||||
}
|
||||
foreach (var p in result)
|
||||
{
|
||||
items[--cnt] = Tuple.Create(p.Key, p.Value);
|
||||
items[--cnt] = (p.Key, p.Value, false);
|
||||
}
|
||||
|
||||
beltSignal.Sources = items;
|
||||
@@ -860,16 +1020,15 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
var v = ((long)factory << 32) | (uint)beltId;
|
||||
if (!_portalFrom.TryGetValue(v, out var number)) return;
|
||||
_portalFrom.Remove(beltId);
|
||||
_portalFrom.Remove(v);
|
||||
if (!_portalTo.TryGetValue(number, out var set)) return;
|
||||
set.Remove(v);
|
||||
}
|
||||
|
||||
private static void GameMain_Begin_Postfix()
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
if (DSPGame.IsMenuDemo) return;
|
||||
if (BeltSignalGeneratorEnabled.Value) InitSignalBelts();
|
||||
InitItemSources();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
@@ -1097,13 +1256,13 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var stackf = (float)stack;
|
||||
for (var i = sources.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var newCnt = progress[i] + sources[i].Item2 * stackf;
|
||||
var newCnt = progress[i] + sources[i].itemCount * stackf;
|
||||
if (newCnt > 0)
|
||||
{
|
||||
var itemId = sources[i].Item1;
|
||||
var itemId = sources[i].itemId;
|
||||
var cnt = Mathf.CeilToInt(newCnt);
|
||||
productRegister[itemId] += cnt;
|
||||
consumeRegister[itemId] += cnt;
|
||||
if (!sources[i].isExtra) consumeRegister[itemId] += cnt;
|
||||
progress[i] = newCnt - cnt;
|
||||
}
|
||||
else
|
||||
@@ -1134,6 +1293,14 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
|
||||
/* BEGIN: Item sources calculation */
|
||||
private static readonly int[] ExtraOreItemIds = [1000, 1116, 1120, 1121, 1208, 5201, 5202, 5203, 5204, 5205, 5206];
|
||||
private static readonly HashSet<int> ExtraProliferationItemIds = [1107, 1111, 1125, 1142, 1143, 1202, 1203, 1204, 1205, 1209, 1210, 1301, 1305, 1401, 1402, 1403, 1405, 1406, 1502, 1503, 1802, 6001, 6003, 6004, 6005, 6006];
|
||||
private static readonly HashSet<int> NoProliferationItemIds = [1126, 6002];
|
||||
// All source items used to create 25 proliferators mk.III (not self-sprayed)
|
||||
private static readonly List<(int, float)> ProliferatorSources = [(1015, 60f), (1124, 20f), (1006, 64f), (1012, 16f), (1112, 32f), (1141, 64f), (1142, 40f), (1143, 25f)];
|
||||
private const float ProliferatorDenom = 21f;
|
||||
// One sprayed proliferator mk.III can spray 75 items, but one is used for spray itself, so the actual count is 74
|
||||
private const float ProliferatorSpayCount = 74f;
|
||||
private static readonly Dictionary<int, ItemSource> ItemSources = [];
|
||||
private static bool _itemSourcesInitialized;
|
||||
|
||||
@@ -1160,7 +1327,12 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
}
|
||||
|
||||
ItemSources[1208] = new ItemSource { Count = 1 };
|
||||
// 水、硫酸、氢、重氢、光子
|
||||
foreach (var itemId in ExtraOreItemIds)
|
||||
{
|
||||
ItemSources[itemId] = new ItemSource { Count = 1 };
|
||||
}
|
||||
|
||||
var recipes = LDB.recipes.dataArray;
|
||||
foreach (var recipe in recipes)
|
||||
{
|
||||
@@ -1171,7 +1343,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
if (ItemSources.ContainsKey(res[i])) continue;
|
||||
var rs = new ItemSource { Count = rescnt[i], From = new Dictionary<int, float>() };
|
||||
var rs = new ItemSource { Count = rescnt[i], From = [] };
|
||||
var it = recipe.Items;
|
||||
var itcnt = recipe.ItemCounts;
|
||||
var len2 = it.Length;
|
||||
@@ -1182,7 +1354,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
|
||||
if (len > 1)
|
||||
{
|
||||
rs.Extra = new Dictionary<int, float>();
|
||||
rs.Extra = [];
|
||||
for (var k = 0; k < len; k++)
|
||||
{
|
||||
if (i != k)
|
||||
@@ -1233,7 +1405,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
_itemSourcesInitialized = true;
|
||||
}
|
||||
|
||||
private static void CalculateAllProductions(IDictionary<int, float> result, IDictionary<int, float> extra, int itemId, float count = 1f)
|
||||
private static void CalculateAllProductions(IDictionary<int, float> result, IDictionary<int, float> extra, ref float sprayedCount, int itemId, float count = 1f)
|
||||
{
|
||||
if (!ItemSources.TryGetValue(itemId, out var itemSource))
|
||||
{
|
||||
@@ -1255,10 +1427,47 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
}
|
||||
|
||||
if (itemSource.From == null) return;
|
||||
if (itemId == 1143 || itemSource.From == null) return;
|
||||
var useProliferator = BeltSignalUseProliferatorEnabled.Value;
|
||||
if (useProliferator && ExtraProliferationItemIds.Contains(itemId))
|
||||
{
|
||||
times *= 0.8f;
|
||||
}
|
||||
foreach (var p in itemSource.From)
|
||||
{
|
||||
CalculateAllProductions(result, extra, p.Key, times * p.Value);
|
||||
var value = p.Value * times;
|
||||
if (useProliferator && !NoProliferationItemIds.Contains(p.Key)) sprayedCount += value;
|
||||
if (extra.TryGetValue(p.Key, out var rcount))
|
||||
{
|
||||
if (value <= rcount)
|
||||
{
|
||||
if (value == rcount)
|
||||
{
|
||||
extra.Remove(p.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
extra[p.Key] = rcount - value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
extra.Remove(p.Key);
|
||||
value -= rcount;
|
||||
}
|
||||
if (result.TryGetValue(p.Key, out rcount))
|
||||
{
|
||||
rcount -= value;
|
||||
if (rcount <= 0)
|
||||
{
|
||||
result.Remove(p.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
result[p.Key] = rcount;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
CalculateAllProductions(result, extra, ref sprayedCount, p.Key, value);
|
||||
}
|
||||
}
|
||||
/* END: Item sources calculation */
|
||||
@@ -1440,6 +1649,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
|
||||
// Iterate all factories and update wind turbines power nodes
|
||||
if (GameMain.data == null) return;
|
||||
foreach (var factory in GameMain.data.factories)
|
||||
{
|
||||
var powerSystem = factory?.powerSystem;
|
||||
@@ -1467,156 +1677,6 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
}
|
||||
|
||||
private class GreaterPowerUsageInLogistics : PatchImpl<GreaterPowerUsageInLogistics>
|
||||
{
|
||||
protected override void OnEnable()
|
||||
{
|
||||
var window = UIRoot.instance?.uiGame?.stationWindow;
|
||||
if (window == null) return;
|
||||
window._Close();
|
||||
window.maxMiningSpeedSlider.maxValue = 27f;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
var window = UIRoot.instance?.uiGame?.stationWindow;
|
||||
if (window == null) return;
|
||||
window._Close();
|
||||
window.maxMiningSpeedSlider.maxValue = 20f;
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnStationIdChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnStationIdChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.Start().Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
Transpilers.EmitDelegate((UIStationWindow window) =>
|
||||
{
|
||||
window.maxMiningSpeedSlider.maxValue = 27f;
|
||||
})
|
||||
).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.maxChargePowerSlider))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Ldc_I4 && ci.OperandIs(0xC350)),
|
||||
new CodeMatch(OpCodes.Conv_I8)
|
||||
);
|
||||
var pos = matcher.Pos + 1;
|
||||
matcher.Advance(5).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Conv_R4),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertySetter(typeof(Slider), nameof(Slider.value)))
|
||||
);
|
||||
var pos2 = matcher.Pos + 2;
|
||||
matcher.Start().Advance(pos);
|
||||
var ldvar = matcher.InstructionAt(1).Clone();
|
||||
var locWorkEnergyPerTick = matcher.InstructionAt(-2).operand;
|
||||
matcher.RemoveInstructions(pos2 - pos).InsertAndAdvance(
|
||||
ldvar,
|
||||
new CodeInstruction(OpCodes.Ldloc_S, locWorkEnergyPerTick),
|
||||
Transpilers.EmitDelegate((UIStationWindow window, long maxWorkEnergy, long workEnergyPerTick) =>
|
||||
{
|
||||
var maxSliderValue = maxWorkEnergy / 50000L;
|
||||
window.maxChargePowerSlider.maxValue = maxSliderValue + 9;
|
||||
window.maxChargePowerSlider.minValue = maxWorkEnergy / 500000L;
|
||||
if (workEnergyPerTick <= maxWorkEnergy)
|
||||
window.maxChargePowerSlider.Set(workEnergyPerTick / 50000L, false);
|
||||
else
|
||||
window.maxChargePowerSlider.Set(maxSliderValue + (workEnergyPerTick - 1) / maxWorkEnergy + 1, false);
|
||||
})
|
||||
);
|
||||
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.maxMiningSpeedSlider))),
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.factorySystem))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.minerPool))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.minerId))),
|
||||
new CodeMatch(OpCodes.Ldelema, typeof(MinerComponent)),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(MinerComponent), nameof(MinerComponent.speed)))
|
||||
);
|
||||
pos = matcher.Pos + 9;
|
||||
matcher.Advance(5).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Conv_R4),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertySetter(typeof(Slider), nameof(Slider.value)))
|
||||
);
|
||||
pos2 = matcher.Pos;
|
||||
matcher.Start().Advance(pos).RemoveInstructions(pos2 - pos).Insert(
|
||||
Transpilers.EmitDelegate((int speed) =>
|
||||
{
|
||||
if (speed <= 30000)
|
||||
return (speed - 10000) / 1000;
|
||||
return (speed - 30000) / 10000 + 20;
|
||||
})
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnMaxMiningSpeedChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnMaxMiningSpeedChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Ldc_I4 && ci.OperandIs(10000)),
|
||||
new CodeMatch(OpCodes.Ldarg_1)
|
||||
);
|
||||
var pos = matcher.Pos;
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stloc_1)
|
||||
);
|
||||
var pos2 = matcher.Pos;
|
||||
matcher.Start().Advance(pos);
|
||||
var labels = matcher.Labels;
|
||||
matcher.RemoveInstructions(pos2 - pos);
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_1).WithLabels(labels),
|
||||
Transpilers.EmitDelegate((float value) =>
|
||||
{
|
||||
var intval = (int)(value + 0.5f);
|
||||
if (intval <= 20)
|
||||
return intval * 1000 + 10000;
|
||||
return (intval - 20) * 10000 + 30000;
|
||||
})
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnMaxChargePowerSliderValueChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnMaxChargePowerSliderValueChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.factory))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetFactory), nameof(PlanetFactory.powerSystem))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PowerSystem), nameof(PowerSystem.consumerPool)))
|
||||
);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
Transpilers.EmitDelegate((UIStationWindow window, float value) =>
|
||||
{
|
||||
float prevMax = window.workEnergyPrefab * 5L / 50000L;
|
||||
if (value <= prevMax)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return prevMax * (value - prevMax + 1);
|
||||
}),
|
||||
new CodeInstruction(OpCodes.Starg_S, 1)
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
|
||||
private class ControlPanelRemoteLogistics : PatchImpl<ControlPanelRemoteLogistics>
|
||||
{
|
||||
[HarmonyTranspiler]
|
||||
|
||||
@@ -42,13 +42,14 @@ public static class GamePatch
|
||||
protected override void OnEnable()
|
||||
{
|
||||
if (_savedDeterminators == null) return;
|
||||
var abnormalLogic = GameMain.gameScenario.abnormalityLogic;
|
||||
var abnormalLogic = GameMain.gameScenario?.abnormalityLogic;
|
||||
if (abnormalLogic == null) return;
|
||||
foreach (var p in _savedDeterminators)
|
||||
{
|
||||
p.Value.OnUnregEvent();
|
||||
}
|
||||
|
||||
abnormalLogic.determinators = new Dictionary<int, AbnormalityDeterminator>();
|
||||
abnormalLogic.determinators = [];
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
@@ -81,7 +82,7 @@ public static class GamePatch
|
||||
{
|
||||
_savedDeterminators = __instance.determinators;
|
||||
if (!AbnormalDisablerEnabled.Value) return;
|
||||
__instance.determinators = new Dictionary<int, AbnormalityDeterminator>();
|
||||
__instance.determinators = [];
|
||||
foreach (var p in _savedDeterminators)
|
||||
{
|
||||
p.Value.OnUnregEvent();
|
||||
@@ -140,7 +141,7 @@ public static class GamePatch
|
||||
var pos = matcher.Pos;
|
||||
/* Remove Shift+F4 part of the method */
|
||||
matcher.Start().RemoveInstructions(pos).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(GameMain), "get_sandboxToolsEnabled")),
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(GameMain), nameof(GameMain.sandboxToolsEnabled))),
|
||||
new CodeMatch(OpCodes.Ldc_I4_0),
|
||||
new CodeMatch(OpCodes.Ceq)
|
||||
);
|
||||
@@ -297,7 +298,7 @@ public static class GamePatch
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UITechNode), nameof(UITechNode.tree))),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(UITechTree), "get_selected"))
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(UITechTree), nameof(UITechTree.selected)))
|
||||
);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
|
||||
@@ -6,6 +6,7 @@ using HarmonyLib;
|
||||
using UXAssist.Common;
|
||||
|
||||
namespace CheatEnabler.Patches;
|
||||
|
||||
public static class PlanetPatch
|
||||
{
|
||||
public static ConfigEntry<bool> WaterPumpAnywhereEnabled;
|
||||
@@ -53,6 +54,92 @@ public static class PlanetPatch
|
||||
|
||||
private class TerraformAnyway : PatchImpl<TerraformAnyway>
|
||||
{
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.DetermineReforms))]
|
||||
private static IEnumerable<CodeInstruction> BuildTool_BlueprintPaste_DetermineReforms_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(BuildTool), nameof(BuildTool.player))),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.sandCount))),
|
||||
new CodeMatch(ci => ci.IsStloc())
|
||||
).Advance(4).MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Conv_I8),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Bge || ci.opcode == OpCodes.Bge_S)
|
||||
);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.RemoveInstructions(3);
|
||||
matcher.Labels.AddRange(labels);
|
||||
matcher.Opcode = OpCodes.Br;
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(BuildTool_Reform), nameof(BuildTool_Reform.RemoveBasePit))]
|
||||
private static IEnumerable<CodeInstruction> BuildTool_Reform_RemoveBasePit_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BuildTool_Reform), nameof(BuildTool_Reform.circlePointCount))),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Blt || ci.opcode == OpCodes.Blt_S)
|
||||
).RemoveInstructions(2).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0)
|
||||
).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(BuildTool), nameof(BuildTool.player))),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.sandCount))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Conv_I8),
|
||||
new CodeMatch(OpCodes.Sub)
|
||||
).Advance(6).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldc_I8, 0L),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), nameof(Math.Max), [typeof(long), typeof(long)]))
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIRemoveBasePitButton), nameof(UIRemoveBasePitButton.OnRemoveButtonClick))]
|
||||
[HarmonyPatch(typeof(UIRemoveBasePitButton), nameof(UIRemoveBasePitButton._OnUpdate))]
|
||||
private static IEnumerable<CodeInstruction> UIRemoveBasePitButton_OnRemoveButtonClick_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIRemoveBasePitButton), nameof(UIRemoveBasePitButton.pointCount))),
|
||||
new CodeMatch(OpCodes.Sub),
|
||||
new CodeMatch(OpCodes.Ldc_I4_0),
|
||||
new CodeMatch(OpCodes.Clt)
|
||||
);
|
||||
if (matcher.IsValid)
|
||||
{
|
||||
matcher.RemoveInstructions(2).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
matcher.Start();
|
||||
}
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIRemoveBasePitButton), nameof(UIRemoveBasePitButton.player))),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.sandCount))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Conv_I8),
|
||||
new CodeMatch(OpCodes.Sub)
|
||||
).Advance(6).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldc_I8, 0L),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), nameof(Math.Max), [typeof(long), typeof(long)]))
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(BuildTool_Reform), nameof(BuildTool_Reform.ReformAction))]
|
||||
private static IEnumerable<CodeInstruction> BuildTool_Reform_ReformAction_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
@@ -65,13 +152,13 @@ public static class PlanetPatch
|
||||
).RemoveInstructions(2).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0)
|
||||
).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), "get_sandCount"))
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.sandCount)))
|
||||
).Advance(1).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Conv_I8),
|
||||
new CodeMatch(OpCodes.Sub)
|
||||
new CodeMatch(OpCodes.Conv_I8),
|
||||
new CodeMatch(OpCodes.Sub)
|
||||
).Advance(2).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldc_I8, 0L),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), "Max", [typeof(long), typeof(long)]))
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), nameof(Math.Max), [typeof(long), typeof(long)]))
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
* Eject anyway
|
||||
* Unlock Dyson Sphere max orbit radius
|
||||
* Complete Dyson Sphere Shells instantly
|
||||
* Remove all frames on Dyson Sphere
|
||||
* Buttons for creating illegal Dyson Sphere Shells, you must enable `IllegalDysonShellFunctionsEnabled` of `DysonSphere` section in config to see the last 2 buttons.
|
||||
* Generate an illegal dyson shell
|
||||
* Keep max production shells and remove others
|
||||
@@ -123,6 +124,7 @@
|
||||
* 全球弹射
|
||||
* 解锁戴森球最大轨道半径
|
||||
* 立即完成戴森壳建造
|
||||
* 移除戴森球上的所有框架
|
||||
* 用于制作仙术戴森壳的按钮,你必须在设置文件里开启`DysonSphere`分类的`IllegalDysonShellFunctionsEnabled`才能看到后面两个按钮
|
||||
* 生成单层仙术戴森壳
|
||||
* 保留发电量最高的戴森壳并移除其他戴森壳
|
||||
|
||||
@@ -39,6 +39,10 @@ public static class UIConfigWindow
|
||||
I18N.Add("Build without condition", "Build without condition check", "无条件建造");
|
||||
I18N.Add("No collision", "No collision", "无碰撞");
|
||||
I18N.Add("Belt signal generator", "Belt signal generator", "传送带信号物品生成");
|
||||
I18N.Add("Count proliferators used for raws/intermediates and finished products", "Use proliferators for raws/intermediates and finished products", "原料、中间产物以及成品使用增产剂");
|
||||
I18N.Add("Count proliferators used for raws/intermediates and finished products tips",
|
||||
"Following items use extra products: Titanium Alloy, Prism, Frame Material, Proliferator Mk.II, Proliferator Mk.III, Magnetic Coil, Electric Motor, Electromagnetic Turbine, Super-magnetic Ring, Circuit Board, Thruster, Reinforced Thruster, Plasma Exciter, Particle Broadband, Graviton Lens, Quantum Chip, Annihilation Constraint Sphere, Deuteron Fuel Rod, Space Warper, Dyson Sphere Component, Small Carrier Rocket, Electromagnetic Matrix, Structure Matrix, Information Matrix, Gravity Matrix, Universe Matrix\nFollowing items does not use proliferators: Casimir Crystal, Energy Matrix\nOther items use speed up production.",
|
||||
"以下物品使用额外产出: 钛合金, 棱镜, 框架材料, 增产剂 Mk.II, 增产剂 Mk.III, 磁线圈, 电动机, 电磁涡轮, 超级磁场环, 电路板, 推进器, 加力推进器, 电浆激发器, 粒子宽带, 引力透镜, 量子芯片, 湮灭约束球, 氘核燃料棒, 空间翘曲器, 戴森球组件, 小型运载火箭, 电磁矩阵, 结构矩阵, 信息矩阵, 引力矩阵, 宇宙矩阵\n以下物品不使用增产剂: 卡西米尔晶体, 能量矩阵\n其他物品使用加速生产");
|
||||
I18N.Add("Belt signal alt format", "Belt signal alt format", "传送带信号替换格式");
|
||||
I18N.Add("Belt signal alt format tips",
|
||||
"Belt signal number format alternative format:\n AAAABC by default\n BCAAAA as alternative\nAAAA=generation speed in minutes, B=proliferate points, C=stack count",
|
||||
@@ -53,8 +57,6 @@ public static class UIConfigWindow
|
||||
I18N.Add("Boost fuel power 2", "(x20,000 for deuteron, x10,000 for antimatter)", "(氘核燃料棒x20,000,反物质燃料棒x10,000)");
|
||||
I18N.Add("Wind Turbines do global power coverage", "Wind Turbines do global power coverage", "风力涡轮机供电覆盖全球");
|
||||
I18N.Add("Boost geothermal power", "Boost geothermal power(x50,000)", "提升地热发电(x50,000)");
|
||||
I18N.Add("Increase maximum power usage in Logistic Stations and Advanced Mining Machines", "Increase maximum power usage in Logistic Stations and Advanced Mining Machines",
|
||||
"提升物流塔和大型采矿机的最大功耗");
|
||||
I18N.Add("Retrieve/Place items from/to remote planets on logistics control panel", "Retrieve/Place items from/to remote planets on logistics control panel", "在物流总控面板上可以从非本地行星取放物品");
|
||||
I18N.Add("Infinite Natural Resources", "Infinite natural resources", "自然资源采集不消耗");
|
||||
I18N.Add("Fast Mining", "Fast mining", "高速采集");
|
||||
@@ -68,7 +70,9 @@ 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 (!!All shells will be removed first!!)", "生成单层仙术戴森壳(!!会先删除全部的壳!!)");
|
||||
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", "快速生成仙术戴森壳");
|
||||
@@ -191,13 +195,14 @@ public static class UIConfigWindow
|
||||
y += 26f;
|
||||
var cb3 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalCountRecipeEnabled, "Count all raws and intermediates in statistics", 13);
|
||||
y += 26f;
|
||||
var cb4 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalNumberAltFormat, "Belt signal alt format", 13);
|
||||
x += cb4.Width + 5f;
|
||||
var cb4 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalUseProliferatorEnabled, "Count proliferators used for raws/intermediates and finished products", 13);
|
||||
y += 6f;
|
||||
var tip1 = wnd.AddTipsButton2(x, y, tab2, "Belt signal alt format", "Belt signal alt format tips", "belt-signal-alt-format-tips");
|
||||
var tip1 = wnd.AddTipsButton2(x + cb4.Width + 5f, y, tab2, "Count proliferators used for raws/intermediates and finished products", "Count proliferators used for raws/intermediates and finished products tips", "count-proliferators-used-for-raws-intermediates-and-finished-products-tips");
|
||||
y += 20f;
|
||||
var cb5 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalNumberAltFormat, "Belt signal alt format", 13);
|
||||
y += 6f;
|
||||
var tip2 = wnd.AddTipsButton2(x + cb5.Width + 5f, y, tab2, "Belt signal alt format", "Belt signal alt format tips", "belt-signal-alt-format-tips");
|
||||
x = 0f;
|
||||
y += 30f;
|
||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.GreaterPowerUsageInLogisticsEnabled, "Increase maximum power usage in Logistic Stations and Advanced Mining Machines");
|
||||
y += 36f;
|
||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.ControlPanelRemoteLogisticsEnabled, "Retrieve/Place items from/to remote planets on logistics control panel");
|
||||
{
|
||||
@@ -211,7 +216,9 @@ public static class UIConfigWindow
|
||||
cb2.gameObject.SetActive(on);
|
||||
cb3.gameObject.SetActive(on);
|
||||
cb4.gameObject.SetActive(on);
|
||||
cb5.gameObject.SetActive(on);
|
||||
tip1.gameObject.SetActive(on);
|
||||
tip2.gameObject.SetActive(on);
|
||||
}
|
||||
}
|
||||
x = 350f;
|
||||
@@ -301,15 +308,23 @@ public static class UIConfigWindow
|
||||
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 += 36f;
|
||||
wnd.AddButton(x, y, 300f, tab4, "Remove all frames on Dyson Sphere", 16, "button-remove-all-frames-on-dyson-sphere", DysonSphereFunctions.RemoveAllFrames);
|
||||
{
|
||||
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,
|
||||
@@ -327,7 +342,7 @@ public static class UIConfigWindow
|
||||
y = originalY;
|
||||
var btn4 = wnd.AddButton(x, y, 300f, tab4, "Generate illegal dyson shell quickly", 16, "button-generate-illegal-dyson-shells-quickly", () =>
|
||||
{
|
||||
UIMessageBox.Show("Generate illegal dyson shell".Translate(), "WARNING: This operation can be very slow, continue?".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.WARNING, null,
|
||||
UIMessageBox.Show("Generate illegal dyson shell quickly".Translate(), "WARNING: This operation can be very slow, continue?".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.WARNING, null,
|
||||
() => { DysonSphereFunctions.CreateIllegalDysonShellQuickly(DysonSphereFunctions.ShellsCountForFunctions.Value); });
|
||||
});
|
||||
y += 30f;
|
||||
@@ -340,6 +355,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);
|
||||
@@ -373,6 +389,7 @@ public static class UIConfigWindow
|
||||
|
||||
private static void UpdateButtons()
|
||||
{
|
||||
if (_resignGameBtn == null || _clearBanBtn == null) return;
|
||||
var data = GameMain.data;
|
||||
if (data == null) return;
|
||||
var resignEnabled = data.account != AccountData.me;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "CheatEnabler",
|
||||
"version_number": "2.4.0",
|
||||
"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": [
|
||||
|
||||
+124
-16
@@ -4,7 +4,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UXAssist", "UXAssist\UXAssi
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CheatEnabler", "CheatEnabler\CheatEnabler.csproj", "{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogisticHub", "LogisticHub\LogisticHub.csproj", "{7149D717-C913-4153-9425-38CB9D087F83}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogisticMiner", "LogisticMiner\LogisticMiner.csproj", "{7149D717-C913-4153-9425-38CB9D087F83}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HideTips", "HideTips\HideTips.csproj", "{4EABD71D-477F-448B-801B-48F8745A3FA7}"
|
||||
EndProject
|
||||
@@ -19,76 +19,184 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OverclockEverything", "Over
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MechaDronesTweaks", "MechaDronesTweaks\MechaDronesTweaks.csproj", "{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LabOpt", "LabOpt\LabOpt.csproj", "{DD76B77C-68D8-4A4C-B98E-CBEECEDC49FB}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{F2D5EBE8-7D9D-4572-9A3E-4DD1114FD99F} = {F2D5EBE8-7D9D-4572-9A3E-4DD1114FD99F}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LabOptPreloader", "LabOptPreloader\LabOptPreloader.csproj", "{F2D5EBE8-7D9D-4572-9A3E-4DD1114FD99F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DustbinPreloader", "DustbinPreloader\DustbinPreloader.csproj", "{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoolOpt", "PoolOpt\PoolOpt.csproj", "{8BE61246-2C9D-4088-AA33-5AFF22C5046E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserCloak", "UserCloak\UserCloak.csproj", "{096D2E4B-D1CE-424D-9954-C36A23E9E279}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaScriptEngine", "LuaScriptEngine\LuaScriptEngine.csproj", "{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpdateGameDlls", "UpdateGameDlls\UpdateGameDlls.csproj", "{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Release|x64.Build.0 = Release|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7149D717-C913-4153-9425-38CB9D087F83}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Release|x86.Build.0 = Release|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Release|x64.Build.0 = Release|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{931F0230-5941-4E49-AB19-66921AF14096}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DD76B77C-68D8-4A4C-B98E-CBEECEDC49FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DD76B77C-68D8-4A4C-B98E-CBEECEDC49FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DD76B77C-68D8-4A4C-B98E-CBEECEDC49FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DD76B77C-68D8-4A4C-B98E-CBEECEDC49FB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F2D5EBE8-7D9D-4572-9A3E-4DD1114FD99F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F2D5EBE8-7D9D-4572-9A3E-4DD1114FD99F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F2D5EBE8-7D9D-4572-9A3E-4DD1114FD99F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F2D5EBE8-7D9D-4572-9A3E-4DD1114FD99F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Release|x64.Build.0 = Release|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E9375F0E-26DC-4CEC-80DC-9C48F23340BC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6E73B301-7C7A-4EF4-B0FA-4C6B40F96653}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<!-- Common properties shared by all DSP mod projects -->
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<!-- Set to true in projects that include a CHANGELOG.md in the package -->
|
||||
<PackHasChangelog>false</PackHasChangelog>
|
||||
<!-- Set to true in projects that use the plugins/patchers layout (Dustbin, LabOpt) -->
|
||||
<PackUsePluginsLayout>false</PackUsePluginsLayout>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Common NuGet packages for all mods -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2022.3.62" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Game DLL references (local copies in AssemblyFromGame/) -->
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>$(MSBuildThisFileDirectory)AssemblyFromGame\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>$(MSBuildThisFileDirectory)AssemblyFromGame\UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- .NET Framework reference assemblies (only needed when targeting net*) -->
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- All projects depend on UpdateGameDlls helper to ensure game DLLs are
|
||||
refreshed before any project resolves assembly references. -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)UpdateGameDlls\UpdateGameDlls.csproj"
|
||||
ReferenceOutputAssembly="false"
|
||||
SkipGetTargetFrameworkProperties="true"
|
||||
Private="false" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
|
||||
<!--
|
||||
ZipMod target: assembles a Thunderstore-ready zip under package/.
|
||||
Run explicitly with: dotnet build -t:ZipMod -c Release
|
||||
It does NOT run automatically on every build.
|
||||
|
||||
"Pack" is reserved by the .NET SDK for NuGet packaging, so this target
|
||||
uses the name "ZipMod" to avoid conflict.
|
||||
|
||||
Per-project customisation properties (set in the project's PropertyGroup):
|
||||
PackHasChangelog – set to 'true' to include CHANGELOG.md in the zip
|
||||
PackUsePluginsLayout – set to 'true' for the plugins/patchers folder layout
|
||||
(used by Dustbin and LabOpt)
|
||||
|
||||
Simple layout zips:
|
||||
<AssemblyName>.dll icon.png manifest.json README.md [CHANGELOG.md]
|
||||
plugins/patchers layout zips:
|
||||
plugins/ patchers/ icon.png manifest.json README.md [CHANGELOG.md]
|
||||
-->
|
||||
<Target Name="ZipMod" DependsOnTargets="Build" Condition="'$(PackPreloaderTargetDir)' == ''">
|
||||
<PropertyGroup>
|
||||
<_PackageDir>$(MSBuildProjectDirectory)\package</_PackageDir>
|
||||
<_StagingDir>$(MSBuildProjectDirectory)\obj\pack-staging</_StagingDir>
|
||||
<_ZipPath>$(_PackageDir)\$(ProjectName)-$(Version).zip</_ZipPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Sync manifest.json version_number from .csproj $(Version) before packaging -->
|
||||
<Exec Condition="Exists('$(_PackageDir)\manifest.json')"
|
||||
Command="powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "$f='$(_PackageDir)\manifest.json'; $c=[IO.File]::ReadAllText($f); $c=$c -replace '(\u0022version_number\u0022\s*:\s*\u0022)[^\u0022]*(\u0022)','${1}$(Version)${2}'; [IO.File]::WriteAllText($f,$c,[Text.UTF8Encoding]::new($true))"" />
|
||||
|
||||
<!-- ── plugins/patchers layout: copy DLL into package/plugins/ first ── -->
|
||||
<MakeDir Directories="$(_PackageDir)\plugins"
|
||||
Condition="'$(PackUsePluginsLayout)' == 'true'" />
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(_PackageDir)\plugins"
|
||||
Condition="'$(PackUsePluginsLayout)' == 'true'" />
|
||||
|
||||
<!-- Collect loose root files (common to both layouts) -->
|
||||
<ItemGroup>
|
||||
<_PackRootFiles Include="$(_PackageDir)\icon.png" />
|
||||
<_PackRootFiles Include="$(_PackageDir)\manifest.json" />
|
||||
<_PackRootFiles Include="$(MSBuildProjectDirectory)\README.md" />
|
||||
<_PackRootFiles Include="$(MSBuildProjectDirectory)\CHANGELOG.md"
|
||||
Condition="'$(PackHasChangelog)' == 'true'" />
|
||||
<!-- Simple layout: also include the DLL itself at the root -->
|
||||
<_PackRootFiles Include="$(TargetPath)"
|
||||
Condition="'$(PackUsePluginsLayout)' != 'true'" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Prepare staging directory -->
|
||||
<RemoveDir Directories="$(_StagingDir)" />
|
||||
<MakeDir Directories="$(_StagingDir)" />
|
||||
|
||||
<!-- Copy loose root files into staging root -->
|
||||
<Copy SourceFiles="@(_PackRootFiles)" DestinationFolder="$(_StagingDir)" />
|
||||
|
||||
<!-- plugins/patchers layout: copy sub-folders into staging (preserve structure) -->
|
||||
<ItemGroup Condition="'$(PackUsePluginsLayout)' == 'true'">
|
||||
<_PluginFiles Include="$(_PackageDir)\plugins\**\*" />
|
||||
<_PatcherFiles Include="$(_PackageDir)\patchers\**\*" />
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(_PluginFiles)"
|
||||
DestinationFiles="@(_PluginFiles->'$(_StagingDir)\plugins\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
Condition="'$(PackUsePluginsLayout)' == 'true'" />
|
||||
<Copy SourceFiles="@(_PatcherFiles)"
|
||||
DestinationFiles="@(_PatcherFiles->'$(_StagingDir)\patchers\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
Condition="'$(PackUsePluginsLayout)' == 'true'" />
|
||||
|
||||
<!-- Delete previous zip if present -->
|
||||
<Delete Files="$(_ZipPath)" Condition="Exists('$(_ZipPath)')" />
|
||||
|
||||
<!-- Create zip using MSBuild ZipDirectory task – no shell, no quoting issues -->
|
||||
<ZipDirectory SourceDirectory="$(_StagingDir)" DestinationFile="$(_ZipPath)" />
|
||||
|
||||
<!-- Clean up staging directory -->
|
||||
<RemoveDir Directories="$(_StagingDir)" />
|
||||
|
||||
<Message Text="ZipMod: created $(_ZipPath)" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<!-- ── Preloader helper target ────────────────────────────────────────────
|
||||
Preloader projects (DustbinPreloader, LabOptPreloader) call this to
|
||||
copy their output DLL into the sibling main mod's patchers/ folder.
|
||||
Set PackPreloaderTargetDir in the preloader's csproj, e.g.:
|
||||
<PackPreloaderTargetDir>..\Dustbin\package\patchers</PackPreloaderTargetDir>
|
||||
──────────────────────────────────────────────────────────────────────── -->
|
||||
<Target Name="CopyToParentPackage" DependsOnTargets="Build"
|
||||
Condition="'$(PackPreloaderTargetDir)' != ''">
|
||||
<MakeDir Directories="$(PackPreloaderTargetDir)" />
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(PackPreloaderTargetDir)" />
|
||||
<Message Text="CopyToParentPackage: copied $(TargetFileName) to $(PackPreloaderTargetDir)" Importance="high" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -77,7 +77,7 @@ public static class BeltSignal
|
||||
SID = ""
|
||||
};
|
||||
p.name = p.Name.Translate();
|
||||
signals.dataArray = signals.dataArray.AddItem(p).ToArray();
|
||||
signals.dataArray = [.. signals.dataArray.AddItem(p)];
|
||||
signals.dataIndices[p.ID] = index;
|
||||
_initialized = true;
|
||||
}
|
||||
@@ -225,11 +225,11 @@ public static class BeltSignal
|
||||
int itemId;
|
||||
if ((itemId = cargoPath.TryPickItem(belt.segIndex + belt.segPivotOffset - 5, 12, out var stack, out _)) <= 0) continue;
|
||||
consumeRegister[itemId] += stack;
|
||||
Dustbin.CalcGetSands(itemId, stack);
|
||||
Dustbin.CalcGetSands(itemId, stack, 0);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class Dustbin : BaseUnityPlugin, IModCanSave, IMultiplayerMod
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int CalcGetSands(int itemId, int count)
|
||||
public static int CalcGetSands(int itemId, int count, int inc)
|
||||
{
|
||||
var sandsPerItem = itemId <= 12000 ? Dustbin.SandsFactors[itemId] : 0;
|
||||
if (sandsPerItem <= 0) return count;
|
||||
|
||||
+3
-23
@@ -1,41 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<BepInExPluginGuid>org.soardev.dustbin</BepInExPluginGuid>
|
||||
<Description>DSP MOD - Dustbin</Description>
|
||||
<Version>1.4.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PackageId>Dustbin</PackageId>
|
||||
<RootNamespace>Dustbin</RootNamespace>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
<PackUsePluginsLayout>true</PackUsePluginsLayout>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.Modding.NebulaMultiplayerModApi" Version="2.0.0" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="assets/icon/signal-410.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>GameAssembly\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
IF NOT EXIST package\plugins (mkdir package\plugins)
copy /y $(TargetPath) package\plugins\
cd package
powershell Compress-Archive -Force -DestinationPath '$(ProjectName)-$(Version).zip' -Path patchers, plugins, icon.png, manifest.json, ../README.md, ../CHANGELOG.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
+48
-8
@@ -148,25 +148,65 @@ public static class StoragePatch
|
||||
_lastStorageId = 0; // Refresh UI to reposition button on client side
|
||||
}
|
||||
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.AddItem), [typeof(int), typeof(int), typeof(int), typeof(int), typeof(bool)],
|
||||
[ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal])]
|
||||
private static IEnumerable<CodeInstruction> StorageComponent_AddItem_HarmonyTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stind_I4)
|
||||
).Advance(1).InsertAndAdvance(
|
||||
var codes = new List<CodeInstruction>(instructions);
|
||||
var matcher = new CodeMatcher(codes, generator);
|
||||
|
||||
// 找到方法开始处
|
||||
// Find the beginning of the method
|
||||
matcher.Start();
|
||||
|
||||
// 定义标签用于跳转
|
||||
// Define label for jump
|
||||
var skipDustbinLogic = generator.DefineLabel();
|
||||
|
||||
// 在方法开始处插入安全检查
|
||||
// Insert safety checks at the beginning of the method
|
||||
matcher.InsertAndAdvance(
|
||||
// 安全检查:确保StorageComponent实例不为null
|
||||
// Safety check: Ensure StorageComponent instance is not null
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Brfalse, skipDustbinLogic),
|
||||
|
||||
// 检查是否是垃圾桶
|
||||
// Check if it's a dustbin
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(StorageComponent), nameof(StorageComponent.IsDustbin))),
|
||||
new CodeInstruction(OpCodes.Brfalse, label1),
|
||||
new CodeInstruction(OpCodes.Brfalse, skipDustbinLogic),
|
||||
|
||||
// 检查count是否大于0
|
||||
// Check if count is greater than 0
|
||||
new CodeInstruction(OpCodes.Ldarg_2),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, skipDustbinLogic),
|
||||
|
||||
// 调用CalcGetSands处理物品销毁和沙子生成
|
||||
// Call CalcGetSands to handle item destruction and sand generation
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Ldarg_2),
|
||||
new CodeInstruction(OpCodes.Ldarg_3),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Dustbin), nameof(Dustbin.CalcGetSands))),
|
||||
new CodeInstruction(OpCodes.Ret)
|
||||
|
||||
// 设置remainInc为0(第5个参数,索引4)
|
||||
// Set remainInc to 0 (5th parameter, index 4)
|
||||
new CodeInstruction(OpCodes.Ldarg, 4),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Stind_I4),
|
||||
|
||||
// 返回count表示成功销毁
|
||||
// Return count to indicate successful destruction
|
||||
new CodeInstruction(OpCodes.Ret),
|
||||
|
||||
// 跳过垃圾桶逻辑的标签
|
||||
// Label to skip dustbin logic
|
||||
new CodeInstruction(OpCodes.Nop).WithLabels(skipDustbinLogic)
|
||||
);
|
||||
matcher.Labels.Add(label1);
|
||||
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>DustbinPreloader</AssemblyName>
|
||||
<Description>DSP MOD - Prealoder for Dustbin</Description>
|
||||
<Description>DSP MOD - Preloader for Dustbin</Description>
|
||||
<Version>1.3.1</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackPreloaderTargetDir>..\Dustbin\package\patchers</PackPreloaderTargetDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="IF NOT EXIST ..\Dustbin\package\patchers (mkdir ..\Dustbin\package\patchers)
copy /y $(TargetPath) ..\Dustbin\package\patchers\" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -1,29 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>HideTips</AssemblyName>
|
||||
<BepInExPluginGuid>org.soardev.hidetips</BepInExPluginGuid>
|
||||
<Description>DSP MOD - HideTips</Description>
|
||||
<Version>1.0.4</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path '$(TargetPath)', package/icon.png, package/manifest.json, README.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
+1
-20
@@ -1,29 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>LabOpt</AssemblyName>
|
||||
<BepInExPluginGuid>org.soardev.labopt</BepInExPluginGuid>
|
||||
<Description>DSP MOD - LabOpt</Description>
|
||||
<Version>0.3.6</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackUsePluginsLayout>true</PackUsePluginsLayout>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
IF NOT EXIST package\plugins (mkdir package\plugins)
copy /y $(TargetPath) package\plugins\
cd package
powershell Compress-Archive -Force -DestinationPath '$(ProjectName)-$(Version).zip' -Path patchers, plugins, icon.png, manifest.json, ../README.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>LabOptPreloader</AssemblyName>
|
||||
<Description>DSP MOD - Prealoder for LabOpt</Description>
|
||||
<Description>DSP MOD - Preloader for LabOpt</Description>
|
||||
<Version>0.2.1</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackPreloaderTargetDir>..\LabOpt\package\patchers</PackPreloaderTargetDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="IF NOT EXIST ..\LabOpt\package\patchers (mkdir ..\LabOpt\package\patchers)
copy /y $(TargetPath) ..\LabOpt\package\patchers\" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using UXAssist.Common;
|
||||
|
||||
namespace LogisticHub;
|
||||
|
||||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
||||
public class LogisticHub : BaseUnityPlugin
|
||||
{
|
||||
public new static readonly BepInEx.Logging.ManualLogSource Logger =
|
||||
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
||||
|
||||
private Type[] _modules;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Module.Miner.Enabled = Config.Bind("Miner", "Enabled", true, "enable/disable this plugin");
|
||||
Module.Miner.OreEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForOre", 2000000L,
|
||||
"Energy consumption for each ore vein group(in W)");
|
||||
Module.Miner.OreMiningMultiplier = Config.Bind("Miner", "OreMiningMultiplier", 3,
|
||||
new ConfigDescription("Mining multiplier for ore veins, multiplies to the number of veins in the group", new AcceptableValueRange<int>(1, 100)));
|
||||
Module.Miner.OreMiningScale = Config.Bind("Miner", "OreMiningScale", 100,
|
||||
"""
|
||||
0 for Auto(which means having researched advanced mining machine makes mining scale 300, otherwise 100).
|
||||
Mining scale(in percents) for slots below half of slot limits, and the scale reduces to 100% smoothly till reach full.
|
||||
Please note that the power consumption increases by the square of the scale which is the same as Advanced Mining Machine.
|
||||
""");
|
||||
Module.Miner.OilEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForOil", 1800000L,
|
||||
"Energy consumption for each oil seep(in W)");
|
||||
Module.Miner.WaterEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForWater", 2000000L,
|
||||
"Energy consumption for water slot(in W)");
|
||||
Module.Miner.WaterSpeed = Config.Bind("Miner", "WaterMiningSpeed", 10,
|
||||
"Water mining speed (count per second)");
|
||||
Module.Miner.FuelIlsSlot = Config.Bind("Miner", "ILSFuelSlot", 4,
|
||||
new ConfigDescription("Fuel slot for ILS, set 0 to disable.", new AcceptableValueRange<int>(0, 5)));
|
||||
Module.Miner.FuelPlsSlot = Config.Bind("Miner", "PLSFuelSlot", 4,
|
||||
new ConfigDescription("Fuel slot for PLS, set 0 to disable.", new AcceptableValueRange<int>(0, 4)));
|
||||
|
||||
_modules = Util.GetTypesFiltered(Assembly.GetExecutingAssembly(),
|
||||
t => string.Equals(t.Namespace, "LogisticHub.Module", StringComparison.Ordinal));
|
||||
_modules?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
||||
Harmony.CreateAndPatchAll(typeof(LogisticHub));
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_modules?.Do(type => type.GetMethod("Start")?.Invoke(null, null));
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_modules?.Do(type => type.GetMethod("Uninit")?.Invoke(null, null));
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<BepInExPluginGuid>org.soardev.logistichub</BepInExPluginGuid>
|
||||
<Description>DSP MOD - LogisticHub</Description>
|
||||
<Version>0.1.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackageId>LogisticHub</PackageId>
|
||||
<RootNamespace>LogisticHub</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2022.3.53" IncludeAssets="compile" />
|
||||
<!-- <PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" /> -->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\AssemblyFromGame\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>..\AssemblyFromGame\UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UXAssist\UXAssist.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace LogisticHub.Module;
|
||||
|
||||
using UXAssist.Common;
|
||||
|
||||
public static class AuxData
|
||||
{
|
||||
public static (long, bool)[] Fuels;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
GameLogic.OnDataLoaded += () =>
|
||||
{
|
||||
var maxId = LDB.items.dataArray.Select(data => data.ID).Prepend(0).Max();
|
||||
Fuels = new (long, bool)[maxId + 1];
|
||||
foreach (var data in LDB.items.dataArray)
|
||||
Fuels[data.ID] = (data.HeatValue, data.Productive);
|
||||
};
|
||||
}
|
||||
|
||||
public static int AlignUpToPowerOf2(int n)
|
||||
{
|
||||
if (n < 16) return 16;
|
||||
n--;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
return n + 1;
|
||||
}
|
||||
}
|
||||
@@ -1,345 +0,0 @@
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using UXAssist.Common;
|
||||
using Random = UnityEngine.Random;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
|
||||
namespace LogisticHub.Module;
|
||||
|
||||
public class Miner : PatchImpl<Miner>
|
||||
{
|
||||
public static ConfigEntry<bool> Enabled;
|
||||
public static ConfigEntry<long> OreEnergyConsume;
|
||||
public static ConfigEntry<int> OreMiningScale;
|
||||
public static ConfigEntry<int> OreMiningMultiplier;
|
||||
public static ConfigEntry<long> OilEnergyConsume;
|
||||
public static ConfigEntry<long> WaterEnergyConsume;
|
||||
public static ConfigEntry<int> WaterSpeed;
|
||||
public static ConfigEntry<int> FuelIlsSlot;
|
||||
public static ConfigEntry<int> FuelPlsSlot;
|
||||
|
||||
private static long _frame;
|
||||
private static float _miningCostRateByTech;
|
||||
private static long _miningFrames;
|
||||
private static long _miningSpeedScaleLong;
|
||||
private static bool _advancedMiningMachineUnlocked;
|
||||
private static int _miningMultiplier = 3;
|
||||
private static int _miningScale = 100;
|
||||
private static uint _miningCostBarrier;
|
||||
private static uint _miningCostBarrierOil;
|
||||
private static int[] _mineIndex;
|
||||
|
||||
private static uint _miningSeed = (uint)Random.Range(0, int.MaxValue);
|
||||
|
||||
private static readonly (int, int)[] VeinList =
|
||||
[
|
||||
(0, 1000),
|
||||
(1, 1001),
|
||||
(2, 1002),
|
||||
(3, 1003),
|
||||
(4, 1004),
|
||||
(5, 1005),
|
||||
(6, 1006),
|
||||
(7, 1007),
|
||||
(11, 1011),
|
||||
(12, 1012),
|
||||
(13, 1013),
|
||||
(14, 1014),
|
||||
(15, 1015),
|
||||
(16, 1016)
|
||||
];
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
Enabled.SettingChanged += (_, _) => { Enable(Enabled.Value); };
|
||||
|
||||
Enable(Enabled.Value);
|
||||
}
|
||||
|
||||
public static void Uninit()
|
||||
{
|
||||
Enable(false);
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
}
|
||||
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
_frame = 0L;
|
||||
UpdateMiningCostRate();
|
||||
UpdateSpeedScale();
|
||||
CheckRecipes();
|
||||
}
|
||||
|
||||
private static int SplitIncLevel(ref int n, ref int m, int p)
|
||||
{
|
||||
var level = m / n;
|
||||
var left = m - level * n;
|
||||
n -= p;
|
||||
left -= n;
|
||||
m -= left > 0 ? level * p + left : level * p;
|
||||
return level;
|
||||
}
|
||||
|
||||
private static void CheckRecipes()
|
||||
{
|
||||
_advancedMiningMachineUnlocked = GameMain.history.recipeUnlocked.Contains(119);
|
||||
_miningMultiplier = OreMiningMultiplier.Value;
|
||||
if (OreMiningScale.Value == 0)
|
||||
{
|
||||
_miningScale = _advancedMiningMachineUnlocked ? 300 : 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
_miningScale = OreMiningScale.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateMiningCostRate()
|
||||
{
|
||||
_miningCostRateByTech = GameMain.history.miningCostRate;
|
||||
_miningCostBarrier = (uint)(int)Math.Ceiling(2147483646.0 * _miningCostRateByTech);
|
||||
_miningCostBarrierOil = (uint)(int)Math.Ceiling(2147483646.0 * _miningCostRateByTech * 0.401116669f / Math.Max(DSPGame.GameDesc.resourceMultiplier, 0.416666657f));
|
||||
}
|
||||
|
||||
private static void UpdateSpeedScale()
|
||||
{
|
||||
_miningSpeedScaleLong = (long)Math.Round(GameMain.history.miningSpeedScale * 100f);
|
||||
_miningFrames = _miningSpeedScaleLong * 6000L;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockTechFunction))]
|
||||
private static void OnUnlockTech(int func)
|
||||
{
|
||||
switch (func)
|
||||
{
|
||||
case 20:
|
||||
UpdateMiningCostRate();
|
||||
break;
|
||||
case 21:
|
||||
UpdateSpeedScale();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.OnFactoryFrameBegin))]
|
||||
private static void GameLogic_OnFactoryFrameBegin_Prefix()
|
||||
{
|
||||
var main = GameMain.instance;
|
||||
if (main.isMenuDemo) return;
|
||||
if (_miningSpeedScaleLong <= 0L) return;
|
||||
|
||||
if (main.timei % 60 != 0) return;
|
||||
_frame += _miningFrames;
|
||||
var frameCounter = _frame / 1200000L;
|
||||
if (frameCounter <= 0) return;
|
||||
_frame -= frameCounter * 1200000L;
|
||||
|
||||
DeepProfiler.BeginSample(DPEntry.Miner);
|
||||
var data = GameMain.data;
|
||||
if (_mineIndex == null || data.factoryCount > _mineIndex.Length)
|
||||
Array.Resize(ref _mineIndex, data.factoryCount);
|
||||
var factoryStatPool = GameMain.statistics.production.factoryStatPool;
|
||||
for (var factoryIndex = data.factoryCount - 1; factoryIndex >= 0; factoryIndex--)
|
||||
{
|
||||
var factory = data.factories[factoryIndex];
|
||||
var veins = VeinManager.GetVeins(factoryIndex);
|
||||
if (veins == null) continue;
|
||||
var stations = StationManager.GetStations(factoryIndex);
|
||||
var planetTransport = factory.transport;
|
||||
var productRegister = factoryStatPool[factoryIndex]?.productRegister;
|
||||
var demands = stations.StorageIndices[1];
|
||||
if (demands == null) continue;
|
||||
foreach (var (itemIndex, itemId) in VeinList)
|
||||
{
|
||||
if (itemIndex >= demands.Length) continue;
|
||||
var demandList = demands[itemIndex];
|
||||
if (demandList == null) continue;
|
||||
foreach (var storageIndex in demandList)
|
||||
{
|
||||
var station = planetTransport.stationPool[storageIndex / 100];
|
||||
if (station == null)
|
||||
continue;
|
||||
ref var storage = ref station.storage[storageIndex % 100];
|
||||
if (storage.count >= storage.max) continue;
|
||||
int amount;
|
||||
long energyConsume;
|
||||
var miningScale = _miningScale;
|
||||
if (miningScale > 100 && storage.count * 2 > storage.max)
|
||||
{
|
||||
miningScale = 100 + ((miningScale - 100) * (storage.max - storage.count) * 2 + storage.max - 1) / storage.max;
|
||||
}
|
||||
|
||||
if (itemIndex > 0)
|
||||
{
|
||||
(amount, energyConsume) = Mine(factory, veins, itemId, miningScale, (int)frameCounter, _miningMultiplier, station.energy);
|
||||
if (amount < 0) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
energyConsume = (WaterEnergyConsume.Value * frameCounter * miningScale * miningScale + 9999L) / 10000L;
|
||||
if (station.energy < energyConsume) continue;
|
||||
amount = WaterSpeed.Value * miningScale / 100;
|
||||
}
|
||||
|
||||
if (amount <= 0) continue;
|
||||
storage.count += amount;
|
||||
if (productRegister != null)
|
||||
productRegister[itemId] += amount;
|
||||
station.energy -= energyConsume;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = planetTransport.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
var stationComponent = planetTransport.stationPool[i];
|
||||
if (stationComponent == null || stationComponent.isCollector || stationComponent.isVeinCollector || stationComponent.energy * 2 >= stationComponent.energyMax) continue;
|
||||
var index = (stationComponent.isStellar ? FuelIlsSlot.Value : FuelPlsSlot.Value) - 1;
|
||||
var storage = stationComponent.storage;
|
||||
if (index < 0 || index >= storage.Length)
|
||||
continue;
|
||||
var fuelCount = storage[index].count;
|
||||
if (fuelCount == 0) continue;
|
||||
var (heat, prod) = AuxData.Fuels[storage[index].itemId];
|
||||
if (heat <= 0)
|
||||
continue;
|
||||
/* Sprayed fuels */
|
||||
int pretendIncLevel;
|
||||
if (prod && (pretendIncLevel = storage[index].inc / storage[index].count) > 0)
|
||||
{
|
||||
var count = (int)((stationComponent.energyMax - stationComponent.energy) * 1000L / Cargo.incTable[pretendIncLevel] / 7L);
|
||||
if (count > fuelCount)
|
||||
count = fuelCount;
|
||||
var incLevel = SplitIncLevel(ref storage[index].count, ref storage[index].inc, count);
|
||||
if (incLevel > 10)
|
||||
incLevel = 10;
|
||||
stationComponent.energy += heat * count * (1000L + Cargo.incTable[incLevel]) / 1000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
var count = (int)((stationComponent.energyMax - stationComponent.energy) / heat);
|
||||
if (count > fuelCount)
|
||||
count = fuelCount;
|
||||
SplitIncLevel(ref storage[index].count, ref storage[index].inc, count);
|
||||
stationComponent.energy += heat * count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeepProfiler.EndSample(DPEntry.Miner);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockRecipe))]
|
||||
private static void OnUnlockRecipe(int recipeId)
|
||||
{
|
||||
if (recipeId == 119)
|
||||
{
|
||||
CheckRecipes();
|
||||
}
|
||||
}
|
||||
|
||||
private static (int, long) Mine(PlanetFactory factory, ProductVeinData[] allVeins, int productId, int percent, int counter, int multiplier, long energyMax)
|
||||
{
|
||||
var veins = allVeins[productId - 1000];
|
||||
if (veins == null)
|
||||
return (-1, -1L);
|
||||
|
||||
var veinIndices = veins.VeinIndices;
|
||||
uint barrier;
|
||||
int limit;
|
||||
int count;
|
||||
long energy;
|
||||
var length = veinIndices.Count - 1;
|
||||
/* if is Oil */
|
||||
if (productId == 1007)
|
||||
{
|
||||
energy = OilEnergyConsume.Value * length;
|
||||
if (energy > energyMax)
|
||||
return (-1, -1L);
|
||||
var countf = 0f;
|
||||
var veinsPool = factory.veinPool;
|
||||
for (var i = length; i > 0; i--)
|
||||
{
|
||||
countf += veinsPool[veinIndices[i]].amount * 4 * VeinData.oilSpeedMultiplier;
|
||||
}
|
||||
count = (int)(countf * (counter * percent) / 100f);
|
||||
if (count == 0)
|
||||
return (-1, -1L);
|
||||
barrier = _miningCostBarrierOil;
|
||||
limit = 2500;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (length * multiplier * counter * percent + 99) / 100;
|
||||
if (count == 0)
|
||||
return (-1, -1L);
|
||||
energy = (OreEnergyConsume.Value * veins.GroupCount * percent * percent + 9999L) / 10000L;
|
||||
if (energy > energyMax)
|
||||
return (-1, -1L);
|
||||
barrier = _miningCostBarrier;
|
||||
limit = 0;
|
||||
}
|
||||
|
||||
var veinsData = factory.veinPool;
|
||||
var total = 0;
|
||||
var factoryIndex = factory.index;
|
||||
var mineIndex = _mineIndex[factoryIndex];
|
||||
for (; count > 0; count--)
|
||||
{
|
||||
mineIndex = mineIndex % length + 1;
|
||||
var index = veinIndices[mineIndex];
|
||||
ref var vd = ref veinsData[index];
|
||||
int groupIndex;
|
||||
|
||||
if (vd.amount <= 0)
|
||||
{
|
||||
groupIndex = vd.groupIndex;
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
length = veinIndices.Count - 1;
|
||||
if (length <= 0) break;
|
||||
continue;
|
||||
}
|
||||
|
||||
total++;
|
||||
|
||||
if (vd.amount <= limit) continue;
|
||||
var consume = true;
|
||||
if (barrier < 2147483646u)
|
||||
{
|
||||
_miningSeed = (uint)((int)((ulong)((_miningSeed % 2147483646u + 1) * 48271L) % 2147483647uL) - 1);
|
||||
consume = _miningSeed < barrier;
|
||||
}
|
||||
|
||||
if (!consume) continue;
|
||||
|
||||
vd.amount--;
|
||||
groupIndex = vd.groupIndex;
|
||||
factory.veinGroups[groupIndex].amount--;
|
||||
|
||||
if (vd.amount > 0) continue;
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
length = veinIndices.Count - 1;
|
||||
if (length <= 0) break;
|
||||
}
|
||||
|
||||
_mineIndex[factoryIndex] = mineIndex;
|
||||
|
||||
return (total, energy);
|
||||
}
|
||||
}
|
||||
@@ -1,325 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using HarmonyLib;
|
||||
using UXAssist.Common;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
|
||||
namespace LogisticHub.Module;
|
||||
|
||||
public class PlanetStations
|
||||
{
|
||||
public readonly List<int>[][] StorageIndices = [null, null];
|
||||
|
||||
public void AddStationStorage(bool demand, int id, int stationId, int storageIdx)
|
||||
{
|
||||
LogisticHub.Logger.LogDebug($"AddStationStorage: demand={demand}, id={id}, stationId={stationId}, storageIdx={storageIdx}");
|
||||
var stations = StorageIndices[demand ? 1 : 0];
|
||||
if (stations == null || id >= stations.Length)
|
||||
{
|
||||
Array.Resize(ref stations, AuxData.AlignUpToPowerOf2(id + 1));
|
||||
StorageIndices[demand ? 1 : 0] = stations;
|
||||
}
|
||||
|
||||
var list = stations[id];
|
||||
if (list == null)
|
||||
{
|
||||
list = [];
|
||||
stations[id] = list;
|
||||
}
|
||||
|
||||
var value = stationId * 100 + storageIdx;
|
||||
var index = list.BinarySearch(value);
|
||||
if (index < 0)
|
||||
list.Insert(~index, value);
|
||||
}
|
||||
|
||||
public void RemoveStationStorage(bool demand, int id, int stationId, int storageIdx)
|
||||
{
|
||||
var stations = StorageIndices[demand ? 1 : 0];
|
||||
if (stations == null || id >= stations.Length)
|
||||
return;
|
||||
var list = stations[id];
|
||||
if (list == null)
|
||||
return;
|
||||
|
||||
var value = stationId * 100 + storageIdx;
|
||||
var index = list.BinarySearch(value);
|
||||
if (index >= 0)
|
||||
list.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public class StationManager : PatchImpl<StationManager>
|
||||
{
|
||||
private static PlanetStations[] _stations;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
Enable(true);
|
||||
}
|
||||
|
||||
public static void Uninit()
|
||||
{
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
Enable(false);
|
||||
}
|
||||
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
_stations = null;
|
||||
var data = GameMain.data;
|
||||
for (var index = data.factoryCount - 1; index >= 0; index--)
|
||||
{
|
||||
var factory = data.factories[index];
|
||||
if (factory == null || factory.index != index) continue;
|
||||
var planetIndex = factory.index;
|
||||
var stations = StationsByPlanet(planetIndex);
|
||||
var transport = factory.transport;
|
||||
var pool = transport.stationPool;
|
||||
for (var i = transport.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
var station = pool[i];
|
||||
if (station == null || station.id != i || station.isCollector || station.isVeinCollector) continue;
|
||||
UpdateStationInfo(stations, station);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int ItemIdToIndex(int itemId)
|
||||
{
|
||||
return itemId switch
|
||||
{
|
||||
>= 1000 and < 2000 => itemId - 1000,
|
||||
>= 5000 and < 5050 => itemId - 5000 + 900,
|
||||
>= 6000 and < 6050 => itemId - 6000 + 950,
|
||||
_ => -1
|
||||
};
|
||||
}
|
||||
|
||||
public static int IndexToItemId(int index)
|
||||
{
|
||||
return index switch
|
||||
{
|
||||
< 900 => index + 1000,
|
||||
< 950 => index - 900 + 5000,
|
||||
< 1000 => index - 950 + 6000,
|
||||
_ => -1
|
||||
};
|
||||
}
|
||||
|
||||
public static PlanetStations GetStations(int planetIndex)
|
||||
{
|
||||
return _stations != null && planetIndex < _stations.Length ? _stations[planetIndex] : null;
|
||||
}
|
||||
|
||||
private static PlanetStations StationsByPlanet(int planetIndex)
|
||||
{
|
||||
if (_stations == null || _stations.Length <= planetIndex)
|
||||
Array.Resize(ref _stations, AuxData.AlignUpToPowerOf2(planetIndex + 1));
|
||||
var stations = _stations[planetIndex];
|
||||
if (stations != null) return stations;
|
||||
stations = new PlanetStations();
|
||||
_stations[planetIndex] = stations;
|
||||
return stations;
|
||||
}
|
||||
|
||||
private static void DebugLog()
|
||||
{
|
||||
for (var idx = 0; idx < _stations.Length; idx++)
|
||||
{
|
||||
var stations = _stations[idx];
|
||||
if (stations == null) continue;
|
||||
LogisticHub.Logger.LogDebug($"Planet {idx}:");
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var storage = stations.StorageIndices[i];
|
||||
if (storage == null) continue;
|
||||
LogisticHub.Logger.LogDebug(i == 1 ? " Demand:" : " Supply:");
|
||||
for (var j = 0; j < storage.Length; j++)
|
||||
{
|
||||
var list = storage[j];
|
||||
if (list == null) continue;
|
||||
var count = list.Count;
|
||||
if (count <= 0) continue;
|
||||
var itemId = IndexToItemId(j);
|
||||
LogisticHub.Logger.LogDebug($" {itemId}: {string.Join(", ", list)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateStationInfo(PlanetStations stations, StationComponent station, int storageIdx = -1)
|
||||
{
|
||||
var storage = station.storage;
|
||||
var stationId = station.id;
|
||||
if (storageIdx >= 0)
|
||||
{
|
||||
if (storageIdx >= storage.Length) return;
|
||||
var itemId = ItemIdToIndex(storage[storageIdx].itemId);
|
||||
if (itemId <= 0) return;
|
||||
var logic = storage[storageIdx].localLogic;
|
||||
switch (logic)
|
||||
{
|
||||
case ELogisticStorage.Demand:
|
||||
stations.AddStationStorage(true, itemId, stationId, storageIdx);
|
||||
break;
|
||||
case ELogisticStorage.Supply:
|
||||
stations.AddStationStorage(false, itemId, stationId, storageIdx);
|
||||
break;
|
||||
case ELogisticStorage.None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = storage.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var itemId = ItemIdToIndex(storage[i].itemId);
|
||||
if (itemId <= 0) continue;
|
||||
var logic = storage[i].localLogic;
|
||||
switch (logic)
|
||||
{
|
||||
case ELogisticStorage.Demand:
|
||||
stations.AddStationStorage(true, itemId, stationId, i);
|
||||
break;
|
||||
case ELogisticStorage.Supply:
|
||||
stations.AddStationStorage(false, itemId, stationId, i);
|
||||
break;
|
||||
case ELogisticStorage.None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveStationInfo(PlanetStations stations, StationComponent station, int storageIdx = -1)
|
||||
{
|
||||
var storage = station.storage;
|
||||
var stationId = station.id;
|
||||
if (storageIdx >= 0)
|
||||
{
|
||||
var itemId = ItemIdToIndex(storage[storageIdx].itemId);
|
||||
if (itemId <= 0) return;
|
||||
var logic = storage[storageIdx].localLogic;
|
||||
switch (logic)
|
||||
{
|
||||
case ELogisticStorage.Demand:
|
||||
stations.RemoveStationStorage(true, itemId, stationId, storageIdx);
|
||||
break;
|
||||
case ELogisticStorage.Supply:
|
||||
stations.RemoveStationStorage(false, itemId, stationId, storageIdx);
|
||||
break;
|
||||
case ELogisticStorage.None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = storage.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var itemId = ItemIdToIndex(storage[i].itemId);
|
||||
if (itemId <= 0) continue;
|
||||
var logic = storage[i].localLogic;
|
||||
switch (logic)
|
||||
{
|
||||
case ELogisticStorage.Demand:
|
||||
stations.RemoveStationStorage(true, itemId, stationId, i);
|
||||
break;
|
||||
case ELogisticStorage.Supply:
|
||||
stations.RemoveStationStorage(false, itemId, stationId, i);
|
||||
break;
|
||||
case ELogisticStorage.None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.Init))]
|
||||
private static void PlanetTransport_Init_Postfix(PlanetTransport __instance)
|
||||
{
|
||||
var factory = __instance.factory;
|
||||
var planetIndex = factory.index;
|
||||
|
||||
if (_stations == null || _stations.Length <= planetIndex)
|
||||
Array.Resize(ref _stations, AuxData.AlignUpToPowerOf2(planetIndex + 1));
|
||||
var stations = new PlanetStations();
|
||||
_stations[planetIndex] = stations;
|
||||
|
||||
var pool = __instance.stationPool;
|
||||
for (var i = __instance.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
var station = pool[i];
|
||||
if (station == null || station.id != i || station.isCollector || station.isVeinCollector) continue;
|
||||
UpdateStationInfo(stations, station);
|
||||
}
|
||||
// DebugLog();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(BuildingParameters), nameof(BuildingParameters.ApplyPrebuildParametersToEntity))]
|
||||
private static void BuildingParameters_ApplyPrebuildParametersToEntity_Postfix(int entityId, PlanetFactory factory)
|
||||
{
|
||||
if (entityId <= 0) return;
|
||||
ref var entity = ref factory.entityPool[entityId];
|
||||
var stationId = entity.stationId;
|
||||
if (stationId <= 0) return;
|
||||
var station = factory.transport.stationPool[stationId];
|
||||
if (station == null || station.id != stationId || station.isCollector || station.isVeinCollector) return;
|
||||
UpdateStationInfo(StationsByPlanet(factory.index), station);
|
||||
// DebugLog();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.RemoveStationComponent))]
|
||||
private static void PlanetTransport_RemoveStationComponent_Prefix(PlanetTransport __instance, int id)
|
||||
{
|
||||
if (id <= 0) return;
|
||||
var station = __instance.stationPool[id];
|
||||
if (station == null || station.id != id || station.isCollector || station.isVeinCollector) return;
|
||||
RemoveStationInfo(StationsByPlanet(__instance.factory.index), station);
|
||||
// DebugLog();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.SetStationStorage))]
|
||||
private static void PlanetTransport_SetStationStorage_Prefix(PlanetTransport __instance, int stationId, int storageIdx, int itemId, ELogisticStorage localLogic, out bool __state)
|
||||
{
|
||||
var station = __instance.stationPool[stationId];
|
||||
if (station == null || station.id != stationId || station.isCollector || station.isVeinCollector || storageIdx < 0 || storageIdx >= station.storage.Length)
|
||||
{
|
||||
__state = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ref var storage = ref station.storage[storageIdx];
|
||||
var oldItemId = storage.itemId;
|
||||
var oldLocalLogic = storage.localLogic;
|
||||
if (localLogic == oldLocalLogic && itemId == oldItemId)
|
||||
{
|
||||
__state = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldItemId > 0 && oldLocalLogic != ELogisticStorage.None)
|
||||
RemoveStationInfo(StationsByPlanet(__instance.factory.index), station, storageIdx);
|
||||
__state = localLogic != ELogisticStorage.None;
|
||||
// if (!__state) DebugLog();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.SetStationStorage))]
|
||||
private static void PlanetTransport_SetStationStorage_Postfix(PlanetTransport __instance, int stationId, int storageIdx, bool __state)
|
||||
{
|
||||
if (!__state) return;
|
||||
var station = __instance.stationPool[stationId];
|
||||
UpdateStationInfo(StationsByPlanet(__instance.factory.index), station, storageIdx);
|
||||
// DebugLog();
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using HarmonyLib;
|
||||
using UXAssist.Common;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
|
||||
namespace LogisticHub.Module;
|
||||
|
||||
public class ProductVeinData
|
||||
{
|
||||
public readonly List<int> VeinIndices = [];
|
||||
public readonly HashSet<int> GroupIndices = [];
|
||||
public int GroupCount = 0;
|
||||
}
|
||||
|
||||
public class VeinManager : PatchImpl<VeinManager>
|
||||
{
|
||||
private static ProductVeinData[][] _veins;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
Enable(true);
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
}
|
||||
|
||||
public static void Uninit()
|
||||
{
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
Enable(false);
|
||||
}
|
||||
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
_veins = null;
|
||||
var data = GameMain.data;
|
||||
for (var index = data.factoryCount - 1; index >= 0; index--)
|
||||
{
|
||||
var factory = data.factories[index];
|
||||
if (factory == null || factory.index != index) continue;
|
||||
RecalcVeins(factory);
|
||||
}
|
||||
}
|
||||
|
||||
public static ProductVeinData[] GetVeins(int planetIndex)
|
||||
{
|
||||
if (_veins == null || _veins.Length <= planetIndex)
|
||||
return null;
|
||||
return _veins[planetIndex];
|
||||
}
|
||||
|
||||
private static ProductVeinData[] GetOrCreateVeins(int planetIndex)
|
||||
{
|
||||
if (_veins == null || _veins.Length <= planetIndex)
|
||||
Array.Resize(ref _veins, AuxData.AlignUpToPowerOf2(planetIndex + 1));
|
||||
var veins = _veins[planetIndex];
|
||||
if (veins != null) return veins;
|
||||
veins = new ProductVeinData[20];
|
||||
_veins[planetIndex] = veins;
|
||||
return veins;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.Init))]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateVeinGroup))]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateAllVeinGroups))]
|
||||
private static void PlanetFactory_RecalculateAllVeinGroups_Postfix(PlanetFactory __instance)
|
||||
{
|
||||
RecalcVeins(__instance);
|
||||
}
|
||||
|
||||
private static void DebugLog()
|
||||
{
|
||||
foreach (var veins in _veins)
|
||||
{
|
||||
if (veins == null) continue;
|
||||
for (var i = 0; i < veins.Length; i++)
|
||||
{
|
||||
var pvd = veins[i];
|
||||
if (pvd == null) continue;
|
||||
LogisticHub.Logger.LogInfo($"Product {i} VeinTypeCount={pvd.VeinIndices.Count} GroupCount={pvd.GroupCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RecalcVeins(PlanetFactory factory)
|
||||
{
|
||||
var planetIndex = factory.index;
|
||||
var veins = GetOrCreateVeins(planetIndex);
|
||||
var veinPool = factory.veinPool;
|
||||
|
||||
foreach (var pvd in veins)
|
||||
{
|
||||
if (pvd == null) continue;
|
||||
pvd.VeinIndices.Clear();
|
||||
pvd.GroupIndices.Clear();
|
||||
pvd.GroupCount = 0;
|
||||
}
|
||||
|
||||
for (var i = factory.veinCursor - 1; i > 0; i--)
|
||||
{
|
||||
if (veinPool[i].id != i || veinPool[i].amount <= 0 || veinPool[i].type == EVeinType.None) continue;
|
||||
var productId = veinPool[i].productId - 1000;
|
||||
if (productId is < 0 or >= 20) continue;
|
||||
var pvd = veins[productId];
|
||||
if (pvd == null)
|
||||
{
|
||||
pvd = new ProductVeinData();
|
||||
veins[productId] = pvd;
|
||||
}
|
||||
|
||||
pvd.VeinIndices.Add(i);
|
||||
pvd.GroupIndices.Add(veinPool[i].groupIndex);
|
||||
}
|
||||
|
||||
foreach (var pvd in veins)
|
||||
{
|
||||
if (pvd == null) continue;
|
||||
pvd.GroupCount = pvd.GroupIndices.Count;
|
||||
}
|
||||
|
||||
// DebugLog();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
# LogisticHub
|
||||
|
||||
#### Cheat functions for Logistic Storages, make them mine resources on the planet and exchange items from certain buildings
|
||||
#### 物流塔作弊功能,使其可以在星球上采矿并与特定建筑物交换物品
|
||||
|
||||
## Usage
|
||||
|
||||
* Miner(and fuel burning) functions
|
||||
+ Inspired by [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
||||
But it is heavily optimized to resolve performance, accuracy and other issues in PlanetMiner.
|
||||
+ (Optimization to PlanetMiner) Only recalculate count of veins when vein chunks are changed (added/removed by foundations/Sandbox-Mode, or exhausted), so this removes Dictionary allocation on each planet for every frame.
|
||||
+ (Optimization to PlanetMiner) More accurate frame counting by use float number.
|
||||
+ (Optimization to PlanetMiner) Does not increase power consumptions on `Veins Utilization` upgrades.
|
||||
+ (Optimization to PlanetMiner) Separate power consumptions for veins, oil seeps and water.
|
||||
+ (Optimization to PlanetMiner) Power consumptions are counted by groups of veins and count of oil seeps, which is more sensible.
|
||||
+ Can burn fuels in certain slot when energy below half of max.
|
||||
- (Optimization to PlanetMiner) Sprayed fuels generates extra energy as normal.
|
||||
+ (Optimization to PlanetMiner) All used parameters are configurable:
|
||||
- LogisticHub has the same speed as normal Mining Machine for normal ores by default.
|
||||
But you can set mining scale in configuration, which makes LogisticHub working like Advance Mining Machines:
|
||||
power consumption increases by the square of the scale, and gradually decrease mining speed over half of the maximum count.
|
||||
This applies to all of veins, oils and water.
|
||||
Mining scale can be set to 0(by default), which means it is automatically set by tech unlocks, set to 300 when you reaches Advanced Mining Machine, otherwise 100.
|
||||
- 100/s for water by default.
|
||||
- Energy costs: 1MW/vein-group & 10MW/water-slot & 1.8MW/oil-seep(configurable)
|
||||
- Fuels burning slot. Default: 4th for ILS and PLS. Set to 0 to disable it.
|
||||
|
||||
## 使用说明
|
||||
|
||||
* 采矿(和燃料燃烧)功能
|
||||
+ 创意来自 [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
||||
对性能重度优化,并解决了PlanetMiner的精度等问题。
|
||||
+ (对PlanetMiner的优化) 仅当矿堆发生变化(填埋/恢复/采完)时重新计算矿堆数据,解决每行星每计算帧要重建字典的性能问题。
|
||||
+ (对PlanetMiner的优化) 用浮点数保证更精确的帧计算。
|
||||
+ (对PlanetMiner的优化) 升级`矿物利用`不会提升能耗。
|
||||
+ (对PlanetMiner的优化) 分开矿物,油井和水的采集能耗。
|
||||
+ (对PlanetMiner的优化) 采集能耗以矿物组,油井为单位,相对更加合理。
|
||||
+ 剩余电量少于一半时可以燃烧指定格子的燃料补充。
|
||||
- (对PlanetMiner的优化) 喷涂了增产剂的燃料按照正常的计算方式提供更多的能量(除了原本就不增加能量输出的反物质燃料棒)。
|
||||
+ (对PlanetMiner的优化) 所有参数都可以在设置文件内配置:
|
||||
- 物流塔枢纽和普通矿机采矿速度一样(等同于同时采集所有对应矿物)。
|
||||
你可以设置采矿倍率改变物流塔枢纽采矿速度,和高级采矿机相同地,能耗和倍率的平方成正比,并且在存储矿物量多于一半时逐渐降低采矿倍率。
|
||||
此倍率对各种矿物,油井和水的采集都生效。
|
||||
倍率可以设置为0(默认),此时倍率会随科技解锁而变化,默认是100%,解锁高级采矿机后变为300%。
|
||||
- 水的采集速度默认为100/s。
|
||||
- 能耗:每矿物组 1MW,单格水 10MW,每油井 1.8MW。
|
||||
- 燃料格位置。默认:星际物流塔和行星内物流塔第4格。设为0则关闭燃料补充能量功能。
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "LogisticHub",
|
||||
"version_number": "0.1.0",
|
||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LogisticHub",
|
||||
"description": "Cheat functions to Logistic Storages which make them miner and items hub / 物流塔作弊功能,使其成为矿机和物品枢纽",
|
||||
"dependencies": [
|
||||
"xiaoye97-BepInEx-5.4.17",
|
||||
"soarqin-UXAssist-1.2.0"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,484 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace LogisticMiner;
|
||||
|
||||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
||||
public class LogisticMiner : BaseUnityPlugin
|
||||
{
|
||||
private new static readonly BepInEx.Logging.ManualLogSource Logger =
|
||||
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
||||
|
||||
private static long _oreEnergyConsume = 2000000;
|
||||
private static long _oilEnergyConsume = 3600000;
|
||||
private static long _waterEnergyConsume = 2000000;
|
||||
private static int _waterSpeed = 10;
|
||||
private static int _miningScale;
|
||||
private static int _fuelIlsSlot = 3;
|
||||
private static int _fuelPlsSlot = 3;
|
||||
|
||||
private static float _frame;
|
||||
private static float _miningCostRateByTech;
|
||||
private static float _miningSpeedScaleByTech;
|
||||
private static float _miningFrames;
|
||||
private static long _miningSpeedScaleLong;
|
||||
private static bool _advancedMiningMachineUnlocked;
|
||||
private static uint _miningCostBarrier;
|
||||
private static uint _miningCostBarrierOil;
|
||||
|
||||
private static uint _seed = (uint)Random.Range(int.MinValue, int.MaxValue);
|
||||
private static readonly Dictionary<int, VeinCacheData> PlanetVeinCacheData = [];
|
||||
private static readonly Dictionary<int, (long, bool)> Fuels = [];
|
||||
|
||||
private bool _cfgEnabled = true;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_cfgEnabled = Config.Bind("General", "Enabled", _cfgEnabled, "enable/disable this plugin").Value;
|
||||
_oreEnergyConsume = Config.Bind("General", "EnergyConsumptionForOre", _oreEnergyConsume / 2000,
|
||||
"Energy consumption for each ore vein group(in kW)").Value * 2000;
|
||||
_oilEnergyConsume = Config.Bind("General", "EnergyConsumptionForOil", _oilEnergyConsume / 2000,
|
||||
"Energy consumption for each oil seep(in kW)").Value * 2000;
|
||||
_waterEnergyConsume = Config.Bind("General", "EnergyConsumptionForWater", _waterEnergyConsume / 2000,
|
||||
"Energy consumption for water slot(in kW)").Value * 2000;
|
||||
_waterSpeed = Config.Bind("General", "WaterMiningSpeed", _waterSpeed,
|
||||
"Water mining speed (count per second)").Value;
|
||||
_miningScale = Config.Bind("General", "MiningScale", _miningScale,
|
||||
"0 for Auto(which means having researched makes mining scale 300, otherwise 100). Mining scale(in percents) for slots below half of slot limits, and the scale reduces to 100% smoothly till reach full. Please note that the power consumption increases by the square of the scale which is the same as Advanced Mining Machine")
|
||||
.Value;
|
||||
_fuelIlsSlot = Config.Bind("General", "ILSFuelSlot", _fuelIlsSlot + 1,
|
||||
new ConfigDescription("Fuel slot for ILS, set to 0 to disable",
|
||||
new AcceptableValueRange<int>(0, 5), []))
|
||||
.Value - 1;
|
||||
_fuelPlsSlot = Config.Bind("General", "PLSFuelSlot", _fuelPlsSlot + 1,
|
||||
new ConfigDescription("Fuel slot for PLS, set to 0 to disable",
|
||||
new AcceptableValueRange<int>(0, 4), []))
|
||||
.Value - 1;
|
||||
if (!_cfgEnabled) return;
|
||||
|
||||
Harmony.CreateAndPatchAll(typeof(LogisticMiner));
|
||||
}
|
||||
|
||||
private static int SplitIncLevel(ref int n, ref int m, int p)
|
||||
{
|
||||
var level = m / n;
|
||||
var left = m - level * n;
|
||||
n -= p;
|
||||
left -= n;
|
||||
m -= left > 0 ? level * p + left : level * p;
|
||||
return level;
|
||||
}
|
||||
|
||||
private static void CheckRecipes()
|
||||
{
|
||||
_advancedMiningMachineUnlocked = GameMain.history.recipeUnlocked.Contains(119);
|
||||
}
|
||||
|
||||
private static void UpdateMiningCostRate()
|
||||
{
|
||||
_miningCostRateByTech = GameMain.history.miningCostRate;
|
||||
_miningCostBarrier = (uint)(int)Math.Ceiling(2147483646.0 * _miningCostRateByTech);
|
||||
_miningCostBarrierOil =
|
||||
(uint)(int)Math.Ceiling(2147483646.0 * _miningCostRateByTech * 0.401116669f /
|
||||
DSPGame.GameDesc.resourceMultiplier);
|
||||
}
|
||||
|
||||
private static void UpdateSpeedScale()
|
||||
{
|
||||
_miningSpeedScaleByTech = GameMain.history.miningSpeedScale;
|
||||
_miningSpeedScaleLong = (long)(_miningSpeedScaleByTech * 100);
|
||||
lock (PlanetVeinCacheData)
|
||||
{
|
||||
_miningFrames = 120f / _miningSpeedScaleByTech;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(DSPGame), nameof(DSPGame.StartGame), typeof(GameDesc))]
|
||||
[HarmonyPatch(typeof(DSPGame), nameof(DSPGame.StartGame), typeof(string))]
|
||||
private static void OnGameStart()
|
||||
{
|
||||
Logger.LogInfo("Game Start");
|
||||
PlanetVeinCacheData.Clear();
|
||||
Fuels.Clear();
|
||||
foreach (var data in LDB.items.dataArray)
|
||||
{
|
||||
if (data.HeatValue > 0)
|
||||
{
|
||||
Fuels.Add(data.ID, (data.HeatValue, data.Productive));
|
||||
}
|
||||
}
|
||||
/* Thinking: storage max may affect mining scale?
|
||||
_localStationMax = LDB.items.Select(2103).prefabDesc.stationMaxItemCount;
|
||||
_remoteStationMax = LDB.items.Select(2104).prefabDesc.stationMaxItemCount;
|
||||
*/
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Start))]
|
||||
private static void OnGameLoaded()
|
||||
{
|
||||
_frame = 0f;
|
||||
|
||||
UpdateMiningCostRate();
|
||||
UpdateSpeedScale();
|
||||
CheckRecipes();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockTechFunction))]
|
||||
private static void OnUnlockTech(int func)
|
||||
{
|
||||
switch (func)
|
||||
{
|
||||
case 20:
|
||||
UpdateMiningCostRate();
|
||||
break;
|
||||
case 21:
|
||||
UpdateSpeedScale();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.OnFactoryFrameBegin))]
|
||||
private static void FrameTick()
|
||||
{
|
||||
var main = GameMain.instance;
|
||||
if (main.isMenuDemo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_frame++;
|
||||
if (_frame <= 1000000f) return;
|
||||
/* keep precision of floats by limiting them <= 1000000f */
|
||||
_frame -= 1000000f;
|
||||
foreach (var pair in PlanetVeinCacheData)
|
||||
{
|
||||
pair.Value.FrameNext -= 1000000f;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockRecipe))]
|
||||
private static void OnUnlockRecipe(int recipeId)
|
||||
{
|
||||
if (recipeId == 119)
|
||||
{
|
||||
CheckRecipes();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.Init))]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateVeinGroup))]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateAllVeinGroups))]
|
||||
private static void NeedRecalcVeins(PlanetFactory __instance)
|
||||
{
|
||||
RecalcVeins(__instance);
|
||||
}
|
||||
|
||||
private static void RecalcVeins(PlanetFactory factory)
|
||||
{
|
||||
var planetId = factory.planetId;
|
||||
lock (PlanetVeinCacheData)
|
||||
{
|
||||
/* remove planet veins from dict */
|
||||
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
||||
{
|
||||
vcd.GenVeins(factory);
|
||||
}
|
||||
else
|
||||
{
|
||||
vcd = new VeinCacheData();
|
||||
vcd.GenVeins(factory);
|
||||
vcd.FrameNext = _frame + _miningFrames;
|
||||
PlanetVeinCacheData.Add(planetId, vcd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.BeforeGameTick))]
|
||||
private static void FactorySystemLogisticMiner(PlanetFactory __instance)
|
||||
{
|
||||
if (_miningSpeedScaleLong <= 0)
|
||||
return;
|
||||
var planetId = __instance.planetId;
|
||||
lock (PlanetVeinCacheData)
|
||||
{
|
||||
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
||||
{
|
||||
if (vcd.FrameNext > _frame)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlanetVeinCacheData[planetId] = new VeinCacheData
|
||||
{
|
||||
FrameNext = _frame + _miningFrames
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
var planetTransport = __instance.transport;
|
||||
var factoryProductionStat =
|
||||
GameMain.statistics.production.factoryStatPool[__instance.index];
|
||||
var productRegister = factoryProductionStat?.productRegister;
|
||||
DeepProfiler.BeginSample(DPEntry.Miner);
|
||||
do
|
||||
{
|
||||
for (var j = 1; j < planetTransport.stationCursor; j++)
|
||||
{
|
||||
var stationComponent = planetTransport.stationPool[j];
|
||||
if (stationComponent == null) continue;
|
||||
/* skip Orbital Collectors and Advanced Mining Machines */
|
||||
if (stationComponent.isCollector || stationComponent.isVeinCollector) continue;
|
||||
var storage = stationComponent.storage;
|
||||
if (storage == null) continue;
|
||||
var isCollecting = false;
|
||||
for (var k = 0; k < stationComponent.storage.Length; k++)
|
||||
{
|
||||
ref var stationStore = ref storage[k];
|
||||
if (stationStore.localLogic != ELogisticStorage.Demand ||
|
||||
stationStore.max <= stationStore.count)
|
||||
continue;
|
||||
|
||||
var isVein = vcd.HasVein(stationStore.itemId);
|
||||
var isVeinOrWater = isVein || stationStore.itemId == __instance.planet.waterItemId;
|
||||
if (!isVeinOrWater) continue;
|
||||
int amount;
|
||||
long energyConsume;
|
||||
isCollecting = true;
|
||||
var miningScale = _miningScale;
|
||||
if (miningScale == 0)
|
||||
{
|
||||
miningScale = _advancedMiningMachineUnlocked ? 300 : 100;
|
||||
}
|
||||
|
||||
if (miningScale > 100 && stationStore.count * 2 > stationStore.max)
|
||||
{
|
||||
miningScale = 100 +
|
||||
((miningScale - 100) * (stationStore.max - stationStore.count) * 2 +
|
||||
stationStore.max - 1) / stationStore.max;
|
||||
}
|
||||
|
||||
if (isVein)
|
||||
{
|
||||
(amount, energyConsume) = vcd.Mine(__instance, stationStore.itemId, miningScale,
|
||||
_miningSpeedScaleLong,
|
||||
stationComponent.energy);
|
||||
if (amount < 0)
|
||||
{
|
||||
k = int.MaxValue - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
energyConsume = (_waterEnergyConsume * miningScale * miningScale + 9999L) / 100L /
|
||||
_miningSpeedScaleLong;
|
||||
if (stationComponent.energy < energyConsume)
|
||||
{
|
||||
k = int.MaxValue - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
amount = _waterSpeed * miningScale / 100;
|
||||
}
|
||||
|
||||
if (amount <= 0) continue;
|
||||
stationStore.count += amount;
|
||||
if (factoryProductionStat != null)
|
||||
productRegister[stationStore.itemId] += amount;
|
||||
stationComponent.energy -= energyConsume;
|
||||
}
|
||||
|
||||
if (!isCollecting || stationComponent.energy * 2 >= stationComponent.energyMax) continue;
|
||||
var index = stationComponent.isStellar ? _fuelIlsSlot : _fuelPlsSlot;
|
||||
if (index < 0 || index >= storage.Length)
|
||||
continue;
|
||||
var fuelCount = storage[index].count;
|
||||
if (fuelCount == 0) continue;
|
||||
if (!Fuels.TryGetValue(storage[index].itemId, out var val) || val.Item1 <= 0)
|
||||
continue;
|
||||
/* Sprayed fuels */
|
||||
int pretendIncLevel;
|
||||
if (val.Item2 && (pretendIncLevel = storage[index].inc / storage[index].count) > 0)
|
||||
{
|
||||
var count = (int)((stationComponent.energyMax - stationComponent.energy) * 1000L /
|
||||
Cargo.incTable[pretendIncLevel] / 7L);
|
||||
if (count > fuelCount)
|
||||
count = fuelCount;
|
||||
var incLevel = SplitIncLevel(ref storage[index].count, ref storage[index].inc, count);
|
||||
if (incLevel > 10)
|
||||
incLevel = 10;
|
||||
stationComponent.energy += val.Item1 * count * (1000L + Cargo.incTable[incLevel]) / 1000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
var count = (int)((stationComponent.energyMax - stationComponent.energy) / val.Item1);
|
||||
if (count > fuelCount)
|
||||
count = fuelCount;
|
||||
SplitIncLevel(ref storage[index].count, ref storage[index].inc, count);
|
||||
stationComponent.energy += val.Item1 * count;
|
||||
}
|
||||
}
|
||||
|
||||
vcd.FrameNext += _miningFrames;
|
||||
} while (vcd.FrameNext <= _frame);
|
||||
|
||||
DeepProfiler.EndSample(DPEntry.Miner);
|
||||
}
|
||||
}
|
||||
|
||||
private class VeinCacheData
|
||||
{
|
||||
public float FrameNext;
|
||||
|
||||
/* stores list of indices to veinData, with an extra INT which indicates cout of veinGroups at last */
|
||||
private Dictionary<int, List<int>> _veins = [];
|
||||
private int _mineIndex = -1;
|
||||
|
||||
public bool HasVein(int productId)
|
||||
{
|
||||
return _veins.ContainsKey(productId);
|
||||
}
|
||||
|
||||
public void GenVeins(PlanetFactory factory)
|
||||
{
|
||||
_veins = [];
|
||||
var veinPool = factory.veinPool;
|
||||
Dictionary<int, HashSet<int>> vg = [];
|
||||
for (var i = 0; i < veinPool.Length; i++)
|
||||
{
|
||||
if (veinPool[i].amount <= 0 || veinPool[i].type == EVeinType.None) continue;
|
||||
var productId = veinPool[i].productId;
|
||||
if (_veins.TryGetValue(productId, out var l))
|
||||
{
|
||||
l.Add(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
_veins.Add(productId, [i]);
|
||||
}
|
||||
|
||||
if (vg.TryGetValue(productId, out var hs))
|
||||
{
|
||||
hs.Add(veinPool[i].groupIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
vg.Add(productId, [veinPool[i].groupIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var pair in vg)
|
||||
{
|
||||
_veins[pair.Key].Add(pair.Value.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public (int, long) Mine(PlanetFactory factory, int productId, int percent, long miningSpeedScale,
|
||||
long energyMax)
|
||||
{
|
||||
if (!_veins.TryGetValue(productId, out var veins))
|
||||
{
|
||||
return (-1, -1L);
|
||||
}
|
||||
|
||||
uint barrier;
|
||||
int limit;
|
||||
int count;
|
||||
long energy;
|
||||
var length = veins.Count - 1;
|
||||
/* if is Oil */
|
||||
if (productId == 1007)
|
||||
{
|
||||
energy = (_oilEnergyConsume * length * percent * percent + 9999L) / 100L / miningSpeedScale;
|
||||
if (energy > energyMax)
|
||||
return (-1, -1L);
|
||||
float countf = 0f;
|
||||
var veinsPool = factory.veinPool;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
ref var vd = ref veinsPool[veins[i]];
|
||||
countf += vd.amount * 4 * VeinData.oilSpeedMultiplier;
|
||||
}
|
||||
|
||||
count = ((int)countf * percent + 99) / 100;
|
||||
if (count == 0)
|
||||
return (-1, -1L);
|
||||
barrier = _miningCostBarrierOil;
|
||||
limit = 2500;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (length * percent + 99) / 100;
|
||||
if (count == 0)
|
||||
return (-1, -1L);
|
||||
energy = (_oreEnergyConsume * veins[length] * percent * percent + 9999L) / 100L / miningSpeedScale;
|
||||
if (energy > energyMax)
|
||||
return (-1, -1L);
|
||||
barrier = _miningCostBarrier;
|
||||
limit = 0;
|
||||
}
|
||||
|
||||
var veinsData = factory.veinPool;
|
||||
var total = 0;
|
||||
for (; count > 0; count--)
|
||||
{
|
||||
_mineIndex = (_mineIndex + 1) % length;
|
||||
var index = veins[_mineIndex];
|
||||
ref var vd = ref veinsData[index];
|
||||
int groupIndex;
|
||||
if (vd.amount > 0)
|
||||
{
|
||||
total++;
|
||||
if (vd.amount > limit)
|
||||
{
|
||||
var consume = true;
|
||||
if (barrier < 2147483646u)
|
||||
{
|
||||
_seed = (uint)((int)((ulong)((_seed % 2147483646u + 1) * 48271L) % 2147483647uL) - 1);
|
||||
consume = _seed < barrier;
|
||||
}
|
||||
|
||||
if (consume)
|
||||
{
|
||||
vd.amount--;
|
||||
groupIndex = vd.groupIndex;
|
||||
factory.veinGroups[groupIndex].amount--;
|
||||
if (vd.amount <= 0)
|
||||
{
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
if (!_veins.TryGetValue(productId, out veins))
|
||||
break;
|
||||
length = veins.Count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
groupIndex = vd.groupIndex;
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
if (!_veins.TryGetValue(productId, out veins))
|
||||
break;
|
||||
length = veins.Count - 1;
|
||||
}
|
||||
|
||||
return (total, energy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AssemblyName>LogisticMiner</AssemblyName>
|
||||
<BepInExPluginGuid>org.soardev.logisticminer</BepInExPluginGuid>
|
||||
<Description>DSP MOD - LogisticMiner</Description>
|
||||
<Version>0.2.0</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,50 @@
|
||||
# LogisticMiner
|
||||
|
||||
#### Logistic Storages can mine all ores/water on current planet
|
||||
#### 物流塔可以采集当前星球的全部矿产(以及水)
|
||||
|
||||
## Usage
|
||||
|
||||
* Inspired
|
||||
by [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
||||
But it is heavily optimized to resolve performance, accuracy and other issues in PlanetMiner.
|
||||
* (Optimization to PlanetMiner) Only recalculate count of veins when vein chunks are changed (added/removed by foundations/Sandbox-Mode, or
|
||||
exhausted), so this removes Dictionary allocation on each planet for every frame.
|
||||
* (Optimization to PlanetMiner) More accurate frame counting by use float number.
|
||||
* (Optimization to PlanetMiner) Does not increase power consumptions on `Veins Utilization` upgrades.
|
||||
* (Optimization to PlanetMiner) Separate power consumptions for veins, oil seeps and water.
|
||||
* (Optimization to PlanetMiner) Power consumptions are counted by groups of veins and count of oil seeps, which is more sensible.
|
||||
* Can burn fuels in certain slot when energy below half of max.
|
||||
* (Optimization to PlanetMiner) Sprayed fuels generates extra energy as normal.
|
||||
* (Optimization to PlanetMiner) All used parameters are configurable:
|
||||
* Logistic Miner has the same speed as normal Mining Machine for normal ores by default.
|
||||
But you can set mining scale in configuration, which makes Logistic Miner working like Advance Mining Machines:
|
||||
power
|
||||
consumption increases by the square of the scale, and gradually decrease mining speed over half of the maximum
|
||||
count.
|
||||
This applies to all of veins, oils and water.
|
||||
Mining scale can be set to 0(by default), which means it is automatically set by tech unlocks, set to 300 when you
|
||||
reaches Advanced Mining Machine, otherwise 100.
|
||||
* 100/s for water by default.
|
||||
* Energy costs: 1MW/vein-group & 10MW/water-slot & 1.8MW/oil-seep(configurable)
|
||||
* Fuels burning slot. Default: 4th for ILS, 4th for PLS. Set to 0 to disable it.
|
||||
|
||||
## 使用说明
|
||||
|
||||
* 创意来自 [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
||||
对性能重度优化,并解决了PlanetMiner的精度等问题。
|
||||
* (对PlanetMiner的优化) 仅当矿堆发生变化(填埋/恢复/采完)时重新计算矿堆数据,解决每行星每计算帧要重建字典的性能问题。
|
||||
* (对PlanetMiner的优化) 用浮点数保证更精确的帧计算。
|
||||
* (对PlanetMiner的优化) 升级`矿物利用`不会提升能耗。
|
||||
* (对PlanetMiner的优化) 分开矿物,油井和水的采集能耗。
|
||||
* (对PlanetMiner的优化) 采集能耗以矿物组,油井为单位,相对更加合理。
|
||||
* 剩余电量少于一半时可以燃烧指定格子的燃料补充。
|
||||
* (对PlanetMiner的优化) 喷涂了增产剂的燃料按照正常的计算方式提供更多的能量(除了原本就不增加能量输出的反物质燃料棒)。
|
||||
* (对PlanetMiner的优化) 所有参数都可以在设置文件内配置:
|
||||
* 物流塔矿机和普通矿机采矿速度一样(等同于同时采集所有对应矿物)。
|
||||
你可以设置采矿倍率改变物流塔矿机采矿速度,和高级采矿机相同地,能耗和倍率的平方成正比,并且在存储矿物量多于一半时逐渐降低采矿倍率。
|
||||
此倍率对各种矿物,油井和水的采集都生效。
|
||||
倍率可以设置为0(默认),此时倍率会随科技解锁而变化,默认是100%,解锁高级采矿机后变为300%。
|
||||
* 水的采集速度默认为100/s。
|
||||
* 能耗:每矿物组 1MW,单格水 10MW,每油井 1.8MW。
|
||||
* 燃料格位置。默认:星际物流塔第4格,行星内物流塔第4格。设为0则关闭燃料补充能量功能。
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "LogisticMiner",
|
||||
"version_number": "0.2.0",
|
||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LogisticMiner",
|
||||
"description": "Logistic Storages can mine all ores/water on current planet / 物流塔可以采集当前星球的全部矿产(以及水)",
|
||||
"dependencies": [
|
||||
"xiaoye97-BepInEx-5.4.17"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
## Changlog
|
||||
* 1.0.0
|
||||
+ Initial release
|
||||
|
||||
## 更新日志
|
||||
* 1.0.0
|
||||
+ 初始版本
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using BepInEx;
|
||||
using BepInEx.Logging;
|
||||
using HarmonyLib;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLua;
|
||||
|
||||
namespace LuaScriptEngine;
|
||||
|
||||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
||||
public class LuaScriptEngine : BaseUnityPlugin
|
||||
{
|
||||
public new static readonly ManualLogSource Logger =
|
||||
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
||||
|
||||
private Harmony _harmony;
|
||||
|
||||
private static readonly LuaState State = new();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_harmony = Harmony.CreateAndPatchAll(typeof(Patches));
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_harmony?.UnpatchSelf();
|
||||
State.Dispose();
|
||||
}
|
||||
|
||||
private static class Patches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(VFPreload), nameof(VFPreload.InvokeOnLoadWorkEnded))]
|
||||
private static void VFPreload_InvokeOnLoadWorkEnded_Postfix()
|
||||
{
|
||||
State.PostDataLoaded();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.FixedUpdate))]
|
||||
private static void GameMain_FixedUpdate_Prefix()
|
||||
{
|
||||
State.PreUpdate();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.FixedUpdate))]
|
||||
private static void GameMain_FixedUpdate_Postfix()
|
||||
{
|
||||
State.PostUpdate();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
|
||||
private static void GameMain_Begin_Prefix()
|
||||
{
|
||||
State.PreGameBegin();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
|
||||
private static void GameMain_Begin_Postfix()
|
||||
{
|
||||
State.PostGameBegin();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.End))]
|
||||
private static void GameMain_End_Prefix()
|
||||
{
|
||||
State.PreGameEnd();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.End))]
|
||||
private static void GameMain_End_Postfix()
|
||||
{
|
||||
State.PostGameEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<!-- Override the default net472 from Directory.Build.props -->
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<AssemblyName>LuaScriptEngine</AssemblyName>
|
||||
<BepInExPluginGuid>org.soardev.luascriptengine</BepInExPluginGuid>
|
||||
<Description>DSP MOD - LuaScriptEngine</Description>
|
||||
<Version>1.0.0</Version>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLua" Version="1.*" />
|
||||
<PackageReference Include="obs-websocket-dotnet" Version="5.*" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,404 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLua;
|
||||
using OBSWebsocketDotNet;
|
||||
|
||||
namespace LuaScriptEngine;
|
||||
|
||||
public class LuaState : IDisposable
|
||||
{
|
||||
private readonly Lua state = new();
|
||||
private readonly List<LuaFunction> PostDataLoadedFuncs = [];
|
||||
private readonly List<LuaFunction> PreUpdateFuncs = [];
|
||||
private readonly List<LuaFunction> PostUpdateFuncs = [];
|
||||
private readonly List<LuaFunction> PreGameBeginFuncs = [];
|
||||
private readonly List<LuaFunction> PostGameBeginFuncs = [];
|
||||
private readonly List<LuaFunction> PreGameEndFuncs = [];
|
||||
private readonly List<LuaFunction> PostGameEndFuncs = [];
|
||||
private readonly HashSet<Timer> Timers = [];
|
||||
private readonly List<Timer> TimersToRemove = [];
|
||||
private readonly OBSWebsocket _obs = new();
|
||||
private readonly Dictionary<string, string> _scheduledText = [];
|
||||
|
||||
private long _lastSeedKey = 0L;
|
||||
private string _lastClusterString = "";
|
||||
|
||||
public LuaState()
|
||||
{
|
||||
var assemblyPath = System.IO.Path.Combine(
|
||||
System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)!,
|
||||
"scripts"
|
||||
);
|
||||
|
||||
state.State.Encoding = Encoding.UTF8;
|
||||
state.LoadCLRPackage();
|
||||
state.DoString("import('Assembly-CSharp')");
|
||||
state.DoString($"package.path = '{assemblyPath.Replace('\\', '/')}/?.lua'");
|
||||
RegisterFunctions();
|
||||
|
||||
foreach (var file in System.IO.Directory.GetFiles(assemblyPath, "*.lua"))
|
||||
{
|
||||
LuaScriptEngine.Logger.LogInfo($"Loading Lua script: {file}");
|
||||
state.DoFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
state.Dispose();
|
||||
if (_obs.IsConnected)
|
||||
{
|
||||
_obs.Disconnect();
|
||||
}
|
||||
_scheduledText.Clear();
|
||||
Timers.Clear();
|
||||
PreUpdateFuncs.Clear();
|
||||
PostUpdateFuncs.Clear();
|
||||
PreGameBeginFuncs.Clear();
|
||||
PostGameBeginFuncs.Clear();
|
||||
PreGameEndFuncs.Clear();
|
||||
PostGameEndFuncs.Clear();
|
||||
}
|
||||
|
||||
private void RegisterFunctions()
|
||||
{
|
||||
#region Callback Functions
|
||||
state["register_callback"] = (string tp, LuaFunction action) =>
|
||||
{
|
||||
switch (tp)
|
||||
{
|
||||
case "data_loaded":
|
||||
PostDataLoadedFuncs.Add(action);
|
||||
break;
|
||||
case "pre_update":
|
||||
PreUpdateFuncs.Add(action);
|
||||
break;
|
||||
case "post_update":
|
||||
PostUpdateFuncs.Add(action);
|
||||
break;
|
||||
case "pre_game_begin":
|
||||
PreGameBeginFuncs.Add(action);
|
||||
break;
|
||||
case "post_game_begin":
|
||||
PostGameBeginFuncs.Add(action);
|
||||
break;
|
||||
case "pre_game_end":
|
||||
PreGameEndFuncs.Add(action);
|
||||
break;
|
||||
case "post_game_end":
|
||||
PostGameEndFuncs.Add(action);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
state["add_timer"] = Timer (LuaFunction func, long firstInterval, long repeatInterval) =>
|
||||
{
|
||||
var timer = new Timer(func, firstInterval, repeatInterval);
|
||||
Timers.Add(timer);
|
||||
return timer;
|
||||
};
|
||||
|
||||
state["remove_timer"] = void (Timer timer) => { Timers.Remove(timer); };
|
||||
#endregion
|
||||
|
||||
#region OBS Functions
|
||||
state["obs_connect"] = void (string server, string password) =>
|
||||
{
|
||||
if (_obs.IsConnected)
|
||||
{
|
||||
LuaScriptEngine.Logger.LogInfo("Already connected to OBS");
|
||||
return;
|
||||
}
|
||||
_obs.Connected += (_, _) =>
|
||||
{
|
||||
LuaScriptEngine.Logger.LogInfo($"Connected to OBS at {server}");
|
||||
foreach (var (sourceName, text) in _scheduledText)
|
||||
{
|
||||
try
|
||||
{
|
||||
_obs.SetInputSettings(sourceName,
|
||||
new JObject
|
||||
{
|
||||
{ "text", text }
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LuaScriptEngine.Logger.LogError($"Error setting {sourceName}'s text to `{text}`: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
_scheduledText.Clear();
|
||||
};
|
||||
_obs.Disconnected += (_, _) =>
|
||||
{
|
||||
_obs.ConnectAsync(server, password);
|
||||
};
|
||||
_obs.ConnectAsync(server, password);
|
||||
};
|
||||
|
||||
state["obs_disconnect"] = void () =>
|
||||
{
|
||||
_obs.Disconnect();
|
||||
};
|
||||
|
||||
state["obs_set_source_text"] = void (string sourceName, string text) =>
|
||||
{
|
||||
if (_obs.IsConnected)
|
||||
{
|
||||
try
|
||||
{
|
||||
_obs.SetInputSettings(sourceName, new JObject
|
||||
{
|
||||
{ "text", text }
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LuaScriptEngine.Logger.LogError($"Error setting source text: {e}");
|
||||
_obs.Disconnect();
|
||||
_scheduledText[sourceName] = text;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_scheduledText[sourceName] = text;
|
||||
}
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region Common Data Retrieval Functions
|
||||
state["get_current_cluster"] = string () =>
|
||||
{
|
||||
var data = GameMain.data;
|
||||
if (data == null) return "";
|
||||
var seedKey = data.GetClusterSeedKey();
|
||||
if (seedKey == _lastSeedKey) return _lastClusterString;
|
||||
_lastSeedKey = seedKey;
|
||||
_lastClusterString = data.gameDesc.clusterString;
|
||||
return _lastClusterString;
|
||||
};
|
||||
|
||||
var getCurrentResearch = () =>
|
||||
{
|
||||
var history = GameMain.history;
|
||||
if (history == null) return (0, 0, 0L, 0L);
|
||||
var current = history.currentTech;
|
||||
if (current == 0) return (0, 0, 0L, 0L);
|
||||
var techStates = history.techStates;
|
||||
if (!techStates.TryGetValue(current, out var value)) return (0, 0, 0L, 0L);
|
||||
return (current, value.curLevel, value.hashUploaded, value.hashNeeded);
|
||||
};
|
||||
state["get_current_research"] = getCurrentResearch;
|
||||
state["get_current_research_str"] = string (string format) =>
|
||||
{
|
||||
var (current, level, hashUploaded, hashNeeded) = getCurrentResearch();
|
||||
if (current == 0) return "";
|
||||
return string.Format(format, LDB.techs.Select(current).name, level, JournalUtility.TranslateKMGValue(hashUploaded), JournalUtility.TranslateKMGValue(hashNeeded));
|
||||
};
|
||||
|
||||
var getTechLevel = (NLua.LuaTable techIds) =>
|
||||
{
|
||||
var techStates = GameMain.history?.techStates;
|
||||
if (techStates == null) return 0;
|
||||
int level = 0;
|
||||
foreach (var techId in techIds.Values.Cast<long>())
|
||||
{
|
||||
if (!techStates.TryGetValue((int)techId, out var value))
|
||||
{
|
||||
return level;
|
||||
}
|
||||
var newLevel = value.unlocked ? value.curLevel : value.curLevel - 1;
|
||||
if (newLevel > level)
|
||||
{
|
||||
level = newLevel;
|
||||
}
|
||||
if (!value.unlocked)
|
||||
{
|
||||
return level;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
};
|
||||
state["get_tech_level"] = getTechLevel;
|
||||
state["get_tech_level_str"] = string (string format, NLua.LuaTable techIds) =>
|
||||
{
|
||||
var level = getTechLevel(techIds);
|
||||
if (level <= 0) return "";
|
||||
return string.Format(format, level);
|
||||
};
|
||||
|
||||
var getFactoryStat = (int itemId) =>
|
||||
{
|
||||
var gameData = GameMain.data;
|
||||
if (gameData == null) return (0, 0);
|
||||
var statPool = GameMain.statistics?.production.factoryStatPool;
|
||||
if (statPool == null) return (0, 0);
|
||||
long productTotal = 0L, consumeTotal = 0L;
|
||||
for (var i = gameData.factoryCount - 1; i >= 0; i--)
|
||||
{
|
||||
var stat = statPool[i];
|
||||
if (stat == null) continue;
|
||||
var index = stat.productIndices[itemId];
|
||||
var ppool = stat.productPool[index];
|
||||
if (ppool == null) continue;
|
||||
var cursor = ppool.cursor[4];
|
||||
if (cursor > 0)
|
||||
{
|
||||
productTotal += ppool.count[cursor - 1];
|
||||
}
|
||||
cursor = ppool.cursor[4 + 6];
|
||||
if (cursor > 0)
|
||||
{
|
||||
consumeTotal += ppool.count[cursor - 1];
|
||||
}
|
||||
}
|
||||
return (productTotal, consumeTotal);
|
||||
};
|
||||
state["get_factory_stat"] = getFactoryStat;
|
||||
state["get_factory_stat_str"] = string (string format, int itemId) =>
|
||||
{
|
||||
var (productTotal, consumeTotal) = getFactoryStat(itemId);
|
||||
return string.Format(format, JournalUtility.TranslateKMGValue(productTotal), JournalUtility.TranslateKMGValue(consumeTotal));
|
||||
};
|
||||
|
||||
var getDysonSphereTotalGen = () =>
|
||||
{
|
||||
var data = GameMain.data;
|
||||
if (data == null) return 0;
|
||||
return data.GetDysonSphereTotalGen();
|
||||
};
|
||||
state["get_dyson_sphere_power_gen"] = getDysonSphereTotalGen;
|
||||
state["get_dyson_sphere_power_gen_str"] = string (string format) =>
|
||||
{
|
||||
var totalGen = getDysonSphereTotalGen();
|
||||
if (totalGen <= 0) return "";
|
||||
return string.Format(format, JournalUtility.TranslateKMGValue(totalGen * 60L));
|
||||
};
|
||||
#endregion
|
||||
}
|
||||
|
||||
public void PostDataLoaded()
|
||||
{
|
||||
LoopCall(PostDataLoadedFuncs);
|
||||
}
|
||||
|
||||
public void PreUpdate()
|
||||
{
|
||||
if (Timers.Count > 0)
|
||||
{
|
||||
var gameTick = GameMain.gameTick;
|
||||
foreach (var timer in Timers)
|
||||
{
|
||||
if (timer == null || !timer.Check(gameTick)) continue;
|
||||
TimersToRemove.Add(timer);
|
||||
}
|
||||
|
||||
if (TimersToRemove.Count > 0)
|
||||
{
|
||||
foreach (var timer in TimersToRemove)
|
||||
{
|
||||
Timers.Remove(timer);
|
||||
}
|
||||
|
||||
TimersToRemove.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
LoopCall(PreUpdateFuncs);
|
||||
}
|
||||
|
||||
public void PostUpdate()
|
||||
{
|
||||
LoopCall(PostUpdateFuncs);
|
||||
}
|
||||
|
||||
public void PreGameBegin()
|
||||
{
|
||||
var tick = GameMain.gameTick;
|
||||
foreach (var timer in Timers)
|
||||
{
|
||||
if (timer.Reset(tick))
|
||||
{
|
||||
TimersToRemove.Add(timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (TimersToRemove.Count > 0)
|
||||
{
|
||||
foreach (var timer in TimersToRemove)
|
||||
{
|
||||
Timers.Remove(timer);
|
||||
}
|
||||
|
||||
TimersToRemove.Clear();
|
||||
}
|
||||
LoopCall(PreGameBeginFuncs);
|
||||
}
|
||||
|
||||
public void PostGameBegin()
|
||||
{
|
||||
LoopCall(PostGameBeginFuncs);
|
||||
}
|
||||
|
||||
public void PreGameEnd()
|
||||
{
|
||||
LoopCall(PreGameEndFuncs);
|
||||
}
|
||||
|
||||
public void PostGameEnd()
|
||||
{
|
||||
LoopCall(PostGameEndFuncs);
|
||||
}
|
||||
|
||||
private void LoopCall(List<LuaFunction> funcs)
|
||||
{
|
||||
foreach (var func in funcs)
|
||||
{
|
||||
try
|
||||
{
|
||||
func.Call();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LuaScriptEngine.Logger.LogError($"Error in Lua script: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Timer(LuaFunction func, long startInterval, long repeatInterval = 0L)
|
||||
{
|
||||
public bool Check(long gameTick)
|
||||
{
|
||||
if (gameTick < _nextTick) return false;
|
||||
try
|
||||
{
|
||||
_func.Call();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LuaScriptEngine.Logger.LogError($"Error in Lua script: {e}");
|
||||
}
|
||||
|
||||
if (_repeatInterval <= 0L) return true;
|
||||
_nextTick += _repeatInterval;
|
||||
if (_nextTick < gameTick)
|
||||
_nextTick = gameTick + 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Reset(long gameTick)
|
||||
{
|
||||
if (_repeatInterval <= 0L) return true;
|
||||
_nextTick = gameTick + _repeatInterval;
|
||||
return false;
|
||||
}
|
||||
|
||||
private readonly LuaFunction _func = func;
|
||||
private readonly long _repeatInterval = repeatInterval;
|
||||
private long _nextTick = GameMain.gameTick + startInterval;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# LuaScriptEngine
|
||||
|
||||
#### Write mod functions in lua scripts
|
||||
#### 用lua脚本编写mod功能
|
||||
|
||||
## Usage
|
||||
|
||||
## 使用说明
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "LuaScriptEngine",
|
||||
"version_number": "1.0.0",
|
||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LuaScriptEngine",
|
||||
"description": "Write mod functions in lua scripts / 用lua脚本编写mod功能",
|
||||
"dependencies": [
|
||||
"xiaoye97-BepInEx-5.4.17"
|
||||
]
|
||||
}
|
||||
@@ -1,29 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>MechaDronesTweaks</AssemblyName>
|
||||
<BepInExPluginGuid>org.soardev.mechadronestweaks</BepInExPluginGuid>
|
||||
<Description>DSP MOD - MechaDronesTweaks</Description>
|
||||
<Version>1.1.4</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path '$(TargetPath)', package/icon.png, package/manifest.json, README.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -186,7 +186,7 @@ public class Patch : BaseUnityPlugin, IModCanSave
|
||||
sorter.stt = sorter.stt * om / nm;
|
||||
if (sorter.time > sorter.stt)
|
||||
{
|
||||
sorter.time = sorter.stt - sorter.speed;
|
||||
sorter.time = sorter.stt - InserterComponent.speed;
|
||||
}
|
||||
|
||||
if (powerSystem == null) continue;
|
||||
|
||||
@@ -1,31 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<BepInExPluginGuid>org.soardev.overclockeverything</BepInExPluginGuid>
|
||||
<Description>DSP MOD - OverclockEverything</Description>
|
||||
<Version>1.0.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PackageId>OverclockEverything</PackageId>
|
||||
<RootNamespace>OverclockEverything</RootNamespace>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path '$(TargetPath)', package/icon.png, package/manifest.json, README.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -1,29 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>PoolOpt</AssemblyName>
|
||||
<BepInExPluginGuid>org.soardev.poolopt</BepInExPluginGuid>
|
||||
<Description>DSP MOD - PoolOpt</Description>
|
||||
<Version>0.9.3</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path '$(TargetPath)', package/icon.png, package/manifest.json, README.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -9,35 +9,15 @@ Add various cheat functions while disabling abnormal determinants
|
||||
|
||||
Moved [to another repo](https://github.com/soarqin/DSP_Mods_TO/tree/master/CompressSave)
|
||||
|
||||
## [LogisticHub](LogisticHub)
|
||||
|
||||
Cheat functions for Logistic Storages, make them mine resources on the planet and exchange items from certain buildings
|
||||
物流塔作弊功能,使其可以在星球上采矿并与特定建筑物交换物品
|
||||
|
||||
## [HideTips](HideTips)
|
||||
|
||||
Hide/Disable various tutorial tips/messages
|
||||
隐藏/屏蔽各种引导提示/消息
|
||||
|
||||
## [Dustbin](Dustbin)
|
||||
|
||||
Can turn Storages and Tanks into Dustbin(Destroy incoming items)
|
||||
储物仓和储液罐可以转变为垃圾桶(销毁送进的物品)
|
||||
|
||||
## [OverclockEverything](OverclockEverything)
|
||||
## [HideTips](HideTips)
|
||||
|
||||
Boost nearly all structures
|
||||
加速几乎所有建筑功能
|
||||
|
||||
## [UniverseGenTweaks](UniverseGenTweaks)
|
||||
|
||||
Universe Generator Tweak
|
||||
宇宙生成参数调节
|
||||
|
||||
## [MechaDronesTweaks](MechaDronesTweaks)
|
||||
|
||||
Some tweaks for mecha drones and build functions(Successor to FastDrones MOD)
|
||||
机甲建设机和建设功能调整(FastDrones MOD的后继者)
|
||||
Hide/Disable various tutorial tips/messages
|
||||
隐藏/屏蔽各种引导提示/消息
|
||||
|
||||
## [LabOpt](LabOpt)
|
||||
|
||||
@@ -46,11 +26,35 @@ Marked as obsoleted temporarily, needs more investigation about LabComponent's m
|
||||
优化研究站性能
|
||||
暂时标识为过期,需要更多关于LabComponent机制的研究
|
||||
|
||||
## [LogisticMiner](LogisticMiner)
|
||||
|
||||
Logistic Storages can mine all ores/water on current planet
|
||||
物流塔可以采集当前星球的全部矿产(以及水)
|
||||
|
||||
## [LuaScriptEngine](LuaScriptEngine)
|
||||
Write mod functions in lua scripts
|
||||
用lua脚本编写mod功能
|
||||
|
||||
## [MechaDronesTweaks](MechaDronesTweaks)
|
||||
|
||||
Some tweaks for mecha drones and build functions(Successor to FastDrones MOD)
|
||||
机甲建设机和建设功能调整(FastDrones MOD的后继者)
|
||||
|
||||
## [OverclockEverything](OverclockEverything)
|
||||
|
||||
Boost nearly all structures
|
||||
加速几乎所有建筑功能
|
||||
|
||||
## [PoolOpt](PoolOpt)
|
||||
|
||||
Optimize memory pools on loading gamesaves
|
||||
加载游戏存档时优化内存池的使用
|
||||
|
||||
## [UniverseGenTweaks](UniverseGenTweaks)
|
||||
|
||||
Universe Generator Tweak
|
||||
宇宙生成参数调节
|
||||
|
||||
## [UserCloak](UserCloak)
|
||||
|
||||
Cloak(Fake) user account info
|
||||
|
||||
+119
-9
@@ -3,6 +3,61 @@
|
||||
|
||||
## 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
|
||||
* `Initialize This Planet`: Fix known crashes and infinite loop.
|
||||
* `Show recent milkyway upload results`: Fix an issue that it only shows earliest results but latest ones.
|
||||
* Fix some other minor bugs found by LLM AI.
|
||||
* 1.5.5
|
||||
* `Initialize This Planet`:
|
||||
* Fix crash issue.
|
||||
* Add 3 options to return certain items.
|
||||
* Enable `Hide UI` function(`F11` by default) while on Star Map view: Hide all other elements in universe.
|
||||
* Fix warning from abnormal check for following features:
|
||||
* `Unlock all techs with metadata`
|
||||
* `Disable battle-related techs in Peace mode`
|
||||
* ``Restore upgrades of `Sorter Cargo Stacking` on panel``
|
||||
* 1.5.4
|
||||
* `Auto-contruct`:
|
||||
* Add a UI option to hide it completely.
|
||||
* Fix an issue that may cause circling.
|
||||
* `Auto-cruise`: Fix some user experience related logics.
|
||||
* 1.5.3
|
||||
* New feature: `Auto-contruct`
|
||||
* Fly to buildings to be contructed automatically.
|
||||
* `Auto-cruise`: Do not try to fly away planet when `Drive Engine 2` is not researched.
|
||||
* `Initialize This Planet`: Fix logistic station ships rendering issue.
|
||||
* Copying Wireless Power Tower works as expected when `Drag building power poles in maximum connection range` and `Build Tesla Tower and Wireless Power Tower alternately` are enabled.
|
||||
* `Belt signals for buy out dark fog items automatically`: Grid position on panel is moved to avoid conflict with newly added signals.
|
||||
* Fix implementation of ``Restore upgrades of `Sorter Cargo Stacking` on panel`` to make it working again.
|
||||
* 1.5.2
|
||||
* Fix crash while error occurs on milkyway login/upload.
|
||||
* 1.5.1
|
||||
* Support game version 0.10.34.28392
|
||||
* 1.5.0
|
||||
* Support game version 0.10.34
|
||||
* New features:
|
||||
* `Show top players in milkyway`: The button is available on top-left corner of Milkyway View
|
||||
* `Show recent milkyway upload results`: The button is on UXAssist `General` tab.
|
||||
* `Night Sunlight`: Fix bugs that sunlight angle is not updated after loading a save.
|
||||
* `Enhanced control for logistic storage capacities`: Working for Logistics Control Panel now.
|
||||
* `Protect veins from exhaustion`: Fix a minor bug.
|
||||
* `Initialize This Planet`: Improve stability and fix some bugs.
|
||||
* 1.4.5
|
||||
* New feature: `Ctrl+Shift+Click to pick items from whole belts`, with 2 suboptions: `Include branches of belts` and `Include connected inserters`
|
||||
* Patch [BlueprintTweaks](https://thunderstore.io/c/dyson-sphere-program/p/kremnev8/BlueprintTweaks/) temporarily to fix `Drag Remove` functions (And wait for limoka to merge the [Pull Request](https://github.com/limoka/DSP-Mods/pull/133)):
|
||||
* Ground rendering is correct now.
|
||||
* Dismantle logic follows offcial's implementation to avoid possible crashes.
|
||||
* Fixed CommonAPI patch to make shortcut key settings saved as expect now, sorry for wrong implementation in last version.
|
||||
* 1.4.4
|
||||
* `Remember window position and size on last exit`: Fix compatiblity for game patch 0.10.33
|
||||
* `Real-time logistic stations info panel`: Try to fix a display issue.
|
||||
* Patch [CommonAPI](https://thunderstore.io/c/dyson-sphere-program/p/CommonAPI/CommonAPI/) temporarily to fix a known issue that shortcut key settings are not saved to config, while its [PR](https://github.com/limoka/CommonAPI/pull/14) is not merged yet.
|
||||
* 1.4.3
|
||||
* `Build Tesla Tower and Wireless Power Tower alternately`:
|
||||
* Fix wrong implementation for latest game patch.
|
||||
@@ -26,7 +81,7 @@
|
||||
* Fix background image issue for tab buttons on config window.
|
||||
* Now build in C# `Debug` Configuration, to avoid some issues caused by optimizations in `Release` Configuration.
|
||||
* 1.3.7
|
||||
* `Re-initialize planet`: Fix a possible crash.
|
||||
* `Initialize This Planet`: Fix a possible crash.
|
||||
* `Auto-config logistic stations`: Add `Set default remote logic to storage`
|
||||
* 1.3.6
|
||||
* `Dismantle blueprint selected buildings`:
|
||||
@@ -43,7 +98,7 @@
|
||||
* 1.3.3
|
||||
* `Starmap filter`: Hide top overlaping windows while the filter UI is shown.
|
||||
* `Auto-config logistic stations`: Can set Max. Charging Power for Battlefield Analysis Base now.
|
||||
* `Re-initialize planet`: Fix a crash.
|
||||
* `Initialize This Planet`: Fix a crash.
|
||||
* `Auto navigation on sailings`:
|
||||
* Add a button to enable/disable `Auto-cruise` quickly.
|
||||
* Do not auto-use Warper if required Tech is not researched.
|
||||
@@ -58,7 +113,7 @@
|
||||
* New button: `Unlock all techs with metadata`
|
||||
* Add a checkbox to make union of results in starmap filter.
|
||||
* Fix some starmap vein/planet filter conditions.
|
||||
* Fix a crash caused by `Re-initialize planet` in peace mode.
|
||||
* Fix a crash caused by `Initialize This Planet` in peace mode.
|
||||
* Fix compatibility with `NebulaMultiplayerMod`.
|
||||
* 1.3.1
|
||||
* Fix an issue that some UI elements are hidden while hitting the newly added combobox on Starmap.
|
||||
@@ -258,7 +313,7 @@
|
||||
* Fix some issues in `Auto nativation` and `Auto-cruise`, now only boosts when core energy at least 10% and warps when core energy at least 50%
|
||||
* 1.0.20
|
||||
* Fix an infinite-loop issue when `Quick build and dismantle stacking labs` and `No condition build` are both enabled
|
||||
* Fix a crash caused by `Re-initialize planet` in combat mode
|
||||
* Fix a crash caused by `Initialize This Planet` in combat mode
|
||||
* 1.0.19
|
||||
* New functions:
|
||||
* `Quick build and dismantle stacking labs`
|
||||
@@ -288,7 +343,7 @@
|
||||
* Enable `Hide UI` function(`F11` by default) while on Star Map view
|
||||
* New function: `Treat stack items as single in monitor components`
|
||||
* 1.0.14
|
||||
* Fix crash in `Re-initialize planet` again
|
||||
* Fix crash in `Initialize This Planet` again
|
||||
* `Off-grid building and stepped rotation`: Add Z coordinate to display, and adjust the precision to 4 decimal after point
|
||||
* 1.0.13
|
||||
* `Off-grid building and stepped rotation`: show building coordinates(relative to grids) on building preview and building info panel now
|
||||
@@ -296,7 +351,7 @@
|
||||
* Increase capacity of player order queue to 128 (from 16)
|
||||
* Fix issue caused by game updates
|
||||
* `Remove some build conditions`: fixed issue that some conditions are not eliminated
|
||||
* `Re-initialize planet`: fixed crash issue
|
||||
* `Initialize This Planet`: fixed crash issue
|
||||
* 1.0.12
|
||||
* Fix a bug that ejectors aimed at even-numbered orbits stop working when `Stop ejectors when available nodes are all filled up` is enabled.
|
||||
* 1.0.11
|
||||
@@ -323,7 +378,7 @@
|
||||
* 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`.
|
||||
* Add confirmation popup for `Initialize This 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 window position not saved correctly when quit game without using in-game menu.
|
||||
* 1.0.2
|
||||
@@ -346,6 +401,61 @@
|
||||
|
||||
## 更新日志
|
||||
|
||||
* 1.5.8
|
||||
* `初始化本行星`:修复可能的崩溃。
|
||||
* `记住上次退出时的窗口位置和大小`:移除不再有用的窗口钩子。
|
||||
* `物流站实时信息面板`:修复物流塔数量 > 128 时的显示问题。
|
||||
* 1.5.7
|
||||
* 修复了与游戏更新0.10.34.28505的兼容性。
|
||||
* 1.5.6
|
||||
* `初始化本行星`:修复已知的崩溃和无限循环问题。
|
||||
* `显示最近银河系上传结果`:修复仅显示最早上传结果而非最新结果的问题。
|
||||
* 修复一些由 LLM AI 发现的其他小问题。
|
||||
* 1.5.5
|
||||
* `初始化本行星`:
|
||||
* 修复崩溃问题。
|
||||
* 增加了3个可返还特定物品的选项。
|
||||
* 在星图视图中启用`隐藏UI`功能(默认按键为`F11`): 隐藏所有其他宇宙元素。
|
||||
* 修复以下功能的异常检查警告:
|
||||
* `使用元数据解锁所有科技`
|
||||
* `在和平模式下隐藏战斗相关科技`
|
||||
* ``在升级面板上恢复`分拣器货物堆叠`的升级``
|
||||
* 1.5.4
|
||||
* `自动建造`:
|
||||
* 增加了一个 UI 选项,可完全隐藏该功能。
|
||||
* 修复了可能导致盘旋的问题。
|
||||
* `自动巡航`:修复了一些用户体验相关的逻辑问题。
|
||||
* 1.5.3
|
||||
* 新功能:`自动建造`
|
||||
* 自动飞行到待建造的建筑处进行建造。
|
||||
* `自动巡航`:在未研究`驱动引擎 Lv2`时,不再尝试飞离行星
|
||||
* `初始化行星`:修复物流塔运输船显示异常的问题
|
||||
* 当启用`拖动建造电线杆时自动使用最大连接距离间隔`和`交替建造电力感应塔和无线输电塔`时,对复制无线输电塔也生效了
|
||||
* `用于自动购买黑雾物品的传送带信号`:移动了其面板网格位置,避免与新添加的信号冲突
|
||||
* 修复``在升级面板上恢复`分拣器货物堆叠`的升级``的实现,使其重新工作
|
||||
* 1.5.2
|
||||
* 修复在银河系登录/上传出错时崩溃的问题
|
||||
* 1.5.1
|
||||
* 支持游戏版本 0.10.34.28392
|
||||
* 1.5.0
|
||||
* 支持游戏版本 0.10.34
|
||||
* 新功能:
|
||||
* `显示银河系发电量排行`:按钮位于银河视图左上角
|
||||
* `显示最近银河系上传结果`:按钮在UXAssist的`常规`标签页内
|
||||
* `夜间日光灯`:修复加载存档后日光角度没有更新的问题
|
||||
* `物流塔存储数量限制控制改进`:现在可用于物流控制面板
|
||||
* `保护矿脉不会耗尽`:修复了一个小问题
|
||||
* `初始化本行星`:提升稳定性并修复部分Bug
|
||||
* 1.4.5
|
||||
* 新功能:`按住Ctrl+Shift点击从整条传送带抓取物品`,包含两个子选项:`包含传送带分支` 和 `包含连接的分拣器`
|
||||
* 临时修复 [BlueprintTweaks](https://thunderstore.io/c/dyson-sphere-program/p/kremnev8/BlueprintTweaks/) 的 `拖拽拆除` 功能(等待 limoka 合并 [Pull Request](https://github.com/limoka/DSP-Mods/pull/133)):
|
||||
* 地面绘制现在已正确
|
||||
* 拆除逻辑遵循官方实现,避免潜在崩溃可能
|
||||
* 修正了 CommonAPI 的补丁,现在快捷键设置可以如预期保存了,不好意思上一版本实现有误
|
||||
* 1.4.4
|
||||
* `记住上次退出时的窗口位置和大小`:修复对游戏补丁0.10.33的兼容性
|
||||
* `物流站实时信息面板`:尝试修复一个显示问题
|
||||
* 对[CommonAPI](https://thunderstore.io/c/dyson-sphere-program/p/CommonAPI/CommonAPI/)临时打补丁,修复快捷键设置未能保存到配置文件的已知问题(其[PR](https://github.com/limoka/CommonAPI/pull/14)仍未合并)
|
||||
* 1.4.3
|
||||
* `交替建造电力感应塔和无线输电塔`:
|
||||
* 修复了在最新游戏补丁中的错误实现
|
||||
@@ -369,7 +479,7 @@
|
||||
* 修复了配置窗口标签按钮的背景图像问题
|
||||
* 现在使用C#的`Debug`配置构建,以避免`Release`配置中的优化导致的一些问题
|
||||
* 1.3.7
|
||||
* `重新初始化行星`: 修复可能导致崩溃的问题
|
||||
* `初始化行星`: 修复可能导致崩溃的问题
|
||||
* `自动配置物流站`: 增加`设置默认远程逻辑为仓储`
|
||||
* 1.3.6
|
||||
* `拆除蓝图选中的建筑`:
|
||||
@@ -386,7 +496,7 @@
|
||||
* 1.3.3
|
||||
* `星图过滤器`:当过滤器UI显示时隐藏顶部重叠窗口
|
||||
* `自动配置物流站`:现在可以为战场分析基站设置最大充能功率
|
||||
* `重新初始化行星`:修复崩溃问题
|
||||
* `初始化行星`:修复崩溃问题
|
||||
* `航行时自动导航`:
|
||||
* 添加快速启用/禁用`自动巡航`的按钮
|
||||
* 如果所需科技未研究则不自动使用翘曲器
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UXAssist.Common;
|
||||
|
||||
@@ -9,24 +10,40 @@ public class GameLogic : PatchImpl<GameLogic>
|
||||
public static Action OnGameBegin;
|
||||
public static Action OnGameEnd;
|
||||
|
||||
private static void InvokeSafe(Action action)
|
||||
{
|
||||
if (action == null) return;
|
||||
foreach (var handler in action.GetInvocationList())
|
||||
{
|
||||
try
|
||||
{
|
||||
((Action)handler)();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(VFPreload), nameof(VFPreload.InvokeOnLoadWorkEnded))]
|
||||
public static void VFPreload_InvokeOnLoadWorkEnded_Postfix()
|
||||
{
|
||||
OnDataLoaded?.Invoke();
|
||||
InvokeSafe(OnDataLoaded);
|
||||
}
|
||||
|
||||
[HarmonyPostfix, HarmonyPriority(Priority.First)]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
|
||||
public static void GameMain_Begin_Postfix()
|
||||
{
|
||||
OnGameBegin?.Invoke();
|
||||
InvokeSafe(OnGameBegin);
|
||||
}
|
||||
|
||||
[HarmonyPostfix, HarmonyPriority(Priority.Last)]
|
||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.End))]
|
||||
public static void GameMain_End_Postfix()
|
||||
{
|
||||
OnGameEnd?.Invoke();
|
||||
InvokeSafe(OnGameEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace UXAssist.Common;
|
||||
|
||||
public enum KnownItemId : int
|
||||
{
|
||||
Drone = 5001,
|
||||
Ship = 5002,
|
||||
Bot = 5003,
|
||||
Warper = 1210,
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public static class Util
|
||||
{
|
||||
public static Type[] GetTypesFiltered(Assembly assembly, Func<Type, bool> predicate)
|
||||
{
|
||||
return assembly.GetTypes().Where(predicate).ToArray();
|
||||
return [.. assembly.GetTypes().Where(predicate)];
|
||||
}
|
||||
|
||||
public static Type[] GetTypesInNamespace(Assembly assembly, string nameSpace) => GetTypesFiltered(assembly, t => string.Equals(t.Namespace, nameSpace, StringComparison.Ordinal));
|
||||
|
||||
@@ -45,7 +45,6 @@ public static class WinApi
|
||||
public const int GWLP_ID = -12;
|
||||
public const int GWL_STYLE = -16;
|
||||
public const int GWLP_USERDATA = -21;
|
||||
public const int GWLP_WNDPROC = -4;
|
||||
public const int DWLP_DLGPROC = 0x4;
|
||||
public const int DWLP_MSGRESULT = 0;
|
||||
public const int DWLP_USER = 0x8;
|
||||
@@ -99,10 +98,11 @@ public static class WinApi
|
||||
|
||||
#region Functions
|
||||
|
||||
public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);
|
||||
|
||||
[DllImport("kernel32", ExactSpelling = true)]
|
||||
public static extern int GetLastError();
|
||||
[DllImport("user32", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int lpdwProcessId);
|
||||
|
||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern int GetWindowLong(IntPtr hwnd, int nIndex);
|
||||
@@ -110,12 +110,6 @@ public static class WinApi
|
||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern int SetWindowLong(IntPtr hwnd, int nIndex, int dwNewLong);
|
||||
|
||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);
|
||||
|
||||
[DllImport("user32", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int lpdwProcessId);
|
||||
|
||||
[DllImport("user32", ExactSpelling = true)]
|
||||
public static extern bool GetWindowRect(IntPtr hwnd, out Rect lpRect);
|
||||
|
||||
@@ -125,33 +119,8 @@ public static class WinApi
|
||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern bool SetWindowText(IntPtr hwnd, string lpString);
|
||||
|
||||
[DllImport("user32", ExactSpelling = true)]
|
||||
public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint);
|
||||
|
||||
[DllImport("user32", ExactSpelling = true)]
|
||||
public static extern IntPtr MonitorFromRect([In] ref Rect lpRect, uint dwFlags);
|
||||
|
||||
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern IntPtr GetCurrentProcess();
|
||||
|
||||
[DllImport("kernel32", ExactSpelling = true)]
|
||||
public static extern int GetCurrentProcessId();
|
||||
|
||||
[DllImport("kernel32", ExactSpelling = true)]
|
||||
public static extern IntPtr GetConsoleWindow();
|
||||
|
||||
// GetPriorityClass and SetPriorityClass
|
||||
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern int GetPriorityClass(IntPtr hProcess);
|
||||
|
||||
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern bool SetPriorityClass(IntPtr hProcess, int dwPriorityClass);
|
||||
|
||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
|
||||
|
||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -24,6 +24,13 @@ public static class FactoryFunctions
|
||||
cargoTraffic.AlterBeltConnections(beltId, 0, i0, i1, i2);
|
||||
}
|
||||
|
||||
public static bool ObjectIsBeltOrInserter(PlanetFactory factory, int objId)
|
||||
{
|
||||
if (objId == 0) return false;
|
||||
ItemProto proto = LDB.items.Select(objId > 0 ? factory.entityPool[objId].protoId : factory.prebuildPool[-objId].protoId);
|
||||
return proto != null && (proto.prefabDesc.isBelt || proto.prefabDesc.isInserter);
|
||||
}
|
||||
|
||||
public static void DismantleBlueprintSelectedBuildings()
|
||||
{
|
||||
var player = GameMain.mainPlayer;
|
||||
@@ -50,7 +57,7 @@ public static class FactoryFunctions
|
||||
for (var j = 0; j < 2; j++)
|
||||
{
|
||||
factory.ReadObjectConn(objId, j, out _, out var connObjId, out _);
|
||||
if (connObjId == 0 || factory.ObjectIsBelt(connObjId) || blueprintCopyTool.ObjectIsInserter(connObjId)) continue;
|
||||
if (connObjId == 0 || ObjectIsBeltOrInserter(factory, connObjId)) continue;
|
||||
needCheck = true;
|
||||
break;
|
||||
}
|
||||
@@ -59,7 +66,7 @@ public static class FactoryFunctions
|
||||
for (var k = 0; k < 16; k++)
|
||||
{
|
||||
factory.ReadObjectConn(objId, k, out _, out var connObjId, out _);
|
||||
if (connObjId != 0 && (index = buildPreviewsToRemove.BinarySearch(connObjId)) < 0 && (factory.ObjectIsBelt(connObjId) || blueprintCopyTool.ObjectIsInserter(connObjId)))
|
||||
if (connObjId != 0 && (index = buildPreviewsToRemove.BinarySearch(connObjId)) < 0 && ObjectIsBeltOrInserter(factory, connObjId))
|
||||
buildPreviewsToRemove.Insert(~index, connObjId);
|
||||
}
|
||||
}
|
||||
@@ -70,7 +77,7 @@ public static class FactoryFunctions
|
||||
for (var j = 0; j < 2; j++)
|
||||
{
|
||||
factory.ReadObjectConn(connObjId, j, out _, out var connObjId2, out _);
|
||||
if (connObjId2 == 0 || (index = buildPreviewsToRemove.BinarySearch(connObjId2)) >= 0 || factory.ObjectIsBelt(connObjId2) || blueprintCopyTool.ObjectIsInserter(connObjId2)) continue;
|
||||
if (connObjId2 == 0 || (index = buildPreviewsToRemove.BinarySearch(connObjId2)) >= 0 || ObjectIsBeltOrInserter(factory, connObjId2)) continue;
|
||||
buildPreviewsToRemove.Insert(~index, connObjId);
|
||||
break;
|
||||
}
|
||||
@@ -81,7 +88,7 @@ public static class FactoryFunctions
|
||||
for (var j = 0; j < 16; j++)
|
||||
{
|
||||
factory.ReadObjectConn(objId, j, out _, out var connObjId, out _);
|
||||
if (connObjId != 0 && (index = buildPreviewsToRemove.BinarySearch(connObjId)) < 0 && (factory.ObjectIsBelt(connObjId) || blueprintCopyTool.ObjectIsInserter(connObjId)))
|
||||
if (connObjId != 0 && (index = buildPreviewsToRemove.BinarySearch(connObjId)) < 0 && ObjectIsBeltOrInserter(factory, connObjId))
|
||||
buildPreviewsToRemove.Insert(~index, connObjId);
|
||||
}
|
||||
}
|
||||
@@ -95,11 +102,11 @@ public static class FactoryFunctions
|
||||
if (stationId > 0)
|
||||
{
|
||||
StationComponent sc = stationPool[stationId];
|
||||
if (sc.id != stationId) continue;
|
||||
if (sc is null || sc.id != stationId) continue;
|
||||
for (int i = 0; i < sc.storage.Length; i++)
|
||||
{
|
||||
int package = player.TryAddItemToPackage(sc.storage[i].itemId, sc.storage[i].count, sc.storage[i].inc, true, objId);
|
||||
UIItemup.Up(sc.storage[i].itemId, package);
|
||||
int added = player.TryAddItemToPackage(sc.storage[i].itemId, sc.storage[i].count, sc.storage[i].inc, true, objId);
|
||||
if (added > 0) UIItemup.Up(sc.storage[i].itemId, added);
|
||||
}
|
||||
sc.storage = new StationStore[sc.storage.Length];
|
||||
sc.needs = new int[sc.needs.Length];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using BepInEx.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -9,7 +9,12 @@ namespace UXAssist.Functions;
|
||||
public static class PlanetFunctions
|
||||
{
|
||||
public static ConfigEntry<int> OrbitalCollectorMaxBuildCount;
|
||||
public static ConfigEntry<bool> ReturnBuildingsOnInitializeEnabled;
|
||||
public static ConfigEntry<bool> ReturnLogisticStorageItemsOnInitializeEnabled;
|
||||
public static ConfigEntry<bool> ReturnBeltAFactoryItemsOnInitializeEnabled;
|
||||
|
||||
private const int OrbitalCollectorItemId = 2105;
|
||||
|
||||
public static void DismantleAll(bool toBag)
|
||||
{
|
||||
var player = GameMain.mainPlayer;
|
||||
@@ -19,28 +24,40 @@ public static class PlanetFunctions
|
||||
if (factory == null) return;
|
||||
foreach (var etd in factory.entityPool)
|
||||
{
|
||||
if (etd.id == 0) continue;
|
||||
var stationId = etd.stationId;
|
||||
if (stationId > 0)
|
||||
{
|
||||
var sc = GameMain.localPlanet.factory.transport.stationPool[stationId];
|
||||
if (sc is null || sc.id != stationId) continue;
|
||||
if (toBag)
|
||||
{
|
||||
for (var i = sc.storage.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var package = player.TryAddItemToPackage(sc.storage[i].itemId, sc.storage[i].count, 0, true, etd.id);
|
||||
UIItemup.Up(sc.storage[i].itemId, package);
|
||||
var added = player.TryAddItemToPackage(sc.storage[i].itemId, sc.storage[i].count, sc.storage[i].inc, true, etd.id);
|
||||
if (added > 0) UIItemup.Up(sc.storage[i].itemId, added);
|
||||
sc.storage[i].count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = sc.storage.Length - 1; i >= 0; i--)
|
||||
{
|
||||
sc.storage[i].count = 0;
|
||||
}
|
||||
}
|
||||
sc.storage = new StationStore[sc.storage.Length];
|
||||
sc.needs = new int[sc.needs.Length];
|
||||
}
|
||||
if (toBag)
|
||||
{
|
||||
player.controller.actionBuild.DoDismantleObject(etd.id);
|
||||
int protoId = 0;
|
||||
factory.DismantleFinally(player, etd.id, ref protoId);
|
||||
}
|
||||
else
|
||||
{
|
||||
factory.RemoveEntityWithComponents(etd.id, false);
|
||||
var objId = etd.id;
|
||||
factory.BeforeDismantleObject(objId);
|
||||
factory.RemoveEntityWithComponents(objId, false);
|
||||
factory.OnDismantleObject(objId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,38 +76,445 @@ public static class PlanetFunctions
|
||||
uiGame.ShutAllFullScreens();
|
||||
}
|
||||
player.controller.actionBuild.Close();
|
||||
|
||||
var groundCombatModule = player.mecha.groundCombatModule;
|
||||
for (var i = 0; i < groundCombatModule.moduleFleets.Length; i++)
|
||||
for (var i = groundCombatModule.moduleFleets.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var entry = groundCombatModule.moduleFleets[i];
|
||||
if (entry.fleetId <= 0 || !entry.fleetEnabled) continue;
|
||||
entry.fleetEnabled = false;
|
||||
groundCombatModule.RemoveFleetDirectly(i);
|
||||
}
|
||||
//planet.data = new PlanetRawData(planet.precision);
|
||||
//planet.data.CalcVerts();
|
||||
var constructionSystem = factory.constructionSystem;
|
||||
var constructionModule = player.mecha.constructionModule;
|
||||
for (var i = constructionSystem.drones.cursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var drone = ref constructionSystem.drones.buffer[i];
|
||||
if (drone.id <= 0) continue;
|
||||
var owner = drone.owner;
|
||||
constructionSystem.ResetDroneTargets(ref drone);
|
||||
if (owner == 0)
|
||||
{
|
||||
factory.RemoveCraftWithComponents(drone.craftId);
|
||||
constructionModule.droneIdleCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
drone.movement = factory.gameData.history.constructionDroneMovement;
|
||||
factory.craftPool[drone.craftId].pos = constructionSystem.constructionModules[owner].baseEjectPos;
|
||||
constructionSystem.constructionModules[owner].droneIdleCount++;
|
||||
}
|
||||
}
|
||||
if (constructionSystem.constructStats?.buffer != null)
|
||||
{
|
||||
for (var i = constructionSystem.constructStats.cursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var constructStat = ref constructionSystem.constructStats.buffer[i];
|
||||
if (constructStat.id <= 0) continue;
|
||||
constructionSystem.RemoveConstructStat(constructStat.id);
|
||||
}
|
||||
}
|
||||
constructionModule.autoReconstructTargetTotalCount = 0;
|
||||
constructionModule.buildTargetTotalCount = 0;
|
||||
constructionModule.repairTargetTotalCount = 0;
|
||||
constructionModule.autoReconstructTargets = null;
|
||||
constructionModule.buildTargets = null;
|
||||
constructionModule.repairTargets = null;
|
||||
constructionModule.tmpTargets = null;
|
||||
constructionModule.tmpTargetsHash = null;
|
||||
constructionModule.checkItemCursor = 0;
|
||||
|
||||
var gameData = GameMain.data;
|
||||
|
||||
var returnBuildings = ReturnBuildingsOnInitializeEnabled.Value;
|
||||
var returnLogisticStorageItems = ReturnLogisticStorageItemsOnInitializeEnabled.Value;
|
||||
var returnBeltAFactoryItems = ReturnBeltAFactoryItemsOnInitializeEnabled.Value;
|
||||
var returnedItems = new Dictionary<int, (long count, int inc)>();
|
||||
|
||||
static void AddReturnedItem(int itemId, int count, int inc, Dictionary<int, (long count, int inc)> returnedItems)
|
||||
{
|
||||
if (returnedItems.TryGetValue(itemId, out var value))
|
||||
{
|
||||
returnedItems[itemId] = (value.count + count, value.inc + inc);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnedItems[itemId] = (count, inc);
|
||||
}
|
||||
}
|
||||
|
||||
if (returnBuildings || returnBeltAFactoryItems)
|
||||
{
|
||||
var factoryStorage = factory.factoryStorage;
|
||||
var factorySystem = factory.factorySystem;
|
||||
var planetTransport = factory.transport;
|
||||
var defenseSystem = factory.defenseSystem;
|
||||
var powerSystem = factory.powerSystem;
|
||||
var cargoTraffic = factory.cargoTraffic;
|
||||
for (var i = factory.entityCursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var ed = ref factory.entityPool[i];
|
||||
if (ed.id != i) continue;
|
||||
if (ed.protoId <= 0) continue;
|
||||
if (returnBuildings) AddReturnedItem(ed.protoId, 1, 0, returnedItems);
|
||||
if (!returnBeltAFactoryItems) continue;
|
||||
#region Storage Items
|
||||
var storageId = ed.storageId;
|
||||
if (storageId > 0)
|
||||
{
|
||||
var storage = factoryStorage.storagePool[storageId];
|
||||
if (storage != null)
|
||||
{
|
||||
for (var j = storage.size - 1; j >= 0; j--)
|
||||
{
|
||||
var count = storage.grids[j].count;
|
||||
if (count <= 0) continue;
|
||||
AddReturnedItem(storage.grids[j].itemId, count, storage.grids[j].inc, returnedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Tank Items
|
||||
var tankId = ed.tankId;
|
||||
if (tankId > 0)
|
||||
{
|
||||
ref var tank = ref factoryStorage.tankPool[tankId];
|
||||
var fluidId = tank.fluidId;
|
||||
var fluidCount = tank.fluidCount;
|
||||
if (fluidId > 0 && fluidCount > 0) AddReturnedItem(fluidId, fluidCount, tank.fluidInc, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Miner Items
|
||||
var minerId = ed.minerId;
|
||||
if (minerId > 0)
|
||||
{
|
||||
ref var miner = ref factorySystem.minerPool[minerId];
|
||||
var productId = miner.productId;
|
||||
var productCount = miner.productCount;
|
||||
if (productId > 0 && productCount > 0) AddReturnedItem(productId, productCount, 0, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Inserter Items
|
||||
var inserterId = ed.inserterId;
|
||||
if (inserterId > 0)
|
||||
{
|
||||
ref var inserter = ref factorySystem.inserterPool[inserterId];
|
||||
var itemId = inserter.itemId;
|
||||
var itemCount = inserter.itemCount;
|
||||
if (itemId > 0 && itemCount > 0) AddReturnedItem(itemId, itemCount, inserter.itemInc, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Assembler Items
|
||||
var assemblerId = ed.assemblerId;
|
||||
if (assemblerId > 0)
|
||||
{
|
||||
ref var assembler = ref factorySystem.assemblerPool[assemblerId];
|
||||
if (assembler.recipeId > 0)
|
||||
{
|
||||
var products = assembler.recipeExecuteData.products;
|
||||
var requires = assembler.recipeExecuteData.requires;
|
||||
var requireCounts = assembler.recipeExecuteData.requireCounts;
|
||||
for (var j = products.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var product = products[j];
|
||||
var produced = assembler.produced[j];
|
||||
if (produced > 0) AddReturnedItem(product, produced, 0, returnedItems);
|
||||
}
|
||||
for (var j = requires.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var require = requires[j];
|
||||
var served = assembler.served[j];
|
||||
var incServed = assembler.incServed[j];
|
||||
if (incServed > served * 10) incServed = served * 10;
|
||||
if (assembler.replicating) served += requireCounts[j];
|
||||
if (served > 0) AddReturnedItem(require, served, incServed, returnedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Fractionator Items
|
||||
var fractionatorId = ed.fractionatorId;
|
||||
if (fractionatorId > 0)
|
||||
{
|
||||
ref var fractionator = ref factorySystem.fractionatorPool[fractionatorId];
|
||||
var fluidId = fractionator.fluidId;
|
||||
var fluidInputCount = fractionator.fluidInputCount;
|
||||
if (fluidInputCount > 0) AddReturnedItem(fluidId, fluidInputCount, fractionator.fluidInputInc, returnedItems);
|
||||
var fluidOutputCount = fractionator.fluidOutputCount;
|
||||
if (fluidOutputCount > 0) AddReturnedItem(fluidId, fluidOutputCount, fractionator.fluidOutputInc, returnedItems);
|
||||
var productOutputCount = fractionator.productOutputCount;
|
||||
if (productOutputCount > 0) AddReturnedItem(fractionator.productId, productOutputCount, 0, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Ejector Items
|
||||
var ejectorId = ed.ejectorId;
|
||||
if (ejectorId > 0)
|
||||
{
|
||||
ref var ejector = ref factorySystem.ejectorPool[ejectorId];
|
||||
var bulletCount = ejector.bulletCount;
|
||||
if (bulletCount > 0) AddReturnedItem(ejector.bulletId, bulletCount, ejector.bulletInc, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Silo Items
|
||||
var siloId = ed.siloId;
|
||||
if (siloId > 0)
|
||||
{
|
||||
ref var silo = ref factorySystem.siloPool[siloId];
|
||||
var itemCount = silo.bulletCount;
|
||||
if (itemCount > 0) AddReturnedItem(silo.bulletId, itemCount, silo.bulletInc, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Lab Items
|
||||
var labId = ed.labId;
|
||||
if (labId > 0)
|
||||
{
|
||||
ref var lab = ref factorySystem.labPool[labId];
|
||||
if (lab.recipeId > 0)
|
||||
{
|
||||
var products = lab.recipeExecuteData.products;
|
||||
var requires = lab.recipeExecuteData.requires;
|
||||
var requireCounts = lab.recipeExecuteData.requireCounts;
|
||||
for (var j = products.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var produced = lab.produced[j];
|
||||
if (produced > 0) AddReturnedItem(products[j], produced, 0, returnedItems);
|
||||
}
|
||||
for (var j = requires.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var served = lab.served[j];
|
||||
var incServed = lab.incServed[j];
|
||||
if (incServed > served * 10) incServed = served * 10;
|
||||
if (lab.replicating) served += requireCounts[j];
|
||||
if (served > 0) AddReturnedItem(requires[j], served, incServed, returnedItems);
|
||||
}
|
||||
}
|
||||
if (lab.researchMode && lab.matrixServed != null)
|
||||
{
|
||||
for (var j = lab.matrixServed.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var served = lab.matrixServed[j] / 3600;
|
||||
if (served > 0) AddReturnedItem(LabComponent.matrixIds[j], served, lab.matrixIncServed[j] / 3600, returnedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Dispenser Items
|
||||
var dispenserId = ed.dispenserId;
|
||||
if (dispenserId > 0)
|
||||
{
|
||||
var dispenser = planetTransport.dispenserPool[dispenserId];
|
||||
var holdupPackage = dispenser.holdupPackage;
|
||||
for (var j = holdupPackage.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var count = holdupPackage[j].count;
|
||||
if (count > 0) AddReturnedItem(holdupPackage[j].itemId, count, holdupPackage[j].inc, returnedItems);
|
||||
}
|
||||
var courierCount = dispenser.idleCourierCount + dispenser.workCourierCount;
|
||||
if (courierCount > 0) AddReturnedItem((int)Common.KnownItemId.Bot, courierCount, 0, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Turret Items
|
||||
var turretId = ed.turretId;
|
||||
if (turretId > 0)
|
||||
{
|
||||
ref var turret = ref defenseSystem.turrets.buffer[turretId];
|
||||
var itemCount = turret.itemCount;
|
||||
if (itemCount > 0) AddReturnedItem(turret.itemId, itemCount, turret.itemInc, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Battle Base Items
|
||||
var battleBaseId = ed.battleBaseId;
|
||||
if (battleBaseId > 0)
|
||||
{
|
||||
ref var battleBase = ref defenseSystem.battleBases.buffer[battleBaseId];
|
||||
var combatModule = battleBase.combatModule;
|
||||
if (combatModule != null && combatModule.moduleFleets[0].fleetId <= 0)
|
||||
{
|
||||
var fighters = combatModule.moduleFleets[0].fighters;
|
||||
for (var j = fighters.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var fighterItemId = fighters[j].itemId;
|
||||
var fighterCount = fighters[j].count;
|
||||
if (fighterItemId > 0 && fighterCount > 0) AddReturnedItem(fighterItemId, fighterCount, 0, returnedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Power Generator Items
|
||||
var powerGeneratorId = ed.powerGenId;
|
||||
if (powerGeneratorId > 0)
|
||||
{
|
||||
ref var powerGen = ref powerSystem.genPool[powerGeneratorId];
|
||||
if (powerGen.fuelId > 0 && powerGen.fuelCount > 0) AddReturnedItem(powerGen.fuelId, powerGen.fuelCount, powerGen.fuelInc, returnedItems);
|
||||
if (powerGen.gamma)
|
||||
{
|
||||
var productId = powerGen.productId;
|
||||
var productCount = (int)powerGen.productCount;
|
||||
if (productId != 0 && productCount > 0) AddReturnedItem(productId, productCount, 0, returnedItems);
|
||||
int catalystId = powerGen.catalystId;
|
||||
var catalystPointDiv = powerGen.catalystPoint / 3600;
|
||||
if (catalystId != 0 && catalystPointDiv > 0) AddReturnedItem(catalystId, catalystPointDiv, powerGen.catalystIncPoint / 3600, returnedItems);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Power Exchanger Items
|
||||
var powerExchangerId = ed.powerExcId;
|
||||
if (powerExchangerId > 0)
|
||||
{
|
||||
ref var powerExchanger = ref powerSystem.excPool[powerExchangerId];
|
||||
var emptyCount = (int)powerExchanger.emptyCount;
|
||||
if (emptyCount > 0) AddReturnedItem(powerExchanger.emptyId, emptyCount, powerExchanger.emptyInc, returnedItems);
|
||||
var fullCount = (int)powerExchanger.fullCount;
|
||||
if (fullCount > 0) AddReturnedItem(powerExchanger.fullId, fullCount, powerExchanger.fullInc, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
#region Spraycoater Items
|
||||
var spraycoaterId = ed.spraycoaterId;
|
||||
if (spraycoaterId > 0)
|
||||
{
|
||||
ref var spraycoater = ref cargoTraffic.spraycoaterPool[spraycoaterId];
|
||||
if (spraycoater.incItemId != 0 && spraycoater.incCount != 0)
|
||||
{
|
||||
var itemProto = LDB.items.Select(spraycoater.incItemId);
|
||||
var count = spraycoater.incCount / itemProto.HpMax;
|
||||
if (count != 0) AddReturnedItem(spraycoater.incItemId, count, 0, returnedItems);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Piler Items
|
||||
var pilerId = ed.pilerId;
|
||||
if (pilerId > 0)
|
||||
{
|
||||
ref var piler = ref cargoTraffic.pilerPool[pilerId];
|
||||
var cacheCargoStack = (int)piler.cacheCargoStack1;
|
||||
if (cacheCargoStack > 0) AddReturnedItem(piler.cacheItemId1, cacheCargoStack, piler.cacheCargoInc1, returnedItems);
|
||||
var cacheCargoStack2 = (int)piler.cacheCargoStack2;
|
||||
if (cacheCargoStack2 > 0) AddReturnedItem(piler.cacheItemId2, cacheCargoStack2, piler.cacheCargoInc2, returnedItems);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
if (returnBeltAFactoryItems)
|
||||
{
|
||||
#region Belt Items
|
||||
for (var i = cargoTraffic.pathCursor - 1; i > 0; i--)
|
||||
{
|
||||
var cargoPath = cargoTraffic.pathPool[i];
|
||||
if (cargoPath == null) continue;
|
||||
var end = cargoPath.bufferLength - 5;
|
||||
var buffer = cargoPath.buffer;
|
||||
for (var j = 0; j <= end;)
|
||||
{
|
||||
if (buffer[j] >= 246)
|
||||
{
|
||||
var delta = 250 - buffer[j];
|
||||
if (delta > 0) j += delta;
|
||||
var bufferIndex = buffer[j + 1] - 1 + (buffer[j + 2] - 1) * 100 + (buffer[j + 3] - 1) * 10000 + (buffer[j + 4] - 1) * 1000000;
|
||||
ref var cargo = ref cargoPath.cargoContainer.cargoPool[bufferIndex];
|
||||
var stack = cargo.stack;
|
||||
if (stack > 0) AddReturnedItem(cargo.item, stack, cargo.inc, returnedItems);
|
||||
j += 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
j += 5;
|
||||
if (j > end && j < end + 5)
|
||||
{
|
||||
j = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
var stationPool = factory.transport?.stationPool;
|
||||
if (stationPool != null)
|
||||
{
|
||||
var galacticTransport = gameData.galacticTransport;
|
||||
for (var i = factory.transport.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
var sc = stationPool[i];
|
||||
if (sc == null || sc.id != i) continue;
|
||||
if (returnLogisticStorageItems)
|
||||
{
|
||||
for (var j = sc.storage.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var count = sc.storage[j].count;
|
||||
if (count > 0) AddReturnedItem(sc.storage[j].itemId, count, sc.storage[j].inc, returnedItems);
|
||||
}
|
||||
var droneCount = sc.idleDroneCount + sc.workDroneCount;
|
||||
if (droneCount > 0) AddReturnedItem((int)Common.KnownItemId.Drone, droneCount, 0, returnedItems);
|
||||
var shipCount = sc.idleShipCount + sc.workShipCount;
|
||||
if (shipCount > 0) AddReturnedItem((int)Common.KnownItemId.Ship, shipCount, 0, returnedItems);
|
||||
var warperCount = sc.warperCount;
|
||||
if (warperCount > 0) AddReturnedItem((int)Common.KnownItemId.Warper, warperCount, 0, returnedItems);
|
||||
}
|
||||
var gid = sc.gid;
|
||||
if (galacticTransport.stationPool[gid] != null)
|
||||
{
|
||||
galacticTransport.stationPool[gid] = null;
|
||||
int cursor = galacticTransport.stationRecycleCursor;
|
||||
galacticTransport.stationRecycleCursor = cursor + 1;
|
||||
galacticTransport.stationRecycle[cursor] = gid;
|
||||
}
|
||||
galacticTransport.RemoveStation2StationRoute(gid);
|
||||
galacticTransport.RefreshTraffic(gid);
|
||||
sc.Reset();
|
||||
}
|
||||
if (galacticTransport.OnStellarStationRemoved != null)
|
||||
{
|
||||
galacticTransport.OnStellarStationRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
var physics = planet.physics;
|
||||
var gpuiManager = GameMain.gpuiManager;
|
||||
var blockContainer = factory.blockContainer;
|
||||
var audio = planet.audio;
|
||||
for (var id = factory.entityCursor - 1; id > 0; id--)
|
||||
{
|
||||
ref var ed = ref factory.entityPool[id];
|
||||
if (ed.id != id) continue;
|
||||
|
||||
factory.BeforeDismantleObject(id);
|
||||
|
||||
if (ed.colliderId != 0)
|
||||
{
|
||||
planet.physics.RemoveLinkedColliderData(ed.colliderId);
|
||||
planet.physics.NotifyObjectRemove(EObjectType.Entity, ed.id);
|
||||
physics.RemoveLinkedColliderData(ed.colliderId);
|
||||
physics.NotifyObjectRemove(EObjectType.Entity, ed.id);
|
||||
}
|
||||
|
||||
if (ed.modelId != 0)
|
||||
{
|
||||
GameMain.gpuiManager.RemoveModel(ed.modelIndex, ed.modelId);
|
||||
gpuiManager.RemoveModel(ed.modelIndex, ed.modelId);
|
||||
}
|
||||
|
||||
if (ed.mmblockId != 0)
|
||||
{
|
||||
factory.blockContainer.RemoveMiniBlock(ed.mmblockId);
|
||||
blockContainer.RemoveMiniBlock(ed.mmblockId);
|
||||
}
|
||||
|
||||
if (ed.audioId == 0) continue;
|
||||
planet.audio?.RemoveAudioData(ed.audioId);
|
||||
if (ed.audioId != 0)
|
||||
{
|
||||
audio.RemoveAudioData(ed.audioId);
|
||||
}
|
||||
|
||||
factory.OnDismantleObject(id);
|
||||
}
|
||||
|
||||
for (var id = factory.prebuildCursor - 1; id > 0; id--)
|
||||
{
|
||||
ref var pb = ref factory.prebuildPool[id];
|
||||
if (pb.id != id) continue;
|
||||
if (pb.colliderId != 0)
|
||||
{
|
||||
physics.RemoveLinkedColliderData(pb.colliderId);
|
||||
}
|
||||
if (pb.modelId != 0)
|
||||
{
|
||||
gpuiManager.RemovePrebuildModel(pb.modelIndex, pb.modelId);
|
||||
}
|
||||
}
|
||||
|
||||
var hives = GameMain.spaceSector?.dfHives;
|
||||
@@ -115,34 +539,21 @@ public static class PlanetFunctions
|
||||
}
|
||||
}
|
||||
|
||||
if (planet.factory.enemyPool != null)
|
||||
if (factory.enemyPool != null)
|
||||
{
|
||||
for (var i = planet.factory.enemyCursor - 1; i > 0; i--)
|
||||
for (var i = factory.enemyCursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var enemyData = ref planet.factory.enemyPool[i];
|
||||
ref var enemyData = ref factory.enemyPool[i];
|
||||
if (enemyData.id != i) continue;
|
||||
var combatStatId = enemyData.combatStatId;
|
||||
planet.factory.skillSystem.OnRemovingSkillTarget(combatStatId, planet.factory.skillSystem.combatStats.buffer[combatStatId].originAstroId, ETargetType.CombatStat);
|
||||
planet.factory.skillSystem.combatStats.Remove(combatStatId);
|
||||
planet.factory.KillEnemyFinally(i, ref CombatStat.empty);
|
||||
factory.skillSystem.OnRemovingSkillTarget(combatStatId, factory.skillSystem.combatStats.buffer[combatStatId].originAstroId, ETargetType.CombatStat);
|
||||
factory.skillSystem.combatStats.Remove(combatStatId);
|
||||
factory.KillEnemyFinally(i, ref CombatStat.empty);
|
||||
}
|
||||
planet.factory.enemySystem.Free();
|
||||
factory.enemySystem.Free();
|
||||
UIRoot.instance.uiGame.dfAssaultTip.ClearAllSpots();
|
||||
}
|
||||
|
||||
var stationPool = factory.transport?.stationPool;
|
||||
if (stationPool != null)
|
||||
{
|
||||
foreach (var sc in stationPool)
|
||||
{
|
||||
if (sc is not { id: > 0 }) continue;
|
||||
sc.storage = new StationStore[sc.storage.Length];
|
||||
sc.needs = new int[sc.needs.Length];
|
||||
int protoId = factory.entityPool[sc.entityId].protoId;
|
||||
factory.DismantleFinally(player, sc.entityId, ref protoId);
|
||||
}
|
||||
}
|
||||
|
||||
var planetId = planet.id;
|
||||
var gameScenario = GameMain.gameScenario;
|
||||
if (gameScenario != null)
|
||||
@@ -167,7 +578,7 @@ public static class PlanetFunctions
|
||||
|
||||
planet.UnloadFactory();
|
||||
var index = factory.index;
|
||||
var warningSystem = GameMain.data.warningSystem;
|
||||
var warningSystem = gameData.warningSystem;
|
||||
var warningPool = warningSystem.warningPool;
|
||||
for (var i = warningSystem.warningCursor - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -212,6 +623,19 @@ public static class PlanetFunctions
|
||||
factory.factoryStorage = new FactoryStorage(planet);
|
||||
factory.powerSystem = new PowerSystem(planet);
|
||||
factory.constructionSystem = new ConstructionSystem(planet);
|
||||
if (factory.veinPool != null)
|
||||
{
|
||||
for (var i = factory.veinPool.Length - 1; i >= 0; i--)
|
||||
{
|
||||
ref var vein = ref factory.veinPool[i];
|
||||
if (vein.id != i) continue;
|
||||
vein.minerCount = 0;
|
||||
vein.minerId0 = 0;
|
||||
vein.minerId1 = 0;
|
||||
vein.minerId2 = 0;
|
||||
vein.minerId3 = 0;
|
||||
}
|
||||
}
|
||||
factory.InitVeinHashAddress();
|
||||
factory.RecalculateAllVeinGroups();
|
||||
factory.InitVegeHashAddress();
|
||||
@@ -224,8 +648,9 @@ public static class PlanetFunctions
|
||||
factory.combatGroundSystem = new CombatGroundSystem(planet);
|
||||
factory.defenseSystem = new DefenseSystem(planet);
|
||||
factory.planetATField = new PlanetATField(planet);
|
||||
factory.transport = new PlanetTransport(GameMain.data, planet);
|
||||
factory.transport = new PlanetTransport(gameData, planet);
|
||||
factory.transport.Init();
|
||||
factory.RefreshHashSystems();
|
||||
var mem = new MemoryStream();
|
||||
var writer = new BinaryWriter(mem);
|
||||
factory.platformSystem.Export(writer);
|
||||
@@ -242,7 +667,13 @@ public static class PlanetFunctions
|
||||
while (!planet.factoryLoaded)
|
||||
{
|
||||
PlanetModelingManager.Update();
|
||||
Thread.Sleep(0);
|
||||
System.Threading.Thread.Sleep(0);
|
||||
}
|
||||
|
||||
foreach (var kvp in returnedItems)
|
||||
{
|
||||
var added = player.TryAddItemToPackage(kvp.Key, (int)kvp.Value.count, kvp.Value.inc, true);
|
||||
if (added > 0) UIItemup.Up(kvp.Key, added);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +692,7 @@ public static class PlanetFunctions
|
||||
var entityPool = factory.entityPool;
|
||||
var pos = new Vector3(0f, 0f, planet.realRadius * 1.025f + 0.2f);
|
||||
var found = false;
|
||||
for (var i = 1; i < stationCursor; i++)
|
||||
for (var i = stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
if (stationPool[i] == null || stationPool[i].id != i) continue;
|
||||
ref var entity = ref entityPool[stationPool[i].entityId];
|
||||
@@ -273,7 +704,7 @@ public static class PlanetFunctions
|
||||
var prebuildPool = factory.prebuildPool;
|
||||
if (!found)
|
||||
{
|
||||
for (var i = 1; i < prebuildCursor; i++)
|
||||
for (var i = prebuildCursor - 1; i > 0; i--)
|
||||
{
|
||||
if (prebuildPool[i].id != i) continue;
|
||||
pos = prebuildPool[i].pos;
|
||||
@@ -296,7 +727,7 @@ public static class PlanetFunctions
|
||||
{
|
||||
/* Check for collision */
|
||||
var collide = false;
|
||||
for (var j = 1; j < stationCursor; j++)
|
||||
for (var j = stationCursor - 1; j > 0; j--)
|
||||
{
|
||||
if (stationPool[j] == null || stationPool[j].id != j) continue;
|
||||
if ((entityPool[stationPool[j].entityId].pos - pos).sqrMagnitude >= 14297f) continue;
|
||||
|
||||
@@ -14,33 +14,11 @@ public static class TechFunctions
|
||||
I18N.Add("Batch buyout tech", "Batch buyout tech", "批量买断科技");
|
||||
}
|
||||
|
||||
public static void GenerateTechListWithPrerequisites(GameHistoryData history, int techId, List<int> techIdList)
|
||||
private static void CheckTechUnlockProperties(GameHistoryData history, TechProto techProto, SortedList<int, int> properties, List<Tuple<TechProto, int, int>> techList, int maxLevel = 10000, bool withPrerequisites = true, HashSet<int> seenTechs = null)
|
||||
{
|
||||
var techProto = LDB.techs.Select(techId);
|
||||
if (techProto == null || !techProto.Published) return;
|
||||
var flag = true;
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
foreach (var preTechId in (i == 1 ? techProto.PreTechsImplicit : techProto.PreTechs))
|
||||
{
|
||||
if (!history.techStates.ContainsKey(preTechId) || history.techStates[preTechId].unlocked) continue;
|
||||
if (history.techStates[preTechId].maxLevel > history.techStates[preTechId].curLevel)
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
GenerateTechListWithPrerequisites(history, preTechId, techIdList);
|
||||
}
|
||||
}
|
||||
if (history.techStates.ContainsKey(techId) && !history.techStates[techId].unlocked && flag)
|
||||
{
|
||||
techIdList.Add(techId);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckTechUnlockProperties(GameHistoryData history, TechProto techProto, SortedList<int, int> properties, List<Tuple<TechProto, int, int>> techList, int maxLevel = 10000, bool withPrerequisites = true)
|
||||
{
|
||||
var techStates = history.techStates;
|
||||
var techID = techProto.ID;
|
||||
if (seenTechs!.Contains(techID)) return;
|
||||
var techStates = history.techStates;
|
||||
if (techStates == null || !techStates.TryGetValue(techID, out var value)) return;
|
||||
if (value.unlocked) return;
|
||||
|
||||
@@ -51,18 +29,19 @@ public static class TechFunctions
|
||||
{
|
||||
var preProto = LDB.techs.Select(preid);
|
||||
if (preProto != null)
|
||||
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level, true);
|
||||
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level, true, seenTechs);
|
||||
}
|
||||
foreach (var preid in techProto.PreTechsImplicit)
|
||||
{
|
||||
var preProto = LDB.techs.Select(preid);
|
||||
if (preProto != null)
|
||||
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level, true);
|
||||
CheckTechUnlockProperties(history, preProto, properties, techList, techProto.PreTechsMax ? 10000 : preProto.Level, true, seenTechs);
|
||||
}
|
||||
}
|
||||
|
||||
if (value.curLevel < techProto.Level) value.curLevel = techProto.Level;
|
||||
techList.Add(new Tuple<TechProto, int, int>(techProto, value.curLevel, techProto.Level));
|
||||
seenTechs!.Add(techID);
|
||||
while (value.curLevel <= maxLvl)
|
||||
{
|
||||
if (techProto.PropertyOverrideItemArray != null)
|
||||
@@ -184,7 +163,7 @@ public static class TechFunctions
|
||||
techProtos.Add(techProto);
|
||||
}
|
||||
}
|
||||
UnlockProtoWithMetadataAndPrompt([.. techProtos], 16, false);
|
||||
UnlockProtoWithMetadataAndPrompt([.. techProtos], 16, true);
|
||||
}
|
||||
|
||||
public static void UnlockProtoWithMetadataAndPrompt(TechProto[] techProtos, int toLevel, bool withPrerequisites = true)
|
||||
@@ -192,9 +171,10 @@ public static class TechFunctions
|
||||
var techList = new List<Tuple<TechProto, int, int>>();
|
||||
var properties = new SortedList<int, int>();
|
||||
var history = GameMain.history;
|
||||
var seenTechs = new HashSet<int>();
|
||||
foreach (var techProto in techProtos)
|
||||
{
|
||||
CheckTechUnlockProperties(history, techProto, properties, techList, toLevel, withPrerequisites);
|
||||
CheckTechUnlockProperties(history, techProto, properties, techList, toLevel, withPrerequisites, seenTechs);
|
||||
}
|
||||
var propertySystem = DSPGame.propertySystem;
|
||||
var clusterSeedKey = history.gameData.GetClusterSeedKey();
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using CommonAPI.Systems;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UXAssist.UI;
|
||||
using CommonAPI.Systems;
|
||||
using UXAssist.Common;
|
||||
using UXAssist.UI;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
|
||||
namespace UXAssist.Functions;
|
||||
@@ -31,6 +33,9 @@ public static class UIFunctions
|
||||
|
||||
I18N.Add("Enable auto-cruise", "Enable auto-cruise", "启用自动巡航");
|
||||
I18N.Add("Disable auto-cruise", "Disable auto-cruise", "禁用自动巡航");
|
||||
I18N.Add("Enable auto-construct", "Enable auto-construct", "启用自动建造");
|
||||
I18N.Add("Disable auto-construct", "Disable auto-construct", "禁用自动建造");
|
||||
I18N.Add("Buildings to construct: {0}", "Buildings to construct: {0}", "待建造数量: {0}");
|
||||
I18N.Add("High yield", "High yield", "高产");
|
||||
I18N.Add("Perfect", "Perfect", "完美");
|
||||
I18N.Add("Union results", "Union results", "结果取并集");
|
||||
@@ -39,6 +44,11 @@ public static class UIFunctions
|
||||
I18N.Add("Show distance", "Show distance", "显示距离");
|
||||
I18N.Add("Show planet count", "Show planet count", "显示行星数");
|
||||
I18N.Add("Show all information", "Show all information", "显示全部信息");
|
||||
I18N.Add("No recent milkyway upload results", "No recent milkyway upload results", "没有最近的银河系发电数据上传结果");
|
||||
I18N.Add("Success", "Success", "成功");
|
||||
I18N.Add("Failure: ", "Failure: ", "失败: ");
|
||||
I18N.Add("Show top players", "Show top players", "显示玩家排行榜");
|
||||
I18N.Add("Hide top players", "Hide top players", "隐藏玩家排行榜");
|
||||
I18N.OnInitialized += RecreateConfigWindow;
|
||||
}
|
||||
|
||||
@@ -129,6 +139,7 @@ public static class UIFunctions
|
||||
}
|
||||
}
|
||||
InitToggleAutoCruiseCheckButton();
|
||||
InitToggleAutoConstructCheckButton();
|
||||
InitStarmapButtons();
|
||||
_initialized = true;
|
||||
}
|
||||
@@ -164,15 +175,17 @@ public static class UIFunctions
|
||||
public static void InitToggleAutoCruiseCheckButton()
|
||||
{
|
||||
var lowGroup = GameObject.Find("UI Root/Overlay Canvas/In Game/Low Group");
|
||||
ToggleAutoCruise = MyCheckButton.CreateCheckButton(0, 0, lowGroup.GetComponent<RectTransform>(), Patches.PlayerPatch.AutoCruiseEnabled).WithSize(120f, 40f);
|
||||
UpdateToggleAutoCruiseCheckButtonVisiblility();
|
||||
ToggleAutoCruiseChecked();
|
||||
ToggleAutoCruise.OnChecked += ToggleAutoCruiseChecked;
|
||||
ToggleAutoCruise = MyCheckButton.CreateCheckButton(0, 0, lowGroup.GetComponent<RectTransform>(), Patches.PlayerPatch.AutoCruiseEnabled).WithSize(160f, 40f);
|
||||
var rectTrans = ToggleAutoCruise.rectTrans;
|
||||
rectTrans.anchorMax = new Vector2(0.5f, 0f);
|
||||
rectTrans.anchorMin = new Vector2(0.5f, 0f);
|
||||
rectTrans.pivot = new Vector2(0.5f, 0f);
|
||||
rectTrans.anchoredPosition3D = new Vector3(0f, 185f, 0f);
|
||||
rectTrans.localScale = new Vector3(1f, 1f, 1f);
|
||||
|
||||
UpdateToggleAutoCruiseCheckButtonVisiblility();
|
||||
ToggleAutoCruiseChecked();
|
||||
ToggleAutoCruise.OnChecked += ToggleAutoCruiseChecked;
|
||||
static void ToggleAutoCruiseChecked()
|
||||
{
|
||||
if (ToggleAutoCruise.Checked)
|
||||
@@ -194,6 +207,82 @@ public static class UIFunctions
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ToggleAutoConstructCheckButton
|
||||
public static UI.MyCheckButton ToggleAutoConstruct;
|
||||
public static GameObject ConstructCountPanel;
|
||||
public static Text ConstructCountText;
|
||||
|
||||
public static void InitToggleAutoConstructCheckButton()
|
||||
{
|
||||
var lowGroup = GameObject.Find("UI Root/Overlay Canvas/In Game/Low Group");
|
||||
var parent = lowGroup.GetComponent<RectTransform>();
|
||||
ToggleAutoConstruct = MyCheckButton.CreateCheckButton(0, 0, parent, Patches.FactoryPatch.AutoConstructEnabled).WithSize(160f, 40f);
|
||||
var rectTrans = ToggleAutoConstruct.rectTrans;
|
||||
rectTrans.anchorMax = new Vector2(0.5f, 0f);
|
||||
rectTrans.anchorMin = new Vector2(0.5f, 0f);
|
||||
rectTrans.pivot = new Vector2(0.5f, 0f);
|
||||
rectTrans.anchoredPosition3D = new Vector3(-165f, 185f, 0f);
|
||||
rectTrans.localScale = new Vector3(1f, 1f, 1f);
|
||||
|
||||
ConstructCountPanel = new GameObject("uxassist-construct-count-panel");
|
||||
rectTrans = ConstructCountPanel.AddComponent<RectTransform>();
|
||||
rectTrans.SetParent(parent);
|
||||
rectTrans.anchorMax = new Vector2(0.5f, 0f);
|
||||
rectTrans.anchorMin = new Vector2(0.5f, 0f);
|
||||
rectTrans.pivot = new Vector2(0.5f, 0f);
|
||||
rectTrans.anchoredPosition3D = new Vector3(-165f, 161f, 0f);
|
||||
rectTrans.localScale = new Vector3(1f, 1f, 1f);
|
||||
rectTrans.sizeDelta = new Vector2(160f, 24f);
|
||||
var bg = ConstructCountPanel.AddComponent<Image>();
|
||||
bg.color = new Color(0.2f, 0.2f, 0.2f, 0.6f);
|
||||
|
||||
ConstructCountText = GameObject.Instantiate(UIRoot.instance.uiGame.assemblerWindow.stateText);
|
||||
ConstructCountText.gameObject.name = "construct-count-text";
|
||||
ConstructCountText.text = String.Format("Buildings to construct: {0}".Translate(), 0);
|
||||
ConstructCountText.color = new Color(1f, 1f, 1f, 0.4f);
|
||||
ConstructCountText.alignment = TextAnchor.MiddleLeft;
|
||||
ConstructCountText.fontSize = 16;
|
||||
rectTrans = ConstructCountText.rectTransform;
|
||||
rectTrans.SetParent(ConstructCountPanel.transform);
|
||||
rectTrans.sizeDelta = new Vector2(150f, 20f);
|
||||
rectTrans.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
rectTrans.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
rectTrans.pivot = new Vector2(0.5f, 0.5f);
|
||||
rectTrans.anchoredPosition3D = new Vector3(0f, 0f, 0f);
|
||||
rectTrans.localScale = new Vector3(1f, 1f, 1f);
|
||||
|
||||
UpdateToggleAutoConstructCheckButtonVisiblility();
|
||||
ToggleAutoConstructChecked();
|
||||
ToggleAutoConstruct.OnChecked += ToggleAutoConstructChecked;
|
||||
static void ToggleAutoConstructChecked()
|
||||
{
|
||||
if (ToggleAutoConstruct.Checked)
|
||||
{
|
||||
ToggleAutoConstruct.SetLabelText("Disable auto-construct");
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleAutoConstruct.SetLabelText("Enable auto-construct");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateToggleAutoConstructCheckButtonVisiblility()
|
||||
{
|
||||
if (ToggleAutoConstruct == null) return;
|
||||
var localPlanet = GameMain.localPlanet;
|
||||
var active = localPlanet != null && localPlanet.factoryLoaded && localPlanet.factory.prebuildCount > 0 && Patches.FactoryPatch.AutoConstructButtonEnabled.Value;
|
||||
ToggleAutoConstruct.gameObject.SetActive(active);
|
||||
ConstructCountPanel.gameObject.SetActive(active);
|
||||
}
|
||||
|
||||
public static void UpdateConstructCountText(int count)
|
||||
{
|
||||
if (ConstructCountText == null) return;
|
||||
ConstructCountText.text = String.Format("Buildings to construct: {0}".Translate(), count);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region StarMapButtons
|
||||
private static int _cornerComboBoxIndex;
|
||||
private static string[] _starOrderNames;
|
||||
@@ -719,4 +808,297 @@ public static class UIFunctions
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MilkyWayClusterUploadResult
|
||||
|
||||
const int ClusterUploadResultKeepCount = 100;
|
||||
private static readonly ClusterUploadResult[] _clusterUploadResults = new ClusterUploadResult[ClusterUploadResultKeepCount];
|
||||
private static readonly object _clusterUploadResultsLock = new();
|
||||
private static int _clusterUploadResultsHead = 0;
|
||||
private static int _clusterUploadResultsCount = 0;
|
||||
|
||||
private struct ClusterUploadResult
|
||||
{
|
||||
public DateTime UploadTime;
|
||||
public int Result;
|
||||
public float RequestTime;
|
||||
}
|
||||
|
||||
public static void AddClusterUploadResult(int result, float requestTime)
|
||||
{
|
||||
lock (_clusterUploadResultsLock)
|
||||
{
|
||||
if (_clusterUploadResultsCount >= ClusterUploadResultKeepCount)
|
||||
{
|
||||
_clusterUploadResults[_clusterUploadResultsHead] = new ClusterUploadResult { UploadTime = DateTime.Now, Result = result, RequestTime = requestTime };
|
||||
_clusterUploadResultsHead = (_clusterUploadResultsHead + 1) % ClusterUploadResultKeepCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
_clusterUploadResults[(_clusterUploadResultsHead + _clusterUploadResultsCount) % ClusterUploadResultKeepCount] = new ClusterUploadResult { UploadTime = DateTime.Now, Result = result, RequestTime = requestTime };
|
||||
_clusterUploadResultsCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExportClusterUploadResults(BinaryWriter w)
|
||||
{
|
||||
lock (_clusterUploadResultsLock)
|
||||
{
|
||||
w.Write(_clusterUploadResultsCount);
|
||||
w.Write(_clusterUploadResultsHead);
|
||||
for (var i = 0; i < _clusterUploadResultsCount; i++)
|
||||
{
|
||||
ref var result = ref _clusterUploadResults[(i + _clusterUploadResultsHead) % ClusterUploadResultKeepCount];
|
||||
w.Write(result.UploadTime.ToBinary());
|
||||
w.Write(result.Result);
|
||||
w.Write(result.RequestTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ImportClusterUploadResults(BinaryReader r)
|
||||
{
|
||||
lock (_clusterUploadResultsLock)
|
||||
{
|
||||
_clusterUploadResultsCount = r.ReadInt32();
|
||||
_clusterUploadResultsHead = r.ReadInt32();
|
||||
for (var i = 0; i < _clusterUploadResultsCount; i++)
|
||||
{
|
||||
ref var result = ref _clusterUploadResults[(i + _clusterUploadResultsHead) % ClusterUploadResultKeepCount];
|
||||
result.UploadTime = DateTime.FromBinary(r.ReadInt64());
|
||||
result.Result = r.ReadInt32();
|
||||
result.RequestTime = r.ReadSingle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearClusterUploadResults()
|
||||
{
|
||||
lock (_clusterUploadResultsLock)
|
||||
{
|
||||
_clusterUploadResultsCount = 0;
|
||||
_clusterUploadResultsHead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowRecentMilkywayUploadResults()
|
||||
{
|
||||
lock (_clusterUploadResultsLock)
|
||||
{
|
||||
if (_clusterUploadResultsCount == 0)
|
||||
{
|
||||
UIMessageBox.Show("UXAssist".Translate(), "No recent milkyway upload results".Translate(), "确定".Translate(), UIMessageBox.INFO, null);
|
||||
return;
|
||||
}
|
||||
StringBuilder sb = new();
|
||||
var start = _clusterUploadResultsCount;
|
||||
var end = start > 10 ? start - 10 : 0;
|
||||
for (var i = start - 1; i >= end; i--)
|
||||
{
|
||||
var res = _clusterUploadResults[(i + _clusterUploadResultsHead) % ClusterUploadResultKeepCount];
|
||||
sb.AppendLine($"{res.UploadTime.ToString("yyyy-MM-dd HH:mm:ss")} - {((res.Result is 0 or 20) ? "Success".Translate() : ("Failure: ".Translate() + res.Result.ToString()))} - {res.RequestTime:F2}s");
|
||||
}
|
||||
UIMessageBox.Show("UXAssist".Translate(), sb.ToString(), "确定".Translate(), UIMessageBox.INFO, null);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MilkyWayTopTenPlayers
|
||||
private static ClusterPlayerData[] _topTenPlayerData = null;
|
||||
private static readonly StringBuilder _sb = new(" ", 12);
|
||||
|
||||
public static UI.MyCheckButton MilkyWayTopTenPlayersToggler;
|
||||
public static event Action OnMilkyWayTopTenPlayersUpdated;
|
||||
|
||||
public static void SetTopPlayerCount(int count)
|
||||
{
|
||||
_topTenPlayerData = new ClusterPlayerData[count];
|
||||
}
|
||||
|
||||
public static void SetTopPlayerData(int index, ref ClusterPlayerData playerData)
|
||||
{
|
||||
if (index < 0 || index >= _topTenPlayerData.Length) return;
|
||||
_topTenPlayerData[index] = playerData;
|
||||
}
|
||||
|
||||
public static void UpdateMilkyWayTopTenPlayers()
|
||||
{
|
||||
if (_topTenPlayerData == null) return;
|
||||
OnMilkyWayTopTenPlayersUpdated?.Invoke();
|
||||
}
|
||||
|
||||
public static void InitMilkyWayTopTenPlayers()
|
||||
{
|
||||
var uiRoot = UIRoot.instance;
|
||||
if (!uiRoot) return;
|
||||
|
||||
var rect = uiRoot.uiMilkyWay.transform as RectTransform;
|
||||
var panel = new GameObject("uxassist-milkyway-top-ten-players-panel");
|
||||
var rtrans = panel.AddComponent<RectTransform>();
|
||||
rtrans.SetParent(rect);
|
||||
rtrans.sizeDelta = new Vector2(0f, 0f);
|
||||
rtrans.localScale = new Vector3(1f, 1f, 1f);
|
||||
rtrans.anchorMax = new Vector2(1f, 1f);
|
||||
rtrans.anchorMin = new Vector2(0f, 0f);
|
||||
rtrans.pivot = new Vector2(0f, 1f);
|
||||
rtrans.anchoredPosition3D = new Vector3(0, 0, 0f);
|
||||
|
||||
MyFlatButton[] buttons = [];
|
||||
Text[] textFields = [];
|
||||
|
||||
MilkyWayTopTenPlayersToggler = UI.MyCheckButton.CreateCheckButton(0, 0, rtrans, false, "Show top players".Translate()).WithSize(120f, 24f);
|
||||
MilkyWayTopTenPlayersToggler.OnChecked += UpdateButtons;
|
||||
MilkyWayTopTenPlayersToggler.Checked = false;
|
||||
UpdateButtons();
|
||||
OnMilkyWayTopTenPlayersUpdated += UpdateButtons;
|
||||
|
||||
Text CreateTextField(RectTransform parent)
|
||||
{
|
||||
var txt = UnityEngine.Object.Instantiate(UIRoot.instance.uiGame.assemblerWindow.stateText, parent);
|
||||
txt.gameObject.name = "uxassist-milkyway-top-ten-players-text-field";
|
||||
txt.text = "";
|
||||
txt.color = new Color(1f, 1f, 1f, 0.4f);
|
||||
txt.alignment = TextAnchor.MiddleLeft;
|
||||
txt.fontSize = 15;
|
||||
txt.rectTransform.sizeDelta = new Vector2(0, 18);
|
||||
return txt;
|
||||
}
|
||||
|
||||
void UpdateButtons()
|
||||
{
|
||||
var chk = MilkyWayTopTenPlayersToggler.Checked;
|
||||
if (_topTenPlayerData == null)
|
||||
{
|
||||
MilkyWayTopTenPlayersToggler.gameObject.SetActive(false);
|
||||
return;
|
||||
}
|
||||
var count = _topTenPlayerData.Length;
|
||||
MilkyWayTopTenPlayersToggler.gameObject.SetActive(count > 0);
|
||||
if (count != buttons.Length)
|
||||
{
|
||||
for (var i = count; i < buttons.Length; i++)
|
||||
{
|
||||
UnityEngine.Object.Destroy(buttons[i].gameObject);
|
||||
UnityEngine.Object.Destroy(textFields[i * 4].gameObject);
|
||||
UnityEngine.Object.Destroy(textFields[i * 4 + 1].gameObject);
|
||||
UnityEngine.Object.Destroy(textFields[i * 4 + 2].gameObject);
|
||||
UnityEngine.Object.Destroy(textFields[i * 4 + 3].gameObject);
|
||||
}
|
||||
Array.Resize(ref buttons, count);
|
||||
Array.Resize(ref textFields, count * 4);
|
||||
}
|
||||
float maxWidth0 = 0f;
|
||||
float maxWidth1 = 0f;
|
||||
float maxWidth2 = 0f;
|
||||
float maxWidth3 = 0f;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var button = buttons[i];
|
||||
if (chk)
|
||||
{
|
||||
if (button == null)
|
||||
{
|
||||
button = MyFlatButton.CreateFlatButton(0f, 20f * i + 24f, rtrans, "").WithSize(20f, 18f);
|
||||
buttons[i] = button;
|
||||
button.uiButton.data = i;
|
||||
button.uiButton.onClick += data =>
|
||||
{
|
||||
if (data < 0 || data >= _topTenPlayerData.Length) return;
|
||||
ref var playerData = ref _topTenPlayerData[data];
|
||||
var seed = playerData.seedKey;
|
||||
int combatValue = (int)(seed % 1000L);
|
||||
int resourceMultiplier = (int)(seed / 1000L % 100L);
|
||||
int starCount = (int)(seed / 100000L % 1000L);
|
||||
int gameSeed = (int)(seed / 100000000L);
|
||||
var uiMilkyWaySearchPanel = UIRoot.instance.uiMilkyWay.uiSearchPanel;
|
||||
uiMilkyWaySearchPanel.selectSeed = gameSeed;
|
||||
uiMilkyWaySearchPanel.selectStarCnt = starCount;
|
||||
uiMilkyWaySearchPanel.selectResMulti = resourceMultiplier;
|
||||
if (combatValue / 100 > 0)
|
||||
{
|
||||
uiMilkyWaySearchPanel.selectMode = 1;
|
||||
uiMilkyWaySearchPanel.selectCombatDiff = combatValue % 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
uiMilkyWaySearchPanel.selectMode = 0;
|
||||
uiMilkyWaySearchPanel.selectCombatDiff = 0;
|
||||
}
|
||||
uiMilkyWaySearchPanel.RefreshInputText();
|
||||
uiMilkyWaySearchPanel.OnSearchButtonClick(0);
|
||||
};
|
||||
textFields[i * 4] = CreateTextField(rtrans);
|
||||
textFields[i * 4].alignment = TextAnchor.MiddleRight;
|
||||
textFields[i * 4 + 1] = CreateTextField(rtrans);
|
||||
textFields[i * 4 + 2] = CreateTextField(rtrans);
|
||||
textFields[i * 4 + 3] = CreateTextField(rtrans);
|
||||
textFields[i * 4 + 3].alignment = TextAnchor.MiddleRight;
|
||||
}
|
||||
button.SetLabelText(">>");
|
||||
textFields[i * 4].text = (i + 1).ToString();
|
||||
textFields[i * 4 + 1].text = _topTenPlayerData[i].name;
|
||||
textFields[i * 4 + 2].text = SeedToString(_topTenPlayerData[i].seedKey);
|
||||
textFields[i * 4 + 3].text = String.Format("{0}W", ToKMG(_topTenPlayerData[i].genCap * 60L));
|
||||
maxWidth0 = Math.Max(maxWidth0, textFields[i * 4].preferredWidth);
|
||||
maxWidth1 = Math.Max(maxWidth1, textFields[i * 4 + 1].preferredWidth);
|
||||
maxWidth2 = Math.Max(maxWidth2, textFields[i * 4 + 2].preferredWidth);
|
||||
maxWidth3 = Math.Max(maxWidth3, textFields[i * 4 + 3].preferredWidth);
|
||||
button.gameObject.SetActive(true);
|
||||
textFields[i * 4].gameObject.SetActive(true);
|
||||
textFields[i * 4 + 1].gameObject.SetActive(true);
|
||||
textFields[i * 4 + 2].gameObject.SetActive(true);
|
||||
textFields[i * 4 + 3].gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
button.gameObject.SetActive(false);
|
||||
textFields[i * 4].gameObject.SetActive(false);
|
||||
textFields[i * 4 + 1].gameObject.SetActive(false);
|
||||
textFields[i * 4 + 2].gameObject.SetActive(false);
|
||||
textFields[i * 4 + 3].gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chk)
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var y = 20f * i + 24f;
|
||||
UI.Util.NormalizeRectWithTopLeft(textFields[i * 4].rectTransform, 24f + maxWidth0 + 5f, y);
|
||||
UI.Util.NormalizeRectWithTopLeft(textFields[i * 4 + 1].rectTransform, 24f + maxWidth0 + 10f, y);
|
||||
UI.Util.NormalizeRectWithTopLeft(textFields[i * 4 + 2].rectTransform, 24f + maxWidth0 + 10f + maxWidth1 + 5f, y);
|
||||
UI.Util.NormalizeRectWithTopLeft(textFields[i * 4 + 3].rectTransform, 24f + maxWidth0 + 10f + maxWidth1 + 5f + maxWidth2 + 5f + maxWidth3, y);
|
||||
}
|
||||
}
|
||||
MilkyWayTopTenPlayersToggler.SetLabelText(chk ? "Hide top players".Translate() : "Show top players".Translate());
|
||||
|
||||
string ToKMG(long value)
|
||||
{
|
||||
StringBuilderUtility.WriteKMG(_sb, 8, value, true);
|
||||
return _sb.ToString();
|
||||
}
|
||||
|
||||
string SeedToString(long seed)
|
||||
{
|
||||
int combatValue = (int)(seed % 1000L);
|
||||
int resourceMultiplier = (int)(seed / 1000L % 100L);
|
||||
int starCount = (int)(seed / 100000L % 1000L);
|
||||
int gameSeed = (int)(seed / 100000000L);
|
||||
string text;
|
||||
if (combatValue / 100 > 0)
|
||||
{
|
||||
text = String.Format("{0:D8}-{1}-Z{2}-{3:00}", gameSeed, starCount, resourceMultiplier, combatValue % 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = String.Format("{0:D8}-{1}-A{2}", gameSeed, starCount, resourceMultiplier);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
using BepInEx.Configuration;
|
||||
using UXAssist.Common;
|
||||
|
||||
@@ -13,7 +13,6 @@ public static class WindowFunctions
|
||||
private const string GameWindowClass = "UnityWndClass";
|
||||
private static string _gameWindowTitle = "Dyson Sphere Program";
|
||||
|
||||
private static IntPtr _oldWndProc = IntPtr.Zero;
|
||||
private static IntPtr _gameWindowHandle = IntPtr.Zero;
|
||||
|
||||
public static ConfigEntry<int> ProcessPriority;
|
||||
@@ -36,33 +35,15 @@ public static class WindowFunctions
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
var wndProc = new WinApi.WndProc(GameWndProc);
|
||||
var gameWnd = FindGameWindow();
|
||||
if (gameWnd != IntPtr.Zero)
|
||||
{
|
||||
_oldWndProc = WinApi.SetWindowLongPtr(gameWnd, WinApi.GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(wndProc));
|
||||
}
|
||||
|
||||
ProcessPriority.SettingChanged += (_, _) => WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), ProrityFlags[ProcessPriority.Value]);
|
||||
WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), ProrityFlags[ProcessPriority.Value]);
|
||||
ProcessPriority.SettingChanged += (_, _) => ApplyProcessPriority();
|
||||
ApplyProcessPriority();
|
||||
}
|
||||
|
||||
private static IntPtr GameWndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam)
|
||||
private static void ApplyProcessPriority()
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WinApi.WM_ACTIVATE:
|
||||
WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), ProrityFlags[ProcessPriority.Value]);
|
||||
break;
|
||||
case WinApi.WM_DESTROY:
|
||||
if (_oldWndProc != IntPtr.Zero && _gameWindowHandle != IntPtr.Zero)
|
||||
{
|
||||
WinApi.SetWindowLongPtr(_gameWindowHandle, WinApi.GWLP_WNDPROC, _oldWndProc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return WinApi.CallWindowProc(_oldWndProc, hWnd, uMsg, wParam, lParam);
|
||||
// Use the managed BCL wrapper instead of a raw kernel32 SetPriorityClass P/Invoke.
|
||||
using var process = Process.GetCurrentProcess();
|
||||
process.PriorityClass = (ProcessPriorityClass)ProrityFlags[ProcessPriority.Value];
|
||||
}
|
||||
|
||||
private static string GetPriorityName(int priority)
|
||||
@@ -117,16 +98,20 @@ public static class WindowFunctions
|
||||
{
|
||||
if (_gameWindowHandle != IntPtr.Zero)
|
||||
return _gameWindowHandle;
|
||||
// Match the game window by its Unity window class plus our own process id. Matching the
|
||||
// class excludes the BepInEx console window (class "ConsoleWindowClass"), which
|
||||
// Process.MainWindowHandle would otherwise return when the console is enabled; the pid
|
||||
// check guards against other running Unity apps. Process.Id supplies the pid so no extra
|
||||
// kernel32 P/Invoke (GetCurrentProcessId/GetConsoleWindow) is needed.
|
||||
int currentProcessId;
|
||||
using (var process = Process.GetCurrentProcess())
|
||||
currentProcessId = process.Id;
|
||||
var wnd = IntPtr.Zero;
|
||||
var consoleWnd = WinApi.GetConsoleWindow();
|
||||
var currentProcessId = WinApi.GetCurrentProcessId();
|
||||
while (true)
|
||||
{
|
||||
wnd = WinApi.FindWindowEx(IntPtr.Zero, wnd, GameWindowClass, _gameWindowTitle);
|
||||
wnd = WinApi.FindWindowEx(IntPtr.Zero, wnd, GameWindowClass, null);
|
||||
if (wnd == IntPtr.Zero)
|
||||
return IntPtr.Zero;
|
||||
if (wnd == consoleWnd)
|
||||
continue;
|
||||
WinApi.GetWindowThreadProcessId(wnd, out var pid);
|
||||
if (pid == currentProcessId)
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using UnityEngine;
|
||||
using UXAssist.Functions;
|
||||
|
||||
namespace UXAssist.ModsCompat;
|
||||
|
||||
class BlueprintTweaks
|
||||
{
|
||||
public const string BlueprintTweaksGuid = "org.kremnev8.plugin.BlueprintTweaks";
|
||||
private static FieldInfo selectObjIdsField;
|
||||
private static Type classTypeBlueprintTweaksPlugin;
|
||||
private static Type classTypeUIBuildingGridPatch2;
|
||||
|
||||
public static bool Run(Harmony harmony)
|
||||
{
|
||||
if (!BepInEx.Bootstrap.Chainloader.PluginInfos.TryGetValue(BlueprintTweaksGuid, out var pluginInfo)) return false;
|
||||
var assembly = pluginInfo.Instance.GetType().Assembly;
|
||||
var classTypeDragRemoveBuildTool = assembly.GetType("BlueprintTweaks.DragRemoveBuildTool");
|
||||
if (classTypeDragRemoveBuildTool == null) return false;
|
||||
if (AccessTools.Method(classTypeDragRemoveBuildTool, "DetermineMorePreviews") != null) return true;
|
||||
classTypeBlueprintTweaksPlugin = assembly.GetType("BlueprintTweaks.BlueprintTweaksPlugin");
|
||||
classTypeUIBuildingGridPatch2 = assembly.GetType("BlueprintTweaks.UIBuildingGridPatch2");
|
||||
var UIBuildingGrid_Update = AccessTools.Method(typeof(UIBuildingGrid), nameof(UIBuildingGrid.Update));
|
||||
harmony.Patch(AccessTools.Method(classTypeUIBuildingGridPatch2, "UpdateGrid"), null, null, new HarmonyMethod(AccessTools.Method(typeof(BlueprintTweaks), nameof(PatchUpdateGrid))));
|
||||
selectObjIdsField = AccessTools.Field(classTypeDragRemoveBuildTool, "selectObjIds");
|
||||
harmony.Patch(AccessTools.Method(classTypeDragRemoveBuildTool, "DeterminePreviews"),
|
||||
new HarmonyMethod(AccessTools.Method(typeof(BlueprintTweaks), nameof(PatchDeterminePreviews))));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly int zMin = Shader.PropertyToID("_ZMin");
|
||||
private static readonly int reformMode = Shader.PropertyToID("_ReformMode");
|
||||
|
||||
private static IEnumerable<CodeInstruction> PatchUpdateGrid(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(classTypeBlueprintTweaksPlugin, "tool")),
|
||||
new CodeMatch(OpCodes.Ldfld),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Brfalse || ci.opcode == OpCodes.Brfalse_S)
|
||||
);
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher.Advance(2).Operand = label1;
|
||||
matcher.Advance(1);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIBuildingGrid), nameof(UIBuildingGrid.blueprintMaterial))),
|
||||
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(classTypeUIBuildingGridPatch2, "tintColor")),
|
||||
new CodeMatch(OpCodes.Call),
|
||||
new CodeMatch(OpCodes.Callvirt)
|
||||
).RemoveInstructions(5);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIBuildingGrid), nameof(UIBuildingGrid.blueprintMaterial))),
|
||||
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(classTypeUIBuildingGridPatch2, "cursorGratBox")),
|
||||
new CodeMatch(OpCodes.Ldsfld),
|
||||
new CodeMatch(OpCodes.Ldfld),
|
||||
new CodeMatch(OpCodes.Call),
|
||||
new CodeMatch(OpCodes.Callvirt)
|
||||
).Advance(1).Operand = AccessTools.Field(typeof(UIBuildingGrid), nameof(UIBuildingGrid.material));
|
||||
matcher.Advance(6);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIBuildingGrid), nameof(UIBuildingGrid.blueprintMaterial))),
|
||||
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(classTypeUIBuildingGridPatch2, "selectColor")),
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld),
|
||||
new CodeMatch(OpCodes.Call),
|
||||
new CodeMatch(OpCodes.Callvirt)
|
||||
).Advance(1).Operand = AccessTools.Field(typeof(UIBuildingGrid), nameof(UIBuildingGrid.material));
|
||||
matcher.Advance(1).Operand = AccessTools.Field(classTypeUIBuildingGridPatch2, "tintColor");
|
||||
matcher.Advance(5);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIBuildingGrid), nameof(UIBuildingGrid.blueprintMaterial))),
|
||||
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(classTypeUIBuildingGridPatch2, "showDivideLine")),
|
||||
new CodeMatch(OpCodes.Ldc_R4, 0f),
|
||||
new CodeMatch(OpCodes.Callvirt)
|
||||
).RemoveInstructions(5);
|
||||
matcher.InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0),
|
||||
Transpilers.EmitDelegate((UIBuildingGrid grid) =>
|
||||
{
|
||||
grid.material.SetFloat(reformMode, 0f);
|
||||
grid.material.SetFloat(zMin, -0.5f);
|
||||
})
|
||||
);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIBuildingGrid), nameof(UIBuildingGrid.blueprintGridRnd))),
|
||||
new CodeMatch(OpCodes.Ldc_I4_1),
|
||||
new CodeMatch(OpCodes.Callvirt),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Br || ci.opcode == OpCodes.Br_S)
|
||||
).RemoveInstructions(4).Set(OpCodes.Ret, null).Labels.Add(label1);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
private static void PatchDeterminePreviews(object __instance)
|
||||
{
|
||||
var selectObjIds = (HashSet<int>)selectObjIdsField.GetValue(__instance);
|
||||
var buildTool = (BuildTool)__instance;
|
||||
var factory = buildTool.factory;
|
||||
HashSet<int> extraObjIds = [];
|
||||
foreach (var objId in selectObjIds)
|
||||
{
|
||||
var desc = buildTool.GetPrefabDesc(objId);
|
||||
var isBelt = desc.isBelt;
|
||||
var isInserter = desc.isInserter;
|
||||
if (isInserter) continue;
|
||||
if (isBelt)
|
||||
{
|
||||
var needCheck = false;
|
||||
for (var j = 0; j < 2; j++)
|
||||
{
|
||||
factory.ReadObjectConn(objId, j, out _, out var connObjId, out _);
|
||||
if (connObjId == 0 || FactoryFunctions.ObjectIsBeltOrInserter(factory, connObjId)) continue;
|
||||
needCheck = true;
|
||||
break;
|
||||
}
|
||||
if (needCheck)
|
||||
{
|
||||
for (var k = 0; k < 16; k++)
|
||||
{
|
||||
factory.ReadObjectConn(objId, k, out _, out var connObjId, out _);
|
||||
if (connObjId != 0 && !selectObjIds.Contains(connObjId) && !extraObjIds.Contains(connObjId) && FactoryFunctions.ObjectIsBeltOrInserter(factory, connObjId))
|
||||
extraObjIds.Add(connObjId);
|
||||
}
|
||||
}
|
||||
for (var m = 0; m < 4; m++)
|
||||
{
|
||||
factory.ReadObjectConn(objId, m, out _, out var connObjId, out _);
|
||||
if (connObjId == 0 || !factory.ObjectIsBelt(connObjId) || selectObjIds.Contains(connObjId) || extraObjIds.Contains(connObjId)) continue;
|
||||
for (var j = 0; j < 2; j++)
|
||||
{
|
||||
factory.ReadObjectConn(connObjId, j, out _, out var connObjId2, out _);
|
||||
if (connObjId2 == 0 || selectObjIds.Contains(connObjId2) || extraObjIds.Contains(connObjId2) || FactoryFunctions.ObjectIsBeltOrInserter(factory, connObjId2)) continue;
|
||||
extraObjIds.Add(connObjId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (desc.addonType == EAddonType.Belt) continue;
|
||||
for (var j = 0; j < 16; j++)
|
||||
{
|
||||
factory.ReadObjectConn(objId, j, out _, out var connObjId, out _);
|
||||
if (connObjId != 0 && !selectObjIds.Contains(connObjId) && !extraObjIds.Contains(connObjId) && FactoryFunctions.ObjectIsBeltOrInserter(factory, connObjId))
|
||||
extraObjIds.Add(connObjId);
|
||||
}
|
||||
}
|
||||
selectObjIds.UnionWith(extraObjIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using BepInEx.Bootstrap;
|
||||
using CommonAPI;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace UXAssist.ModsCompat;
|
||||
|
||||
public static class CommonAPIWrapper
|
||||
{
|
||||
public static void Run(Harmony harmony)
|
||||
{
|
||||
if (!Chainloader.PluginInfos.TryGetValue(CommonAPIPlugin.GUID, out var commonAPIPlugin) ||
|
||||
commonAPIPlugin.Metadata.Version > new System.Version(1, 6, 7, 0)) return;
|
||||
harmony.Patch(AccessTools.Method(typeof(GameOption), nameof(GameOption.InitKeys)), new HarmonyMethod(AccessTools.Method(typeof(CommonAPIWrapper), nameof(PatchInitKeys)), Priority.First));
|
||||
}
|
||||
|
||||
public static bool PatchInitKeys(GameOption __instance)
|
||||
{
|
||||
return __instance.overrideKeys == null;
|
||||
}
|
||||
}
|
||||
@@ -269,14 +269,14 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
InitNodeForAbsorb();
|
||||
GameLogicProc.OnGameBegin += GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameEnd += GameMain_End_Postfix;
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
GameLogicProc.OnGameEnd += OnGameEnd;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
GameLogicProc.OnGameEnd -= GameMain_End_Postfix;
|
||||
GameLogicProc.OnGameBegin -= GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameEnd -= OnGameEnd;
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
_initialized = false;
|
||||
_nodeForAbsorb = null;
|
||||
}
|
||||
@@ -347,12 +347,12 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
return comp is { Count: > 0 };
|
||||
}
|
||||
|
||||
private static void GameMain_Begin_Postfix()
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
InitNodeForAbsorb();
|
||||
}
|
||||
|
||||
private static void GameMain_End_Postfix()
|
||||
private static void OnGameEnd()
|
||||
{
|
||||
_initialized = false;
|
||||
_nodeForAbsorb = null;
|
||||
@@ -414,7 +414,7 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||
);
|
||||
if (jmpTarget == null) return matcher.InstructionEnumeration();
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Labels = [];
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(EjectorComponent), nameof(EjectorComponent.runtimeOrbitId))),
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BepInEx.Configuration;
|
||||
using CommonAPI.Systems;
|
||||
using HarmonyLib;
|
||||
@@ -31,6 +32,8 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
public static ConfigEntry<bool> DoNotRenderEntitiesEnabled;
|
||||
public static ConfigEntry<bool> DragBuildPowerPolesEnabled;
|
||||
public static ConfigEntry<bool> DragBuildPowerPolesAlternatelyEnabled;
|
||||
public static ConfigEntry<bool> AutoConstructButtonEnabled;
|
||||
public static ConfigEntry<bool> AutoConstructEnabled;
|
||||
public static ConfigEntry<bool> BeltSignalsForBuyOutEnabled;
|
||||
public static ConfigEntry<bool> TankFastFillInAndTakeOutEnabled;
|
||||
public static ConfigEntry<int> TankFastFillInAndTakeOutMultiplier;
|
||||
@@ -45,6 +48,9 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
public static ConfigEntry<int> EjectorBufferCount;
|
||||
public static ConfigEntry<int> SiloBufferCount;
|
||||
public static ConfigEntry<bool> ShortcutKeysForBlueprintCopyEnabled;
|
||||
public static ConfigEntry<bool> PressShiftToTakeWholeBeltItemsEnabled;
|
||||
public static ConfigEntry<bool> PressShiftToTakeWholeBeltItemsIncludeBranches;
|
||||
public static ConfigEntry<bool> PressShiftToTakeWholeBeltItemsIncludeInserters;
|
||||
|
||||
private static PressKeyBind _doNotRenderEntitiesKey;
|
||||
private static PressKeyBind _offgridfForPathsKey;
|
||||
@@ -119,6 +125,8 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
DoNotRenderEntitiesEnabled.SettingChanged += (_, _) => DoNotRenderEntities.Enable(DoNotRenderEntitiesEnabled.Value);
|
||||
DragBuildPowerPolesEnabled.SettingChanged += (_, _) => DragBuildPowerPoles.Enable(DragBuildPowerPolesEnabled.Value);
|
||||
DragBuildPowerPolesAlternatelyEnabled.SettingChanged += (_, _) => DragBuildPowerPoles.AlternatelyChanged();
|
||||
AutoConstructButtonEnabled.SettingChanged += (_, _) => AutoConstructButton.Enable(AutoConstructButtonEnabled.Value);
|
||||
AutoConstructEnabled.SettingChanged += (_, _) => Functions.UIFunctions.UpdateToggleAutoConstructCheckButtonVisiblility();
|
||||
BeltSignalsForBuyOutEnabled.SettingChanged += (_, _) => BeltSignalsForBuyOut.Enable(BeltSignalsForBuyOutEnabled.Value);
|
||||
TankFastFillInAndTakeOutEnabled.SettingChanged += (_, _) => TankFastFillInAndTakeOut.Enable(TankFastFillInAndTakeOutEnabled.Value);
|
||||
TankFastFillInAndTakeOutMultiplier.SettingChanged += (_, _) => UpdateTankFastFillInAndTakeOutMultiplierRealValue();
|
||||
@@ -131,6 +139,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
ReceiverBufferCount.SettingChanged += (_, _) => TweakBuildingBuffer.RefreshReceiverBufferCount();
|
||||
EjectorBufferCount.SettingChanged += (_, _) => TweakBuildingBuffer.RefreshEjectorBufferCount();
|
||||
SiloBufferCount.SettingChanged += (_, _) => TweakBuildingBuffer.RefreshSiloBufferCount();
|
||||
PressShiftToTakeWholeBeltItemsEnabled.SettingChanged += (_, _) => PressShiftToTakeWholeBeltItems.Enable(PressShiftToTakeWholeBeltItemsEnabled.Value);
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
@@ -147,9 +156,11 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
ProtectVeinsFromExhaustion.Enable(ProtectVeinsFromExhaustionEnabled.Value);
|
||||
DoNotRenderEntities.Enable(DoNotRenderEntitiesEnabled.Value);
|
||||
DragBuildPowerPoles.Enable(DragBuildPowerPolesEnabled.Value);
|
||||
AutoConstructButton.Enable(AutoConstructButtonEnabled.Value);
|
||||
BeltSignalsForBuyOut.Enable(BeltSignalsForBuyOutEnabled.Value);
|
||||
TankFastFillInAndTakeOut.Enable(TankFastFillInAndTakeOutEnabled.Value);
|
||||
TweakBuildingBuffer.Enable(TweakBuildingBufferEnabled.Value);
|
||||
PressShiftToTakeWholeBeltItems.Enable(PressShiftToTakeWholeBeltItemsEnabled.Value);
|
||||
|
||||
Enable(true);
|
||||
UpdateTankFastFillInAndTakeOutMultiplierRealValue();
|
||||
@@ -159,9 +170,11 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
Enable(false);
|
||||
|
||||
PressShiftToTakeWholeBeltItems.Enable(false);
|
||||
TweakBuildingBuffer.Enable(false);
|
||||
TankFastFillInAndTakeOut.Enable(false);
|
||||
BeltSignalsForBuyOut.Enable(false);
|
||||
AutoConstructButton.Enable(false);
|
||||
DragBuildPowerPoles.Enable(false);
|
||||
DoNotRenderEntities.Enable(false);
|
||||
ProtectVeinsFromExhaustion.Enable(false);
|
||||
@@ -267,6 +280,95 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
public class AutoConstructButton : PatchImpl<AutoConstructButton>
|
||||
{
|
||||
private static int _lastPrebuildCount = -1;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
Functions.UIFunctions.UpdateToggleAutoConstructCheckButtonVisiblility();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
Functions.UIFunctions.UpdateToggleAutoConstructCheckButtonVisiblility();
|
||||
_lastPrebuildCount = -1;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetData), nameof(PlanetData.NotifyFactoryLoaded))]
|
||||
private static void PlanetData_NotifyFactoryLoaded_Postfix()
|
||||
{
|
||||
Functions.UIFunctions.UpdateToggleAutoConstructCheckButtonVisiblility();
|
||||
_lastPrebuildCount = -1;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetData), nameof(PlanetData.UnloadFactory))]
|
||||
private static void PlanetData_UnloadFactory_Postfix()
|
||||
{
|
||||
Functions.UIFunctions.UpdateToggleAutoConstructCheckButtonVisiblility();
|
||||
_lastPrebuildCount = -1;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlayerAction_Rts), nameof(PlayerAction_Rts.GameTick))]
|
||||
private static void PlayerAction_Rts_GameTick_Postfix(PlayerAction_Rts __instance, long timei)
|
||||
{
|
||||
if (timei % 60L != 0) return;
|
||||
var planet = GameMain.localPlanet;
|
||||
if (planet == null || !planet.factoryLoaded) return;
|
||||
var factory = planet.factory;
|
||||
var prebuildCount = factory.prebuildCount;
|
||||
if (_lastPrebuildCount != prebuildCount)
|
||||
{
|
||||
if (_lastPrebuildCount <= 0 || prebuildCount == 0)
|
||||
{
|
||||
Functions.UIFunctions.UpdateToggleAutoConstructCheckButtonVisiblility();
|
||||
}
|
||||
_lastPrebuildCount = prebuildCount;
|
||||
Functions.UIFunctions.UpdateConstructCountText(prebuildCount);
|
||||
}
|
||||
if (prebuildCount <= 0) return;
|
||||
if (!AutoConstructEnabled.Value) return;
|
||||
var player = __instance.player;
|
||||
if (prebuildCount <= player.mecha.constructionModule.buildTargetTotalCount) return;
|
||||
if (player.orders.orderCount > 0) return;
|
||||
if (player.controller.horzVelocity.sqrMagnitude > 0.01f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var prebuilds = factory.prebuildPool;
|
||||
var minDist = float.MaxValue;
|
||||
var minIndex = 0;
|
||||
var playerPos = player.position;
|
||||
for (var i = factory.prebuildCursor - 1; i > 0; i--)
|
||||
{
|
||||
ref var prebuild = ref prebuilds[i];
|
||||
if (prebuild.id != i || prebuild.isDestroyed) continue;
|
||||
if (prebuild.itemRequired > 0)
|
||||
{
|
||||
if (player.package.GetItemCount(prebuild.protoId) < prebuild.itemRequired) continue;
|
||||
}
|
||||
var dist = (prebuild.pos - playerPos).sqrMagnitude;
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
minIndex = i;
|
||||
}
|
||||
}
|
||||
if (minIndex == 0) return;
|
||||
var diff = prebuilds[minIndex].pos - playerPos;
|
||||
if (diff.sqrMagnitude < 400f) return;
|
||||
if (player.movementState == EMovementState.Walk && player.mecha.thrusterLevel >= 1)
|
||||
{
|
||||
player.controller.actionWalk.SwitchToFly();
|
||||
return;
|
||||
}
|
||||
player.Order(OrderNode.MoveTo(prebuilds[minIndex].pos + diff.normalized * 6f), false);
|
||||
}
|
||||
}
|
||||
|
||||
public class NightLight : PatchImpl<NightLight>
|
||||
{
|
||||
private static bool _nightlightInitialized;
|
||||
@@ -276,12 +378,12 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
GameLogicProc.OnGameEnd += GameMain_End_Postfix;
|
||||
GameLogicProc.OnGameEnd += OnGameEnd;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
GameLogicProc.OnGameEnd -= GameMain_End_Postfix;
|
||||
GameLogicProc.OnGameEnd -= OnGameEnd;
|
||||
if (_sunlight)
|
||||
{
|
||||
_sunlight.transform.localEulerAngles = new Vector3(0f, 180f);
|
||||
@@ -292,7 +394,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
_nightlightInitialized = false;
|
||||
}
|
||||
|
||||
private static void GameMain_End_Postfix()
|
||||
private static void OnGameEnd()
|
||||
{
|
||||
if (_sunlight)
|
||||
{
|
||||
@@ -304,25 +406,13 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
_nightlightInitialized = false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void UpdateSunlightAngle()
|
||||
{
|
||||
if (!_sunlight) return;
|
||||
_sunlight.transform.rotation = Quaternion.LookRotation(-GameMain.mainPlayer.transform.up + GameMain.mainPlayer.transform.forward * NightLightAngleX.Value / 10f +
|
||||
GameMain.mainPlayer.transform.right * NightLightAngleY.Value / 10f);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameData), nameof(GameData.ArriveStar))]
|
||||
public static void GameData_ArriveStar_Postfix()
|
||||
{
|
||||
_sunlight = GameMain.universeSimulator?.LocalStarSimulator()?.sunLight;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(GameData), nameof(GameData.LeaveStar))]
|
||||
public static void GameData_LeaveStar_Prefix()
|
||||
{
|
||||
_sunlight = null;
|
||||
_sunlight.transform.rotation =
|
||||
Quaternion.LookRotation(-GameMain.mainPlayer.transform.up + GameMain.mainPlayer.transform.forward * NightLightAngleX.Value / 10f +
|
||||
GameMain.mainPlayer.transform.right * NightLightAngleY.Value / 10f);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
@@ -335,7 +425,6 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
if (!GameMain.mainPlayer.controller.model.gameObject.activeInHierarchy) return;
|
||||
if (_sail == null) _sail = GameMain.mainPlayer.animator.sails[GameMain.mainPlayer.animator.sailAnimIndex];
|
||||
_sunlight = GameMain.universeSimulator?.LocalStarSimulator()?.sunLight;
|
||||
_nightlightInitialized = true;
|
||||
}
|
||||
|
||||
@@ -356,6 +445,10 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
|
||||
if (sailing) return;
|
||||
_mechaOnEarth = true;
|
||||
if (_sunlight == null)
|
||||
{
|
||||
_sunlight = GameMain.universeSimulator?.LocalStarSimulator()?.sunLight;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
@@ -385,8 +478,8 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(PlanetSimulator), nameof(PlanetSimulator.LateUpdate))]
|
||||
private static IEnumerable<CodeInstruction> PlanetSimulator_LateUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
[HarmonyPatch(typeof(PlanetSimulator), nameof(PlanetSimulator.LateRefresh))]
|
||||
private static IEnumerable<CodeInstruction> PlanetSimulator_LateRefresh_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
// var vec = (NightlightEnabled ? GameMain.mainPlayer.transform.up : (Quaternion.Inverse(localPlanet.runtimeRotation) * (__instance.planetData.star.uPosition - __instance.planetData.uPosition).normalized));
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
@@ -1172,6 +1265,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
currentVeinIndex++;
|
||||
}
|
||||
__instance.currentVeinIndex = veinCount > 1 ? currentVeinIndex % veinCount : 0;
|
||||
__instance.time -= __instance.period * times;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1261,6 +1355,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
else
|
||||
{
|
||||
__instance.time -= __instance.period * times;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1405,16 +1500,16 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin += GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameEnd += GameMain_End_Postfix;
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
GameLogicProc.OnGameEnd += OnGameEnd;
|
||||
FixProto();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
UnfixProto();
|
||||
GameLogicProc.OnGameEnd -= GameMain_End_Postfix;
|
||||
GameLogicProc.OnGameBegin -= GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameEnd -= OnGameEnd;
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
}
|
||||
|
||||
public static void AlternatelyChanged()
|
||||
@@ -1440,14 +1535,14 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
OldDragBuild.Add(prefabDesc.dragBuild);
|
||||
OldDragBuildDist.Add(prefabDesc.dragBuildDist);
|
||||
prefabDesc.dragBuild = true;
|
||||
var distance = prefabDesc.powerConnectDistance - 0.72f;
|
||||
var distance = prefabDesc.powerConnectDistance - 0.8f;
|
||||
prefabDesc.dragBuildDist = new Vector2(distance, distance);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnfixProto()
|
||||
{
|
||||
if (GetHarmony() == null || OldDragBuild.Count < 3 || DSPGame.IsMenuDemo) return;
|
||||
if (GetHarmony() == null || OldDragBuild.Count < PowerPoleIds.Length || DSPGame.IsMenuDemo) return;
|
||||
var i = 0;
|
||||
foreach (var id in PowerPoleIds)
|
||||
{
|
||||
@@ -1465,14 +1560,16 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
OldDragBuildDist.Clear();
|
||||
}
|
||||
|
||||
private static void GameMain_Begin_Postfix()
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
_powerPoleProto ??= LDB.items.Select(2201);
|
||||
FixProto();
|
||||
}
|
||||
|
||||
private static void GameMain_End_Postfix()
|
||||
private static void OnGameEnd()
|
||||
{
|
||||
UnfixProto();
|
||||
_powerPoleProto = null;
|
||||
}
|
||||
|
||||
private static int PlanetGridSnapDotsNonAllocNotAligned(PlanetGrid planetGrid, Vector3 begin, Vector3 end, Vector2 interval, float yaw, float planetRadius, float gap, Vector3[] snaps)
|
||||
@@ -1571,21 +1668,43 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
);
|
||||
var operand = matcher.Operand;
|
||||
matcher.Start().Advance(pos);
|
||||
matcher.Advance(2).InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, operand)).SetInstructionAndAdvance(Transpilers.EmitDelegate((BuildTool_Click click, int i) =>
|
||||
matcher.Advance(2).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, operand)
|
||||
).SetInstructionAndAdvance(Transpilers.EmitDelegate((BuildTool_Click click, int i) =>
|
||||
{
|
||||
if (!DragBuildPowerPolesAlternatelyEnabled.Value || (i & 1) == 0) return click.handItem;
|
||||
var id = click.handItem.ID;
|
||||
if (id != 2202) return click.handItem;
|
||||
return LDB.items.Select(id ^ 3);
|
||||
})).Advance(3).InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, operand)).SetInstructionAndAdvance(Transpilers.EmitDelegate((BuildTool_Click click, int i) =>
|
||||
if (click.handItem.ID != 2202 || (i & 1) == 0 || !DragBuildPowerPolesAlternatelyEnabled.Value)
|
||||
return click.handItem;
|
||||
return _powerPoleProto;
|
||||
})).Advance(3).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, operand)
|
||||
).SetInstructionAndAdvance(Transpilers.EmitDelegate((BuildTool_Click click, int i) =>
|
||||
{
|
||||
if (!DragBuildPowerPolesAlternatelyEnabled.Value || (i & 1) == 0) return click.handPrefabDesc;
|
||||
var id = click.handItem.ID;
|
||||
if (id != 2202) return click.handPrefabDesc;
|
||||
return LDB.items.Select(id ^ 3).prefabDesc;
|
||||
if (click.handItem.ID != 2202 || (i & 1) == 0 || !DragBuildPowerPolesAlternatelyEnabled.Value)
|
||||
return click.handPrefabDesc;
|
||||
return _powerPoleProto.prefabDesc;
|
||||
}));
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BuildPreview), nameof(BuildPreview.Clone)))
|
||||
).Advance(2).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, operand)
|
||||
).SetInstructionAndAdvance(Transpilers.EmitDelegate((BuildPreview to, BuildPreview from, int i) =>
|
||||
{
|
||||
if (from.item.ID != 2202 || (i & 1) == 0 || !DragBuildPowerPolesAlternatelyEnabled.Value)
|
||||
{
|
||||
to.Clone(from);
|
||||
return;
|
||||
}
|
||||
to.ResetAll();
|
||||
to.item = _powerPoleProto;
|
||||
to.desc = _powerPoleProto.prefabDesc;
|
||||
to.needModel = _powerPoleProto.prefabDesc.lodCount > 0 && _powerPoleProto.prefabDesc.lodMeshes[0] != null;
|
||||
}));
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
private static ItemProto _powerPoleProto;
|
||||
}
|
||||
|
||||
private class BeltSignalsForBuyOut : PatchImpl<BeltSignalsForBuyOut>
|
||||
@@ -1620,7 +1739,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
ID = 301,
|
||||
Name = "存储单元",
|
||||
GridIndex = 3601,
|
||||
GridIndex = 3801,
|
||||
IconPath = "assets/signal/memory.png",
|
||||
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/memory.png", assembly),
|
||||
SID = ""
|
||||
@@ -1629,7 +1748,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
ID = 302,
|
||||
Name = "能量碎片",
|
||||
GridIndex = 3602,
|
||||
GridIndex = 3802,
|
||||
IconPath = "assets/signal/energy-fragment.png",
|
||||
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/energy-fragment.png", assembly),
|
||||
SID = ""
|
||||
@@ -1638,7 +1757,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
ID = 303,
|
||||
Name = "硅基神经元",
|
||||
GridIndex = 3603,
|
||||
GridIndex = 3803,
|
||||
IconPath = "assets/signal/silicon-neuron.png",
|
||||
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/silicon-neuron.png", assembly),
|
||||
SID = ""
|
||||
@@ -1647,7 +1766,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
ID = 304,
|
||||
Name = "负熵奇点",
|
||||
GridIndex = 3604,
|
||||
GridIndex = 3804,
|
||||
IconPath = "assets/signal/negentropy.png",
|
||||
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/negentropy.png", assembly),
|
||||
SID = ""
|
||||
@@ -1656,7 +1775,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
ID = 305,
|
||||
Name = "物质重组器",
|
||||
GridIndex = 3605,
|
||||
GridIndex = 3805,
|
||||
IconPath = "assets/signal/reassembler.png",
|
||||
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/reassembler.png", assembly),
|
||||
SID = ""
|
||||
@@ -1665,7 +1784,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
ID = 306,
|
||||
Name = "虚粒子",
|
||||
GridIndex = 3606,
|
||||
GridIndex = 3806,
|
||||
IconPath = "assets/signal/virtual-particle.png",
|
||||
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/virtual-particle.png", assembly),
|
||||
SID = ""
|
||||
@@ -1677,7 +1796,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
}
|
||||
|
||||
var index = signals.dataArray.Length;
|
||||
signals.dataArray = signals.dataArray.Concat(protos).ToArray();
|
||||
signals.dataArray = [.. signals.dataArray, .. protos];
|
||||
foreach (var proto in protos)
|
||||
{
|
||||
signals.dataIndices[proto.ID] = index;
|
||||
@@ -1693,7 +1812,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var signals = LDB._signals;
|
||||
if (signals.dataIndices.TryGetValue(301, out var index))
|
||||
{
|
||||
signals.dataArray = signals.dataArray.Take(index).Concat(signals.dataArray.Skip(index + 6)).ToArray();
|
||||
signals.dataArray = [.. signals.dataArray.Take(index), .. signals.dataArray.Skip(index + 6)];
|
||||
for (var id = 301; id <= 306; id++)
|
||||
signals.dataIndices.Remove(id);
|
||||
var len = signals.dataArray.Length;
|
||||
@@ -1741,7 +1860,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
if (index < 0) return null;
|
||||
if (index >= _signalBelts.Length)
|
||||
{
|
||||
Array.Resize(ref _signalBelts, index * 2);
|
||||
Array.Resize(ref _signalBelts, (index + 1) * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1749,7 +1868,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
if (obj != null) return obj;
|
||||
}
|
||||
|
||||
obj = new Dictionary<int, uint>();
|
||||
obj = [];
|
||||
_signalBelts[index] = obj;
|
||||
return obj;
|
||||
}
|
||||
@@ -1782,12 +1901,12 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
{
|
||||
AddBeltSignalProtos();
|
||||
GameLogicProc.OnDataLoaded += VFPreload_InvokeOnLoadWorkEnded_Postfix;
|
||||
GameLogicProc.OnGameBegin += GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin -= GameMain_Begin_Postfix;
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
GameLogicProc.OnDataLoaded -= VFPreload_InvokeOnLoadWorkEnded_Postfix;
|
||||
}
|
||||
|
||||
@@ -1809,7 +1928,7 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
RemovePlanetSignalBelts(factory.index);
|
||||
}
|
||||
|
||||
private static void GameMain_Begin_Postfix()
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
_clusterSeedKey = GameMain.data.GetClusterSeedKey();
|
||||
InitSignalBelts();
|
||||
@@ -1888,11 +2007,10 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var consume = (byte)Math.Min(DarkFogItemsInVoid[itemIdx], 4);
|
||||
if (consume < 4)
|
||||
{
|
||||
var metaverse = propertySystem.GetItemAvaliableProperty(_clusterSeedKey, 6006);
|
||||
if (metaverse > 0)
|
||||
var metaverseLong = propertySystem.GetItemAvaliableProperty(_clusterSeedKey, 6006);
|
||||
if (metaverseLong > 0L)
|
||||
{
|
||||
if (metaverse > 10)
|
||||
metaverse = 10;
|
||||
var metaverse = metaverseLong > 10 ? 10 : (int)metaverseLong;
|
||||
propertySystem.AddItemConsumption(_clusterSeedKey, 6006, metaverse);
|
||||
var mainPlayer = GameMain.mainPlayer;
|
||||
GameMain.history.AddPropertyItemConsumption(6006, metaverse, true);
|
||||
@@ -2155,13 +2273,14 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.timeSpend))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.recipeExecuteData))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(RecipeExecuteData), nameof(RecipeExecuteData.timeSpend))),
|
||||
new CodeMatch(OpCodes.Ldc_I4, 5400000),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Bgt_S || ci.opcode == OpCodes.Bgt),
|
||||
new CodeMatch(OpCodes.Ldc_I4_3)
|
||||
);
|
||||
var extraCount = LabBufferExtraCountForAdvancedAssemble.Value;
|
||||
matcher.Advance(4).SetAndAdvance(OpCodes.Ldc_I4, extraCount);
|
||||
matcher.Advance(5).SetAndAdvance(OpCodes.Ldc_I4, extraCount);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Div),
|
||||
new CodeMatch(OpCodes.Mul),
|
||||
@@ -2233,4 +2352,234 @@ public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
|
||||
private class PressShiftToTakeWholeBeltItems : PatchImpl<PressShiftToTakeWholeBeltItems>
|
||||
{
|
||||
private static long nextTimei = 0;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||
}
|
||||
|
||||
private static void OnGameBegin()
|
||||
{
|
||||
nextTimei = 0;
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(VFInput), nameof(VFInput._fastTransferWithEntityDown), MethodType.Getter)]
|
||||
[HarmonyPatch(typeof(VFInput), nameof(VFInput._fastTransferWithEntityPress), MethodType.Getter)]
|
||||
private static IEnumerable<CodeInstruction> VFInput_fastTransferWithEntityDown_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(typeof(VFInput), nameof(VFInput.shift))),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Brtrue || ci.opcode == OpCodes.Brtrue_S)
|
||||
);
|
||||
var lables = matcher.Labels;
|
||||
matcher.RemoveInstructions(2);
|
||||
matcher.Labels.AddRange(lables);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(PlayerAction_Inspect), nameof(PlayerAction_Inspect.GameTick))]
|
||||
private static IEnumerable<CodeInstruction> PlayerAction_Inspect_GameTick_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldc_I4_1),
|
||||
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(PlayerAction_Inspect), nameof(PlayerAction_Inspect.fastFillIn)))
|
||||
);
|
||||
matcher.SetAndAdvance(OpCodes.Ldsfld, AccessTools.Field(typeof(VFInput), nameof(VFInput.shift))).Insert(
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ceq)
|
||||
);
|
||||
|
||||
var label0 = generator.DefineLabel();
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsStloc()),
|
||||
new CodeMatch(OpCodes.Ldc_I4_0),
|
||||
new CodeMatch(ci => ci.IsStloc()),
|
||||
new CodeMatch(OpCodes.Ldloc_0),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(PlanetFactory), nameof(PlanetFactory.EntityFastTakeOut)))
|
||||
).Advance(8).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(VFInput), nameof(VFInput.shift))),
|
||||
new CodeInstruction(OpCodes.Brfalse_S, label0),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PressShiftToTakeWholeBeltItems), nameof(EntityFastTakeOutAlt))),
|
||||
new CodeInstruction(OpCodes.Br, label1)
|
||||
).Labels.Add(label0);
|
||||
matcher.Advance(1).Labels.Add(label1);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
private static void EntityFastTakeOutAlt(PlanetFactory factory, int entityId, bool toPackage, out ItemBundle itemBundle, out bool full)
|
||||
{
|
||||
if (factory._tmp_items == null)
|
||||
{
|
||||
factory._tmp_items = new ItemBundle();
|
||||
}
|
||||
else
|
||||
{
|
||||
factory._tmp_items.Clear();
|
||||
}
|
||||
itemBundle = factory._tmp_items;
|
||||
full = false;
|
||||
if (entityId == 0 || factory.entityPool[entityId].id != entityId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var main = GameMain.instance;
|
||||
if (main.timei < nextTimei) return;
|
||||
nextTimei = main.timei + 12;
|
||||
|
||||
ref var entityData = ref factory.entityPool[entityId];
|
||||
if (entityData.beltId <= 0) return;
|
||||
var cargoTraffic = factory.cargoTraffic;
|
||||
ref var belt = ref cargoTraffic.beltPool[entityData.beltId];
|
||||
if (belt.id != entityData.beltId) return;
|
||||
|
||||
HashSet<int> pathIds = [belt.segPathId];
|
||||
HashSet<int> inserterIds = [];
|
||||
var includeBranches = PressShiftToTakeWholeBeltItemsIncludeBranches.Value;
|
||||
var includeInserters = PressShiftToTakeWholeBeltItemsIncludeInserters.Value;
|
||||
List<int> pendingPathIds = [belt.segPathId];
|
||||
Dictionary<int, long> takeOutItems = [];
|
||||
var factorySystem = factory.factorySystem;
|
||||
while (pendingPathIds.Count > 0)
|
||||
{
|
||||
var lastIndex = pendingPathIds.Count - 1;
|
||||
var thisPathId = pendingPathIds[lastIndex];
|
||||
pendingPathIds.RemoveAt(lastIndex);
|
||||
var path = cargoTraffic.GetCargoPath(thisPathId);
|
||||
if (path == null) continue;
|
||||
if (includeInserters)
|
||||
{
|
||||
foreach (var beltId in path.belts)
|
||||
{
|
||||
ref var b = ref cargoTraffic.beltPool[beltId];
|
||||
if (b.id != beltId) return;
|
||||
// From WriteObjectConn: Only slot 4 to 11 is used for belt <-> inserter connections (method argument slot/otherSlot is -1 there)
|
||||
for (int cidx = 4; cidx < 12; cidx++)
|
||||
{
|
||||
factory.ReadObjectConn(b.entityId, cidx, out var isOutput, out var otherObjId, out var otherSlot);
|
||||
if (otherObjId <= 0) continue;
|
||||
var inserterId = factory.entityPool[otherObjId].inserterId;
|
||||
if (inserterId <= 0) continue;
|
||||
ref var inserter = ref factorySystem.inserterPool[inserterId];
|
||||
if (inserter.id != inserterId) continue;
|
||||
inserterIds.Add(inserterId);
|
||||
if (includeBranches)
|
||||
{
|
||||
var pickTargetId = inserter.pickTarget;
|
||||
if (pickTargetId > 0)
|
||||
{
|
||||
ref var pickTarget = ref factory.entityPool[pickTargetId];
|
||||
if (pickTarget.id == pickTargetId && pickTarget.beltId > 0)
|
||||
{
|
||||
ref var pickTargetBelt = ref cargoTraffic.beltPool[pickTarget.beltId];
|
||||
if (pickTargetBelt.id == pickTarget.beltId && !pathIds.Contains(pickTargetBelt.segPathId))
|
||||
{
|
||||
pathIds.Add(pickTargetBelt.segPathId);
|
||||
pendingPathIds.Add(pickTargetBelt.segPathId);
|
||||
}
|
||||
}
|
||||
}
|
||||
var insertTargetId = inserter.insertTarget;
|
||||
if (insertTargetId > 0)
|
||||
{
|
||||
ref var insertTarget = ref factory.entityPool[insertTargetId];
|
||||
if (insertTarget.id == insertTargetId && insertTarget.beltId > 0)
|
||||
{
|
||||
ref var insertTargetBelt = ref cargoTraffic.beltPool[insertTarget.beltId];
|
||||
if (insertTargetBelt.id == insertTarget.beltId && !pathIds.Contains(insertTargetBelt.segPathId))
|
||||
{
|
||||
pathIds.Add(insertTargetBelt.segPathId);
|
||||
pendingPathIds.Add(insertTargetBelt.segPathId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!includeBranches) continue;
|
||||
foreach (var inputPathId in path.inputPaths)
|
||||
{
|
||||
if (pathIds.Contains(inputPathId)) continue;
|
||||
pathIds.Add(inputPathId);
|
||||
pendingPathIds.Add(inputPathId);
|
||||
}
|
||||
if (path.outputPath == null) continue;
|
||||
var outputPathId = path.outputPath.id;
|
||||
if (pathIds.Contains(outputPathId)) continue;
|
||||
pathIds.Add(outputPathId);
|
||||
pendingPathIds.Add(outputPathId);
|
||||
}
|
||||
|
||||
var mainPlayer = factory.gameData.mainPlayer;
|
||||
foreach (var pathId in pathIds)
|
||||
{
|
||||
var cargoPath = cargoTraffic.GetCargoPath(pathId);
|
||||
if (cargoPath == null) continue;
|
||||
var end = cargoPath.bufferLength - 5;
|
||||
var buffer = cargoPath.buffer;
|
||||
for (var i = 0; i <= end;)
|
||||
{
|
||||
if (buffer[i] >= 246)
|
||||
{
|
||||
var delta = 250 - buffer[i];
|
||||
if (delta > 0) i += delta;
|
||||
var index = buffer[i + 1] - 1 + (buffer[i + 2] - 1) * 100 + (buffer[i + 3] - 1) * 10000 + (buffer[i + 4] - 1) * 1000000;
|
||||
ref var cargo = ref cargoPath.cargoContainer.cargoPool[index];
|
||||
var item = cargo.item;
|
||||
takeOutItems[item] = (takeOutItems.TryGetValue(item, out var value) ? value : 0)
|
||||
+ ((long)cargo.stack | ((long)cargo.inc << 32));
|
||||
Array.Clear(buffer, i - 4, 10);
|
||||
i += 6;
|
||||
if (cargoPath.updateLen < i) cargoPath.updateLen = i;
|
||||
i += 4;
|
||||
cargoPath.cargoContainer.RemoveCargo(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
i += 5;
|
||||
if (i > end && i < end + 5)
|
||||
{
|
||||
i = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var inserterId in inserterIds)
|
||||
{
|
||||
ref var inserter = ref factorySystem.inserterPool[inserterId];
|
||||
if (inserter.itemId > 0 && inserter.stackCount > 0)
|
||||
{
|
||||
takeOutItems[inserter.itemId] = (takeOutItems.TryGetValue(inserter.itemId, out var value) ? value : 0)
|
||||
+ ((long)inserter.itemCount | ((long)inserter.itemInc << 32));
|
||||
inserter.itemId = 0;
|
||||
inserter.stackCount = 0;
|
||||
inserter.itemCount = 0;
|
||||
inserter.itemInc = 0;
|
||||
}
|
||||
}
|
||||
foreach (var kvp in takeOutItems)
|
||||
{
|
||||
var added = mainPlayer.TryAddItemToPackage(kvp.Key, (int)(kvp.Value & 0xFFFFFFFF), (int)(kvp.Value >> 32), true, entityId);
|
||||
if (added > 0) UIItemup.Up(kvp.Key, added);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,6 +464,16 @@ public class GamePatch : PatchImpl<GamePatch>
|
||||
_needConvert = true;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.Import))]
|
||||
private static void GameHistoryData_Import_Postfix(GameHistoryData __instance)
|
||||
{
|
||||
if (_needConvert)
|
||||
{
|
||||
__instance.combatSettings = UIRoot.instance.galaxySelect.uiCombat.combatSettings;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(GameData), nameof(GameData.Import))]
|
||||
private static IEnumerable<CodeInstruction> GameData_Import_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
@@ -511,8 +521,9 @@ public class GamePatch : PatchImpl<GamePatch>
|
||||
__instance.ImportXML(optionPath);
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
var gameXMLOptionPath = GameConfig.gameXMLOptionPath;
|
||||
|
||||
+588
-140
@@ -48,6 +48,7 @@ public static class LogisticsPatch
|
||||
|
||||
public static ConfigEntry<bool> LogisticsCapacityTweaksEnabled;
|
||||
public static ConfigEntry<bool> AllowOverflowInLogisticsEnabled;
|
||||
public static ConfigEntry<bool> GreaterPowerUsageInLogisticsEnabled;
|
||||
public static ConfigEntry<bool> LogisticsConstrolPanelImprovementEnabled;
|
||||
public static ConfigEntry<bool> RealtimeLogisticsInfoPanelEnabled;
|
||||
public static ConfigEntry<bool> RealtimeLogisticsInfoPanelBarsEnabled;
|
||||
@@ -59,6 +60,7 @@ public static class LogisticsPatch
|
||||
SetDefaultRemoteLogicToStorage.SettingChanged += (_, _) => AutoConfigLogisticsSetDefaultRemoteLogicToStorage.Enable(SetDefaultRemoteLogicToStorage.Value);
|
||||
LogisticsCapacityTweaksEnabled.SettingChanged += (_, _) => LogisticsCapacityTweaks.Enable(LogisticsCapacityTweaksEnabled.Value);
|
||||
AllowOverflowInLogisticsEnabled.SettingChanged += (_, _) => AllowOverflowInLogistics.Enable(AllowOverflowInLogisticsEnabled.Value);
|
||||
GreaterPowerUsageInLogisticsEnabled.SettingChanged += (_, _) => GreaterPowerUsageInLogistics.Enable(GreaterPowerUsageInLogisticsEnabled.Value);
|
||||
LogisticsConstrolPanelImprovementEnabled.SettingChanged += (_, _) => LogisticsConstrolPanelImprovement.Enable(LogisticsConstrolPanelImprovementEnabled.Value);
|
||||
RealtimeLogisticsInfoPanelEnabled.SettingChanged += (_, _) => RealtimeLogisticsInfoPanel.Enable(RealtimeLogisticsInfoPanelEnabled.Value);
|
||||
RealtimeLogisticsInfoPanelBarsEnabled.SettingChanged += (_, _) => RealtimeLogisticsInfoPanel.EnableBars(RealtimeLogisticsInfoPanelBarsEnabled.Value);
|
||||
@@ -70,23 +72,27 @@ public static class LogisticsPatch
|
||||
AutoConfigLogisticsSetDefaultRemoteLogicToStorage.Enable(SetDefaultRemoteLogicToStorage.Value);
|
||||
LogisticsCapacityTweaks.Enable(LogisticsCapacityTweaksEnabled.Value);
|
||||
AllowOverflowInLogistics.Enable(AllowOverflowInLogisticsEnabled.Value);
|
||||
GreaterPowerUsageInLogistics.Enable(GreaterPowerUsageInLogisticsEnabled.Value);
|
||||
LogisticsConstrolPanelImprovement.Enable(LogisticsConstrolPanelImprovementEnabled.Value);
|
||||
RealtimeLogisticsInfoPanel.Enable(RealtimeLogisticsInfoPanelEnabled.Value);
|
||||
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);
|
||||
AutoConfigLogisticsSetDefaultRemoteLogicToStorage.Enable(false);
|
||||
LogisticsCapacityTweaks.Enable(false);
|
||||
AllowOverflowInLogistics.Enable(false);
|
||||
GreaterPowerUsageInLogistics.Enable(false);
|
||||
LogisticsConstrolPanelImprovement.Enable(false);
|
||||
RealtimeLogisticsInfoPanel.Enable(false);
|
||||
}
|
||||
@@ -107,16 +113,243 @@ public static class LogisticsPatch
|
||||
}
|
||||
}
|
||||
|
||||
#region Apply auto-config values to existing facilities on the current planet
|
||||
|
||||
private enum StationKind
|
||||
{
|
||||
Pls,
|
||||
Ils,
|
||||
VeinCollector
|
||||
}
|
||||
|
||||
// === Per-field setters (single source of truth, shared by auto-config-on-build and apply-to-planet) ===
|
||||
|
||||
private static void StationSetChargePower(PlanetFactory factory, StationComponent station) =>
|
||||
factory.powerSystem.consumerPool[station.pcId].workEnergyPerTick =
|
||||
(long)((station.isStellar ? 250000.0 * AutoConfigILSChargePower.Value : 50000.0 * AutoConfigPLSChargePower.Value) + 0.5);
|
||||
|
||||
private static void StationSetTripRangeDrones(PlanetFactory factory, StationComponent station) =>
|
||||
station.tripRangeDrones = Math.Cos((station.isStellar ? AutoConfigILSMaxTripDrone.Value : AutoConfigPLSMaxTripDrone.Value) / 180.0 * Math.PI);
|
||||
|
||||
private static void StationSetDeliveryDrones(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var v = station.isStellar ? AutoConfigILSDroneMinDeliver.Value : AutoConfigPLSDroneMinDeliver.Value;
|
||||
station.deliveryDrones = v == 0 ? 1 : v * 10;
|
||||
}
|
||||
|
||||
private static void StationSetPilerCount(PlanetFactory factory, StationComponent station) =>
|
||||
station.pilerCount = station.isStellar ? AutoConfigILSMinPilerValue.Value : AutoConfigPLSMinPilerValue.Value;
|
||||
|
||||
private static void StationFillDrones(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var target = station.isStellar ? AutoConfigILSDroneCount.Value : AutoConfigPLSDroneCount.Value;
|
||||
var toFill = Math.Max(0, target - station.idleDroneCount - station.workDroneCount);
|
||||
if (toFill > 0) station.idleDroneCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Drone, toFill, out _);
|
||||
}
|
||||
|
||||
private static void StationSetTripRangeShips(PlanetFactory factory, StationComponent station) =>
|
||||
station.tripRangeShips = AutoConfigILSMaxTripShip.Value switch
|
||||
{
|
||||
<= 20 => AutoConfigILSMaxTripShip.Value,
|
||||
<= 40 => AutoConfigILSMaxTripShip.Value * 2 - 20,
|
||||
_ => 10000,
|
||||
} * 2400000.0;
|
||||
|
||||
private static void StationSetWarpDistance(PlanetFactory factory, StationComponent station) =>
|
||||
station.warpEnableDist = AutoConfigILSWarperDistance.Value switch
|
||||
{
|
||||
<= 7 => AutoConfigILSWarperDistance.Value * 0.5 - 0.5,
|
||||
<= 16 => AutoConfigILSWarperDistance.Value - 4.0,
|
||||
<= 20 => AutoConfigILSWarperDistance.Value * 2 - 20.0,
|
||||
_ => 60.0,
|
||||
} * 40000.0;
|
||||
|
||||
private static void StationSetDeliveryShips(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var v = AutoConfigILSShipMinDeliver.Value;
|
||||
station.deliveryShips = v == 0 ? 1 : v * 10;
|
||||
}
|
||||
|
||||
private static void StationFillShips(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var toFill = Math.Max(0, AutoConfigILSShipCount.Value - station.idleShipCount - station.workShipCount);
|
||||
if (toFill > 0) station.idleShipCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Ship, toFill, out _);
|
||||
}
|
||||
|
||||
private static void StationSetIncludeOrbitCollector(PlanetFactory factory, StationComponent station) =>
|
||||
station.includeOrbitCollector = AutoConfigILSIncludeOrbitCollector.Value;
|
||||
|
||||
private static void StationSetWarperNecessary(PlanetFactory factory, StationComponent station) =>
|
||||
station.warperNecessary = AutoConfigILSWarperNecessary.Value;
|
||||
|
||||
/* station.minerId may not be set yet on freshly built collectors, so resolve the minerId from the EntityData. */
|
||||
private static bool VeinCollectorSetHarvestSpeed(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
ref var entity = ref factory.entityPool[station.entityId];
|
||||
if (entity.id != station.entityId || entity.minerId <= 0 || entity.minerId >= factory.factorySystem.minerCursor) return false;
|
||||
factory.factorySystem.minerPool[entity.minerId].speed = 10000 + AutoConfigVeinCollectorHarvestSpeed.Value * 1000;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void VeinCollectorSetPilerCount(PlanetFactory factory, StationComponent station) =>
|
||||
station.pilerCount = AutoConfigVeinCollectorMinPilerValue.Value;
|
||||
|
||||
private static void DispenserSetChargePower(PlanetFactory factory, DispenserComponent dispenser) =>
|
||||
factory.powerSystem.consumerPool[dispenser.pcId].workEnergyPerTick = (long)(5000.0 * AutoConfigDispenserChargePower.Value + 0.5);
|
||||
|
||||
private static void DispenserFillCouriers(PlanetFactory factory, DispenserComponent dispenser)
|
||||
{
|
||||
var toFill = Math.Max(0, AutoConfigDispenserCourierCount.Value - dispenser.idleCourierCount - dispenser.workCourierCount);
|
||||
if (toFill > 0) dispenser.idleCourierCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Bot, toFill, out _);
|
||||
}
|
||||
|
||||
private static void BattleBaseSetChargePower(PlanetFactory factory, BattleBaseComponent battleBase) =>
|
||||
factory.powerSystem.consumerPool[battleBase.pcId].workEnergyPerTick = (long)(5000.0 * AutoConfigBattleBaseChargePower.Value + 0.5);
|
||||
|
||||
// === Per-facility "apply all settings" (also used as auto-config-on-build entry point) ===
|
||||
|
||||
private static void DoConfigStation(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
if (station.isCollector) return;
|
||||
if (station.isVeinCollector)
|
||||
{
|
||||
if (VeinCollectorSetHarvestSpeed(factory, station))
|
||||
VeinCollectorSetPilerCount(factory, station);
|
||||
return;
|
||||
}
|
||||
if (!station.isStellar)
|
||||
{
|
||||
StationSetChargePower(factory, station);
|
||||
StationSetTripRangeDrones(factory, station);
|
||||
StationSetDeliveryDrones(factory, station);
|
||||
StationSetPilerCount(factory, station);
|
||||
StationFillDrones(factory, station);
|
||||
return;
|
||||
}
|
||||
StationSetChargePower(factory, station);
|
||||
StationSetTripRangeDrones(factory, station);
|
||||
StationSetTripRangeShips(factory, station);
|
||||
StationSetWarpDistance(factory, station);
|
||||
StationSetDeliveryDrones(factory, station);
|
||||
StationSetDeliveryShips(factory, station);
|
||||
StationSetPilerCount(factory, station);
|
||||
StationSetIncludeOrbitCollector(factory, station);
|
||||
StationSetWarperNecessary(factory, station);
|
||||
StationFillDrones(factory, station);
|
||||
StationFillShips(factory, station);
|
||||
}
|
||||
|
||||
// === Iterate over the current planet's facilities of a given kind ===
|
||||
|
||||
private static void ForEachStation(StationKind kind, Action<PlanetFactory, StationComponent> action)
|
||||
{
|
||||
var factory = GameMain.localPlanet?.factory;
|
||||
var transport = factory?.transport;
|
||||
var stationPool = transport?.stationPool;
|
||||
if (stationPool == null) return;
|
||||
for (var i = transport.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
var station = stationPool[i];
|
||||
if (station == null || station.id != i || station.isCollector) continue;
|
||||
var skip = kind switch
|
||||
{
|
||||
StationKind.VeinCollector => !station.isVeinCollector,
|
||||
StationKind.Ils => station.isVeinCollector || !station.isStellar,
|
||||
StationKind.Pls => station.isVeinCollector || station.isStellar,
|
||||
_ => true
|
||||
};
|
||||
if (skip) continue;
|
||||
action(factory, station);
|
||||
}
|
||||
RefreshOpenLogisticsWindows();
|
||||
}
|
||||
|
||||
private static void ForEachDispenser(Action<PlanetFactory, DispenserComponent> action)
|
||||
{
|
||||
var factory = GameMain.localPlanet?.factory;
|
||||
var transport = factory?.transport;
|
||||
var dispenserPool = transport?.dispenserPool;
|
||||
if (dispenserPool == null) return;
|
||||
for (var i = transport.dispenserCursor - 1; i > 0; i--)
|
||||
{
|
||||
var dispenser = dispenserPool[i];
|
||||
if (dispenser == null || dispenser.id != i) continue;
|
||||
action(factory, dispenser);
|
||||
}
|
||||
RefreshOpenLogisticsWindows();
|
||||
}
|
||||
|
||||
private static void ForEachBattleBase(Action<PlanetFactory, BattleBaseComponent> action)
|
||||
{
|
||||
var factory = GameMain.localPlanet?.factory;
|
||||
var battleBases = factory?.defenseSystem?.battleBases;
|
||||
if (battleBases?.buffer == null) return;
|
||||
for (var i = battleBases.cursor - 1; i > 0; i--)
|
||||
{
|
||||
var battleBase = battleBases.buffer[i];
|
||||
if (battleBase == null || battleBase.id != i) continue;
|
||||
action(factory, battleBase);
|
||||
}
|
||||
RefreshOpenLogisticsWindows();
|
||||
}
|
||||
|
||||
// Re-populate any open logistic facility detail window so applied values show immediately.
|
||||
private static void RefreshOpenLogisticsWindows()
|
||||
{
|
||||
var uiRoot = UIRoot.instance;
|
||||
if (!uiRoot) return;
|
||||
var uiGame = uiRoot.uiGame;
|
||||
if (!uiGame) return;
|
||||
var stationWindow = uiGame.stationWindow;
|
||||
if (stationWindow && stationWindow.active) stationWindow.OnStationIdChange();
|
||||
var dispenserWindow = uiGame.dispenserWindow;
|
||||
if (dispenserWindow && dispenserWindow.active) dispenserWindow.OnDispenserIdChange();
|
||||
var battleBaseWindow = uiGame.battleBaseWindow;
|
||||
if (battleBaseWindow && battleBaseWindow.active) battleBaseWindow.OnBattleBaseIdChange();
|
||||
}
|
||||
|
||||
// === Public entry points invoked by the config panel buttons ===
|
||||
|
||||
// Dispenser
|
||||
public static void ApplyDispenserChargePower() => ForEachDispenser(DispenserSetChargePower);
|
||||
public static void ApplyDispenserCourierCount() => ForEachDispenser(DispenserFillCouriers);
|
||||
public static void ApplyAllDispenser() => ForEachDispenser((f, d) => { DispenserSetChargePower(f, d); DispenserFillCouriers(f, d); });
|
||||
|
||||
// Battlefield Analysis Base
|
||||
public static void ApplyBattleBaseChargePower() => ForEachBattleBase(BattleBaseSetChargePower);
|
||||
public static void ApplyAllBattleBase() => ForEachBattleBase(BattleBaseSetChargePower);
|
||||
|
||||
// PLS
|
||||
public static void ApplyPLSChargePower() => ForEachStation(StationKind.Pls, StationSetChargePower);
|
||||
public static void ApplyPLSTripRangeDrones() => ForEachStation(StationKind.Pls, StationSetTripRangeDrones);
|
||||
public static void ApplyPLSDroneMinDeliver() => ForEachStation(StationKind.Pls, StationSetDeliveryDrones);
|
||||
public static void ApplyPLSMinPilerValue() => ForEachStation(StationKind.Pls, StationSetPilerCount);
|
||||
public static void ApplyPLSDroneCount() => ForEachStation(StationKind.Pls, StationFillDrones);
|
||||
public static void ApplyAllPLS() => ForEachStation(StationKind.Pls, DoConfigStation);
|
||||
|
||||
// ILS
|
||||
public static void ApplyILSChargePower() => ForEachStation(StationKind.Ils, StationSetChargePower);
|
||||
public static void ApplyILSTripRangeDrones() => ForEachStation(StationKind.Ils, StationSetTripRangeDrones);
|
||||
public static void ApplyILSTripRangeShips() => ForEachStation(StationKind.Ils, StationSetTripRangeShips);
|
||||
public static void ApplyILSWarpDistance() => ForEachStation(StationKind.Ils, StationSetWarpDistance);
|
||||
public static void ApplyILSDroneMinDeliver() => ForEachStation(StationKind.Ils, StationSetDeliveryDrones);
|
||||
public static void ApplyILSShipMinDeliver() => ForEachStation(StationKind.Ils, StationSetDeliveryShips);
|
||||
public static void ApplyILSMinPilerValue() => ForEachStation(StationKind.Ils, StationSetPilerCount);
|
||||
public static void ApplyILSDroneCount() => ForEachStation(StationKind.Ils, StationFillDrones);
|
||||
public static void ApplyILSShipCount() => ForEachStation(StationKind.Ils, StationFillShips);
|
||||
public static void ApplyILSIncludeOrbitCollector() => ForEachStation(StationKind.Ils, StationSetIncludeOrbitCollector);
|
||||
public static void ApplyILSWarperNecessary() => ForEachStation(StationKind.Ils, StationSetWarperNecessary);
|
||||
public static void ApplyAllILS() => ForEachStation(StationKind.Ils, DoConfigStation);
|
||||
|
||||
// Vein Collector (Advanced Mining Machine)
|
||||
public static void ApplyVeinCollectorHarvestSpeed() => ForEachStation(StationKind.VeinCollector, (f, s) => VeinCollectorSetHarvestSpeed(f, s));
|
||||
public static void ApplyVeinCollectorMinPilerValue() => ForEachStation(StationKind.VeinCollector, VeinCollectorSetPilerCount);
|
||||
public static void ApplyAllVeinCollector() => ForEachStation(StationKind.VeinCollector, DoConfigStation);
|
||||
|
||||
#endregion
|
||||
|
||||
private class AutoConfigLogistics : PatchImpl<AutoConfigLogistics>
|
||||
{
|
||||
enum KnownItemId : int
|
||||
{
|
||||
Drone = 5001,
|
||||
Ship = 5002,
|
||||
Bot = 5003,
|
||||
Warper = 1210,
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
ToggleLimitAutoReplenishCount();
|
||||
@@ -186,66 +419,6 @@ public static class LogisticsPatch
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoConfigStation(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
if (station.isCollector) return;
|
||||
if (station.isVeinCollector)
|
||||
{
|
||||
/* station.minerId is not set at this point, so we need to fetch the minerId from the EntityData */
|
||||
ref var entity = ref factory.entityPool[station.entityId];
|
||||
if (entity.id != station.entityId || entity.minerId <= 0 || entity.minerId >= factory.factorySystem.minerCursor) return;
|
||||
factory.factorySystem.minerPool[entity.minerId].speed = 10000 + AutoConfigVeinCollectorHarvestSpeed.Value * 1000;
|
||||
station.pilerCount = AutoConfigVeinCollectorMinPilerValue.Value;
|
||||
return;
|
||||
}
|
||||
int toFill;
|
||||
if (!station.isStellar)
|
||||
{
|
||||
factory.powerSystem.consumerPool[station.pcId].workEnergyPerTick = (long)(50000.0 * AutoConfigPLSChargePower.Value + 0.5);
|
||||
station.tripRangeDrones = Math.Cos(AutoConfigPLSMaxTripDrone.Value / 180.0 * Math.PI);
|
||||
station.deliveryDrones = AutoConfigPLSDroneMinDeliver.Value switch { 0 => 1, _ => AutoConfigPLSDroneMinDeliver.Value * 10 };
|
||||
station.pilerCount = AutoConfigPLSMinPilerValue.Value;
|
||||
toFill = Math.Max(0, AutoConfigPLSDroneCount.Value - station.idleDroneCount - station.workDroneCount);
|
||||
if (toFill > 0) station.idleDroneCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Drone, toFill, out _);
|
||||
return;
|
||||
}
|
||||
factory.powerSystem.consumerPool[station.pcId].workEnergyPerTick = (long)(250000.0 * AutoConfigILSChargePower.Value + 0.5);
|
||||
station.tripRangeDrones = Math.Cos(AutoConfigILSMaxTripDrone.Value / 180.0 * Math.PI);
|
||||
station.tripRangeShips = AutoConfigILSMaxTripShip.Value switch
|
||||
{
|
||||
<= 20 => AutoConfigILSMaxTripShip.Value,
|
||||
<= 40 => AutoConfigILSMaxTripShip.Value * 2 - 20,
|
||||
_ => 10000,
|
||||
} * 2400000.0;
|
||||
station.warpEnableDist = AutoConfigILSWarperDistance.Value switch
|
||||
{
|
||||
<= 7 => AutoConfigILSWarperDistance.Value * 0.5 - 0.5,
|
||||
<= 16 => AutoConfigILSWarperDistance.Value - 4.0,
|
||||
<= 20 => AutoConfigILSWarperDistance.Value * 2 - 20.0,
|
||||
_ => 60.0,
|
||||
} * 40000.0;
|
||||
station.deliveryDrones = AutoConfigILSDroneMinDeliver.Value switch { 0 => 1, _ => AutoConfigILSDroneMinDeliver.Value * 10 };
|
||||
station.deliveryShips = AutoConfigILSShipMinDeliver.Value switch { 0 => 1, _ => AutoConfigILSShipMinDeliver.Value * 10 };
|
||||
station.pilerCount = AutoConfigILSMinPilerValue.Value;
|
||||
station.includeOrbitCollector = AutoConfigILSIncludeOrbitCollector.Value;
|
||||
station.warperNecessary = AutoConfigILSWarperNecessary.Value;
|
||||
toFill = Math.Max(0, AutoConfigILSDroneCount.Value - station.idleDroneCount - station.workDroneCount);
|
||||
if (toFill > 0) station.idleDroneCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Drone, toFill, out _);
|
||||
toFill = Math.Max(0, AutoConfigILSShipCount.Value - station.idleShipCount - station.workShipCount);
|
||||
if (toFill > 0) station.idleShipCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Ship, toFill, out _);
|
||||
}
|
||||
|
||||
private static void DoConfigDispenser(PlanetFactory factory, DispenserComponent dispenser)
|
||||
{
|
||||
var toFill = Math.Max(0, AutoConfigDispenserCourierCount.Value - dispenser.idleCourierCount - dispenser.workCourierCount);
|
||||
if (toFill > 0) dispenser.idleCourierCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Bot, toFill, out _);
|
||||
}
|
||||
|
||||
private static void DoConfigBattleBase(PlanetFactory factory, BattleBaseComponent battleBase)
|
||||
{
|
||||
factory.powerSystem.consumerPool[battleBase.pcId].workEnergyPerTick = (long)(5000.0 * AutoConfigBattleBaseChargePower.Value + 0.5);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.SetDefaultParams))]
|
||||
private static void BuildTool_Addon_SetDefaultParams_Postfix(BuildTool_Addon __instance, int bpIndex)
|
||||
@@ -268,7 +441,7 @@ public static class LogisticsPatch
|
||||
private static void DefenseSystem_NewBattleBaseComponent_Postfix(DefenseSystem __instance, int __result)
|
||||
{
|
||||
if (__result <= 0) return;
|
||||
DoConfigBattleBase(__instance.factory, __instance.battleBases[__result]);
|
||||
BattleBaseSetChargePower(__instance.factory, __instance.battleBases[__result]);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
@@ -276,7 +449,7 @@ public static class LogisticsPatch
|
||||
private static void PlanetTransport_NewDispenserComponent_Postfix(PlanetTransport __instance, int __result)
|
||||
{
|
||||
if (__result <= 0) return;
|
||||
DoConfigDispenser(__instance.factory, __instance.dispenserPool[__result]);
|
||||
DispenserFillCouriers(__instance.factory, __instance.dispenserPool[__result]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,20 +485,26 @@ public static class LogisticsPatch
|
||||
{
|
||||
private static KeyCode _lastKey = KeyCode.None;
|
||||
private static long _nextKeyTick;
|
||||
private static bool _skipNextEvent;
|
||||
private static bool _skipNextUIStationStorageEvent;
|
||||
private static bool _skipNextUIControlPanelStationStorageEvent;
|
||||
private static bool _refreshingUIStationStorage;
|
||||
private static bool _refreshingUIControlPanelStationStorage;
|
||||
|
||||
private static bool UpdateKeyPressed(KeyCode code)
|
||||
{
|
||||
if (!Input.GetKey(code))
|
||||
return false;
|
||||
var main = GameMain.instance;
|
||||
if (main == null)
|
||||
return false;
|
||||
if (code != _lastKey)
|
||||
{
|
||||
_lastKey = code;
|
||||
_nextKeyTick = GameMain.instance.timei + 30;
|
||||
_nextKeyTick = main.timei + 30;
|
||||
return true;
|
||||
}
|
||||
|
||||
var currTick = GameMain.instance.timei;
|
||||
var currTick = main.timei;
|
||||
if (_nextKeyTick > currTick) return false;
|
||||
_nextKeyTick = currTick + 4;
|
||||
return true;
|
||||
@@ -388,10 +567,28 @@ public static class LogisticsPatch
|
||||
EventSystem.current.RaycastAll(new PointerEventData(EventSystem.current) { position = Input.mousePosition }, targets);
|
||||
foreach (var target in targets)
|
||||
{
|
||||
StationComponent station = null;
|
||||
int index = -1;
|
||||
PlanetFactory planetFactory = null;
|
||||
var stationStorage = target.gameObject.GetComponentInParent<UIStationStorage>();
|
||||
var station = stationStorage?.station;
|
||||
bool isControlPanelStationStorage = false;
|
||||
if (stationStorage != null)
|
||||
{
|
||||
station = stationStorage.station;
|
||||
index = stationStorage.index;
|
||||
planetFactory = stationStorage.stationWindow?.factory;
|
||||
}
|
||||
else
|
||||
{
|
||||
var controlPanelStationStorage = target.gameObject.GetComponentInParent<UIControlPanelStationStorage>();
|
||||
if (controlPanelStationStorage == null) continue;
|
||||
station = controlPanelStationStorage.station;
|
||||
index = controlPanelStationStorage.index;
|
||||
planetFactory = controlPanelStationStorage.factory;
|
||||
isControlPanelStationStorage = true;
|
||||
}
|
||||
if (station?.storage is null) continue;
|
||||
ref var storage = ref station.storage[stationStorage.index];
|
||||
ref var storage = ref station.storage[index];
|
||||
var oldMax = storage.max;
|
||||
var newMax = oldMax + delta;
|
||||
if (newMax < 0)
|
||||
@@ -407,11 +604,10 @@ public static class LogisticsPatch
|
||||
}
|
||||
else
|
||||
{
|
||||
var factory = stationStorage.stationWindow?.factory;
|
||||
if (factory == null || station.entityId <= 0 || station.entityId >= factory.entityCursor) continue;
|
||||
var modelProto = LDB.models.Select(factory.entityPool[station.entityId].modelIndex);
|
||||
if (planetFactory == null || station.entityId <= 0 || station.entityId >= planetFactory.entityCursor) continue;
|
||||
var modelProto = LDB.models.Select(planetFactory.entityPool[station.entityId].modelIndex);
|
||||
itemCountMax = modelProto == null ? 0 : modelProto.prefabDesc.stationMaxItemCount;
|
||||
itemCountMax += station.isStellar ? GameMain.history.remoteStationExtraStorage : GameMain.history.localStationExtraStorage;
|
||||
itemCountMax += station.isStellar && !station.isCollector ? GameMain.history.remoteStationExtraStorage : GameMain.history.localStationExtraStorage;
|
||||
}
|
||||
|
||||
if (newMax > itemCountMax)
|
||||
@@ -421,17 +617,61 @@ public static class LogisticsPatch
|
||||
}
|
||||
|
||||
storage.max = newMax;
|
||||
_skipNextEvent = oldMax / 100 != newMax / 100;
|
||||
if (isControlPanelStationStorage)
|
||||
{
|
||||
_skipNextUIControlPanelStationStorageEvent = oldMax / 100 != newMax / 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
_skipNextUIStationStorageEvent = oldMax / 100 != newMax / 100;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIStationStorage), "RefreshValues")]
|
||||
private static void UIStationStorage_RefreshValues_Prefix()
|
||||
{
|
||||
_refreshingUIStationStorage = true;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(UIStationStorage), "RefreshValues")]
|
||||
private static void UIStationStorage_RefreshValues_Postfix()
|
||||
{
|
||||
_refreshingUIStationStorage = false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), "RefreshValues")]
|
||||
private static void UIControlPanelStationStorage_RefreshValues_Prefix()
|
||||
{
|
||||
_refreshingUIControlPanelStationStorage = true;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), "RefreshValues")]
|
||||
private static void UIControlPanelStationStorage_RefreshValues_Postfix()
|
||||
{
|
||||
_refreshingUIControlPanelStationStorage = false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIStationStorage), nameof(UIStationStorage.OnMaxSliderValueChange))]
|
||||
private static bool UIStationStorage_OnMaxSliderValueChange_Prefix()
|
||||
{
|
||||
if (!_skipNextEvent) return true;
|
||||
_skipNextEvent = false;
|
||||
if (!_refreshingUIStationStorage && !_skipNextUIStationStorageEvent) return true;
|
||||
_skipNextUIStationStorageEvent = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.OnMaxSliderValueChange))]
|
||||
private static bool UIControlPanelStationStorage_OnMaxSliderValueChange_Prefix()
|
||||
{
|
||||
if (!_refreshingUIControlPanelStationStorage && !_skipNextUIControlPanelStationStorageEvent) return true;
|
||||
_skipNextUIControlPanelStationStorageEvent = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -452,6 +692,7 @@ public static class LogisticsPatch
|
||||
var modelIndex = factory.entityPool[stationPool[i].entityId].modelIndex;
|
||||
var maxCount = LDB.models.Select(modelIndex).prefabDesc.stationMaxItemCount;
|
||||
var oldMaxCount = maxCount + history.localStationExtraStorage - _valuelf;
|
||||
if (oldMaxCount < 1.0) continue;
|
||||
var intOldMaxCount = (int)Math.Round(oldMaxCount);
|
||||
var intNewMaxCount = maxCount + history.localStationExtraStorage;
|
||||
var ratio = intNewMaxCount / oldMaxCount;
|
||||
@@ -477,6 +718,7 @@ public static class LogisticsPatch
|
||||
var modelIndex = factory.entityPool[stationPool[i].entityId].modelIndex;
|
||||
var maxCount = LDB.models.Select(modelIndex).prefabDesc.stationMaxItemCount;
|
||||
var oldMaxCount = maxCount + history.remoteStationExtraStorage - _valuelf;
|
||||
if (oldMaxCount < 1.0) continue;
|
||||
var intOldMaxCount = (int)Math.Round(oldMaxCount);
|
||||
var intNewMaxCount = maxCount + history.remoteStationExtraStorage;
|
||||
var ratio = intNewMaxCount / oldMaxCount;
|
||||
@@ -572,6 +814,156 @@ public static class LogisticsPatch
|
||||
}
|
||||
}
|
||||
|
||||
private class GreaterPowerUsageInLogistics : PatchImpl<GreaterPowerUsageInLogistics>
|
||||
{
|
||||
protected override void OnEnable()
|
||||
{
|
||||
var window = UIRoot.instance?.uiGame?.stationWindow;
|
||||
if (window == null) return;
|
||||
window._Close();
|
||||
window.maxMiningSpeedSlider.maxValue = 27f;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
var window = UIRoot.instance?.uiGame?.stationWindow;
|
||||
if (window == null) return;
|
||||
window._Close();
|
||||
window.maxMiningSpeedSlider.maxValue = 20f;
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnStationIdChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnStationIdChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.Start().Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
Transpilers.EmitDelegate((UIStationWindow window) =>
|
||||
{
|
||||
window.maxMiningSpeedSlider.maxValue = 27f;
|
||||
})
|
||||
).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.maxChargePowerSlider))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Ldc_I4 && ci.OperandIs(0xC350)),
|
||||
new CodeMatch(OpCodes.Conv_I8)
|
||||
);
|
||||
var pos = matcher.Pos + 1;
|
||||
matcher.Advance(5).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Conv_R4),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertySetter(typeof(Slider), nameof(Slider.value)))
|
||||
);
|
||||
var pos2 = matcher.Pos + 2;
|
||||
matcher.Start().Advance(pos);
|
||||
var ldvar = matcher.InstructionAt(1).Clone();
|
||||
var locWorkEnergyPerTick = matcher.InstructionAt(-2).operand;
|
||||
matcher.RemoveInstructions(pos2 - pos).InsertAndAdvance(
|
||||
ldvar,
|
||||
new CodeInstruction(OpCodes.Ldloc_S, locWorkEnergyPerTick),
|
||||
Transpilers.EmitDelegate((UIStationWindow window, long maxWorkEnergy, long workEnergyPerTick) =>
|
||||
{
|
||||
var maxSliderValue = maxWorkEnergy / 50000L;
|
||||
window.maxChargePowerSlider.maxValue = maxSliderValue + 9;
|
||||
window.maxChargePowerSlider.minValue = maxWorkEnergy / 500000L;
|
||||
if (workEnergyPerTick <= maxWorkEnergy)
|
||||
window.maxChargePowerSlider.Set(workEnergyPerTick / 50000L, false);
|
||||
else
|
||||
window.maxChargePowerSlider.Set(maxSliderValue + (workEnergyPerTick - 1) / maxWorkEnergy + 1, false);
|
||||
})
|
||||
);
|
||||
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.maxMiningSpeedSlider))),
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.factorySystem))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.minerPool))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.minerId))),
|
||||
new CodeMatch(OpCodes.Ldelema, typeof(MinerComponent)),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(MinerComponent), nameof(MinerComponent.speed)))
|
||||
);
|
||||
pos = matcher.Pos + 9;
|
||||
matcher.Advance(5).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Conv_R4),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertySetter(typeof(Slider), nameof(Slider.value)))
|
||||
);
|
||||
pos2 = matcher.Pos;
|
||||
matcher.Start().Advance(pos).RemoveInstructions(pos2 - pos).Insert(
|
||||
Transpilers.EmitDelegate((int speed) =>
|
||||
{
|
||||
if (speed <= 30000)
|
||||
return (speed - 10000) / 1000;
|
||||
return (speed - 30000) / 10000 + 20;
|
||||
})
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnMaxMiningSpeedChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnMaxMiningSpeedChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Ldc_I4 && ci.OperandIs(10000)),
|
||||
new CodeMatch(OpCodes.Ldarg_1)
|
||||
);
|
||||
var pos = matcher.Pos;
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stloc_1)
|
||||
);
|
||||
var pos2 = matcher.Pos;
|
||||
matcher.Start().Advance(pos);
|
||||
var labels = matcher.Labels;
|
||||
matcher.RemoveInstructions(pos2 - pos);
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_1).WithLabels(labels),
|
||||
Transpilers.EmitDelegate((float value) =>
|
||||
{
|
||||
var intval = (int)(value + 0.5f);
|
||||
if (intval <= 20)
|
||||
return intval * 1000 + 10000;
|
||||
return (intval - 20) * 10000 + 30000;
|
||||
})
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnMaxChargePowerSliderValueChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnMaxChargePowerSliderValueChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.factory))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetFactory), nameof(PlanetFactory.powerSystem))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PowerSystem), nameof(PowerSystem.consumerPool)))
|
||||
);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
Transpilers.EmitDelegate((UIStationWindow window, float value) =>
|
||||
{
|
||||
float prevMax = window.workEnergyPrefab * 5L / 50000L;
|
||||
if (value <= prevMax)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return prevMax * (value - prevMax + 1);
|
||||
}),
|
||||
new CodeInstruction(OpCodes.Starg_S, 1)
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
|
||||
private class LogisticsConstrolPanelImprovement : PatchImpl<LogisticsConstrolPanelImprovement>
|
||||
{
|
||||
private static int ItemIdHintUnderMouse()
|
||||
@@ -652,7 +1044,7 @@ public static class LogisticsPatch
|
||||
}
|
||||
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Labels = [];
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
Transpilers.EmitDelegate((UIGame uiGame) =>
|
||||
@@ -681,37 +1073,37 @@ public static class LogisticsPatch
|
||||
controlPanelWindow.DetermineFilterResults();
|
||||
}
|
||||
|
||||
private static readonly Action<int>[] OnStationEntryItemIconRightClickActions = new Action<int>[5];
|
||||
private static readonly Dictionary<UIControlPanelStationEntry, Action<int>[]> OnStationEntryItemIconRightClickActionsMap = new();
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationEntry), nameof(UIControlPanelStationEntry._OnRegEvent))]
|
||||
private static void UIControlPanelStationEntry__OnRegEvent_Postfix(UIControlPanelStationEntry __instance)
|
||||
{
|
||||
OnStationEntryItemIconRightClickActions[0] = _ => OnStationEntryItemIconRightClick(__instance, 0);
|
||||
OnStationEntryItemIconRightClickActions[1] = _ => OnStationEntryItemIconRightClick(__instance, 1);
|
||||
OnStationEntryItemIconRightClickActions[2] = _ => OnStationEntryItemIconRightClick(__instance, 2);
|
||||
OnStationEntryItemIconRightClickActions[3] = _ => OnStationEntryItemIconRightClick(__instance, 3);
|
||||
OnStationEntryItemIconRightClickActions[4] = _ => OnStationEntryItemIconRightClick(__instance, 4);
|
||||
__instance.storageItem0.itemButton.onRightClick += OnStationEntryItemIconRightClickActions[0];
|
||||
__instance.storageItem1.itemButton.onRightClick += OnStationEntryItemIconRightClickActions[1];
|
||||
__instance.storageItem2.itemButton.onRightClick += OnStationEntryItemIconRightClickActions[2];
|
||||
__instance.storageItem3.itemButton.onRightClick += OnStationEntryItemIconRightClickActions[3];
|
||||
__instance.storageItem4.itemButton.onRightClick += OnStationEntryItemIconRightClickActions[4];
|
||||
var actions = new Action<int>[5];
|
||||
actions[0] = _ => OnStationEntryItemIconRightClick(__instance, 0);
|
||||
actions[1] = _ => OnStationEntryItemIconRightClick(__instance, 1);
|
||||
actions[2] = _ => OnStationEntryItemIconRightClick(__instance, 2);
|
||||
actions[3] = _ => OnStationEntryItemIconRightClick(__instance, 3);
|
||||
actions[4] = _ => OnStationEntryItemIconRightClick(__instance, 4);
|
||||
OnStationEntryItemIconRightClickActionsMap[__instance] = actions;
|
||||
__instance.storageItem0.itemButton.onRightClick += actions[0];
|
||||
__instance.storageItem1.itemButton.onRightClick += actions[1];
|
||||
__instance.storageItem2.itemButton.onRightClick += actions[2];
|
||||
__instance.storageItem3.itemButton.onRightClick += actions[3];
|
||||
__instance.storageItem4.itemButton.onRightClick += actions[4];
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationEntry), nameof(UIControlPanelStationEntry._OnUnregEvent))]
|
||||
private static void UIControlPanelStationEntry__OnUnregEvent_Postfix(UIControlPanelStationEntry __instance)
|
||||
{
|
||||
__instance.storageItem0.itemButton.onRightClick -= OnStationEntryItemIconRightClickActions[0];
|
||||
__instance.storageItem1.itemButton.onRightClick -= OnStationEntryItemIconRightClickActions[1];
|
||||
__instance.storageItem2.itemButton.onRightClick -= OnStationEntryItemIconRightClickActions[2];
|
||||
__instance.storageItem3.itemButton.onRightClick -= OnStationEntryItemIconRightClickActions[3];
|
||||
__instance.storageItem4.itemButton.onRightClick -= OnStationEntryItemIconRightClickActions[4];
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
OnStationEntryItemIconRightClickActions[i] = null;
|
||||
}
|
||||
if (!OnStationEntryItemIconRightClickActionsMap.TryGetValue(__instance, out var actions)) return;
|
||||
__instance.storageItem0.itemButton.onRightClick -= actions[0];
|
||||
__instance.storageItem1.itemButton.onRightClick -= actions[1];
|
||||
__instance.storageItem2.itemButton.onRightClick -= actions[2];
|
||||
__instance.storageItem3.itemButton.onRightClick -= actions[3];
|
||||
__instance.storageItem4.itemButton.onRightClick -= actions[4];
|
||||
OnStationEntryItemIconRightClickActionsMap.Remove(__instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,7 +1140,7 @@ public static class LogisticsPatch
|
||||
{
|
||||
var history = GameMain.history;
|
||||
if (history == null) return false;
|
||||
if (_remoteStorageExtra == history.remoteStationExtraStorage) return false;
|
||||
if (_remoteStorageExtra == history.remoteStationExtraStorage && _localStorageExtra == history.localStationExtraStorage) return false;
|
||||
_localStorageExtra = history.localStationExtraStorage;
|
||||
_remoteStorageExtra = history.remoteStationExtraStorage;
|
||||
_localStorageMaxTotal = _localStorageMax + _localStorageExtra;
|
||||
@@ -767,12 +1159,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)
|
||||
@@ -796,9 +1189,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()
|
||||
@@ -817,14 +1213,14 @@ public static class LogisticsPatch
|
||||
{
|
||||
if (!prefabDesc.isCollectStation)
|
||||
{
|
||||
_remoteStorageMax = prefabDesc.stationMaxItemCount;
|
||||
_remoteStorageMax = Math.Max(_remoteStorageMax, prefabDesc.stationMaxItemCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!prefabDesc.isVeinCollector)
|
||||
{
|
||||
_localStorageMax = prefabDesc.stationMaxItemCount;
|
||||
_localStorageMax = Math.Max(_localStorageMax, prefabDesc.stationMaxItemCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -851,12 +1247,36 @@ public static class LogisticsPatch
|
||||
rtrans.anchoredPosition3D = new Vector3(0, 0, 0f);
|
||||
|
||||
var sliderBgPrefab = GameObject.Find("UI Root/Overlay Canvas/In Game/Windows/Station Window/storage-box-0/slider-bg");
|
||||
if (sliderBgPrefab == null)
|
||||
{
|
||||
UXAssist.Logger.LogWarning("RealtimeLogisticsInfoPanel.InitGUI: slider-bg prefab not found, aborting GUI init");
|
||||
Object.Destroy(_stationTipsRoot);
|
||||
_stationTipsRoot = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_tipPrefab = Object.Instantiate(GameObject.Find("UI Root/Overlay Canvas/In Game/Scene UIs/Vein Marks/vein-tips/vein-tip-prefab"), _stationTipsRoot.transform);
|
||||
var veinTipPrefabGo = GameObject.Find("UI Root/Overlay Canvas/In Game/Scene UIs/Vein Marks/vein-tips/vein-tip-prefab");
|
||||
if (veinTipPrefabGo == null)
|
||||
{
|
||||
UXAssist.Logger.LogWarning("RealtimeLogisticsInfoPanel.InitGUI: vein-tip-prefab not found, aborting GUI init");
|
||||
Object.Destroy(_stationTipsRoot);
|
||||
_stationTipsRoot = null;
|
||||
return;
|
||||
}
|
||||
var keyTipPrefabGo = GameObject.Find("UI Root/Overlay Canvas/In Game/Windows/Key Tips/tip-prefab");
|
||||
if (keyTipPrefabGo == null)
|
||||
{
|
||||
UXAssist.Logger.LogWarning("RealtimeLogisticsInfoPanel.InitGUI: key tip-prefab not found, aborting GUI init");
|
||||
Object.Destroy(_stationTipsRoot);
|
||||
_stationTipsRoot = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_tipPrefab = Object.Instantiate(veinTipPrefabGo, _stationTipsRoot.transform);
|
||||
_tipPrefab.name = "tipPrefab";
|
||||
Object.Destroy(_tipPrefab.GetComponent<UIVeinDetailNode>());
|
||||
var image = _tipPrefab.GetComponent<Image>();
|
||||
image.sprite = GameObject.Find("UI Root/Overlay Canvas/In Game/Windows/Key Tips/tip-prefab").GetComponent<Image>().sprite;
|
||||
image.sprite = keyTipPrefabGo.GetComponent<Image>().sprite;
|
||||
image.color = new Color(0, 0, 0, 0.8f);
|
||||
image.enabled = true;
|
||||
var rectTrans = (RectTransform)_tipPrefab.transform;
|
||||
@@ -1010,49 +1430,57 @@ 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(stationTip);
|
||||
}
|
||||
ReleaseStationTip(stationTip);
|
||||
}
|
||||
|
||||
Array.Resize(ref _stationTips, 16);
|
||||
Array.Clear(_stationTips, 0, _stationTips.Length);
|
||||
_stationTips = new StationTip[16];
|
||||
}
|
||||
|
||||
private static void RecycleStationTip(int index)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var result = StationTipsRecycle[--_stationTipsRecycleCount];
|
||||
_stationTipsRecycleCount--;
|
||||
var result = StationTipsRecycle[_stationTipsRecycleCount];
|
||||
StationTipsRecycle[_stationTipsRecycleCount] = null;
|
||||
return result;
|
||||
}
|
||||
@@ -1192,6 +1620,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")]
|
||||
@@ -1222,7 +1670,7 @@ public static class LogisticsPatch
|
||||
private float _pixelPerItem;
|
||||
|
||||
private StorageItemData[] _storageItems;
|
||||
private static readonly Dictionary<int, Sprite> ItemSprites = new();
|
||||
private static readonly Dictionary<int, Sprite> ItemSprites = [];
|
||||
private static readonly Color[] StateColor = [Color.gray, SupplyColor, DemandColor];
|
||||
|
||||
private struct StorageItemData
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Emit;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UXAssist.Common;
|
||||
|
||||
namespace UXAssist.Patches;
|
||||
@@ -51,7 +53,7 @@ public class PersistPatch : PatchImpl<PersistPatch>
|
||||
);
|
||||
var ldLocOpr = matcher.Operand;
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Labels = [];
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, ldLocOpr).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Component), nameof(Component.transform))),
|
||||
@@ -169,4 +171,151 @@ public class PersistPatch : PatchImpl<PersistPatch>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fix crash in NeutronStarHandler.OnEnable()
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(NeutronStarHandler), nameof(NeutronStarHandler.OnEnable))]
|
||||
private static IEnumerable<CodeInstruction> NeutronStarHandler_OnEnable_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(NeutronStarHandler), nameof(NeutronStarHandler.streamRenderer))),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Renderer), nameof(Renderer.sharedMaterial)))
|
||||
).RemoveInstructions(3).InsertAndAdvance(
|
||||
Transpilers.EmitDelegate(() =>
|
||||
{
|
||||
return Configs.builtin.neutronStarPrefab.streamRenderer.sharedMaterial;
|
||||
})
|
||||
);
|
||||
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Disable rendering when Player is hidden (Press F11 twice)
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.LateUpdate))]
|
||||
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.Draw))]
|
||||
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.DrawPost))]
|
||||
private static IEnumerable<CodeInstruction> GameLogic_LateUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.Start();
|
||||
matcher.CreateLabel(out var label);
|
||||
matcher.InsertAndAdvance(
|
||||
Transpilers.EmitDelegate(bool () =>
|
||||
{
|
||||
return GameMain.localPlanet == null && !GameMain.mainPlayer.controller.modelVisible;
|
||||
}),
|
||||
new CodeInstruction(OpCodes.Brfalse, label),
|
||||
new CodeInstruction(OpCodes.Ret)
|
||||
);
|
||||
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(UniverseSimulator), nameof(UniverseSimulator.SetPlanetSimulator))]
|
||||
private static void UniverseSimulator_SetPlanetSimulator_Postfix(UniverseSimulator __instance, PlanetSimulator sim)
|
||||
{
|
||||
if (GameMain.localPlanet == null && !GameMain.mainPlayer.controller.modelVisible) sim.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
#region Cluster Upload Result
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MilkyWayWebClient), nameof(MilkyWayWebClient.OnUploadLoginErrored))]
|
||||
private static void MilkyWayWebClient_OnUploadLoginErrored_Postfix(MilkyWayWebClient __instance, DSPWeb.HTTP_ERROR_TYPE errorType, string errorInfo, int errorCode)
|
||||
{
|
||||
switch (errorType)
|
||||
{
|
||||
case DSPWeb.HTTP_ERROR_TYPE.NETWORK_ERROR:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-10001, 0f);
|
||||
break;
|
||||
case DSPWeb.HTTP_ERROR_TYPE.HTTP_ERROR:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-10010 - errorCode, 0f);
|
||||
break;
|
||||
case DSPWeb.HTTP_ERROR_TYPE.USER_ABORT:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-10003, 0f);
|
||||
break;
|
||||
case DSPWeb.HTTP_ERROR_TYPE.UNEXPECTED_ERROR:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-10004, 0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MilkyWayWebClient), nameof(MilkyWayWebClient.OnUploadErrored))]
|
||||
private static void MilkyWayWebClient_OnUploadErrored_Postfix(MilkyWayWebClient __instance, DSPWeb.HTTP_ERROR_TYPE errorType, string errorInfo, int errorCode)
|
||||
{
|
||||
switch (errorType)
|
||||
{
|
||||
case DSPWeb.HTTP_ERROR_TYPE.NETWORK_ERROR:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-101, 0f);
|
||||
break;
|
||||
case DSPWeb.HTTP_ERROR_TYPE.HTTP_ERROR:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-110 - errorCode, 0f);
|
||||
break;
|
||||
case DSPWeb.HTTP_ERROR_TYPE.USER_ABORT:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-103, 0f);
|
||||
break;
|
||||
case DSPWeb.HTTP_ERROR_TYPE.UNEXPECTED_ERROR:
|
||||
Functions.UIFunctions.AddClusterUploadResult(-104, 0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MilkyWayWebClient), nameof(MilkyWayWebClient.OnUploadSucceed))]
|
||||
private static void MilkyWayWebClient_OnUploadSucceed_Postfix(MilkyWayWebClient __instance, DownloadHandler handler)
|
||||
{
|
||||
if (!int.TryParse(handler.text, out var rcode))
|
||||
rcode = -1;
|
||||
Functions.UIFunctions.AddClusterUploadResult(rcode, __instance.uploadRequest == null ? 0f : (float)__instance.uploadRequest.reqTime);
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(MilkyWayCache), nameof(MilkyWayCache.LoadTopTenPlayerData))]
|
||||
private static IEnumerable<CodeInstruction> MilkyWayCache_LoadTopTenPlayerData_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_1),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(BinaryReader), nameof(BinaryReader.ReadInt32))),
|
||||
new CodeMatch(ci => ci.IsStloc())
|
||||
).Advance(2).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Dup),
|
||||
Transpilers.EmitDelegate(Functions.UIFunctions.SetTopPlayerCount)
|
||||
);
|
||||
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloca_S),
|
||||
new CodeMatch(OpCodes.Ldarg_1),
|
||||
new CodeMatch(OpCodes.Callvirt),
|
||||
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(ClusterPlayerData), nameof(ClusterPlayerData.isAnon)))
|
||||
);
|
||||
var objloc = matcher.Operand;
|
||||
matcher.Advance(4);
|
||||
var iinstr = matcher.Instruction.Clone();
|
||||
matcher.InsertAndAdvance(
|
||||
iinstr,
|
||||
new CodeInstruction(OpCodes.Ldloca_S, objloc),
|
||||
Transpilers.EmitDelegate((int index, ref ClusterPlayerData playerData) =>
|
||||
{
|
||||
Functions.UIFunctions.SetTopPlayerData(index, ref playerData);
|
||||
})
|
||||
);
|
||||
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MilkyWayCache), nameof(MilkyWayCache.LoadTopTenPlayerData))]
|
||||
private static void MilkyWayCache_LoadTopTenPlayerData_Postfix(MilkyWayCache __instance)
|
||||
{
|
||||
Functions.UIFunctions.UpdateMilkyWayTopTenPlayers();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using HarmonyLib;
|
||||
using UXAssist.Common;
|
||||
|
||||
namespace UXAssist.Patches;
|
||||
|
||||
public static class PlanetPatch
|
||||
{
|
||||
public static ConfigEntry<bool> PlayerActionsInGlobeViewEnabled;
|
||||
|
||||
@@ -98,10 +98,12 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
Label? jumpPos = null;
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(UIStarmapStar), nameof(UIStarmapStar.projectedCoord))),
|
||||
new CodeMatch(OpCodes.Ldarg_0)
|
||||
).Advance(2).MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsStloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.Branches(out jumpPos))
|
||||
);
|
||||
matcher.Advance(3);
|
||||
).Advance(3);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = [];
|
||||
matcher.CreateLabel(out var jumpPos2);
|
||||
@@ -264,7 +266,7 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
);
|
||||
matcher.CreateLabelAt(matcher.Pos + 8, out var jumpPos);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Labels = [];
|
||||
matcher.InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(ShortcutKeysForStarsName), nameof(_showAllStarsNameStatus))).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_1),
|
||||
@@ -314,7 +316,7 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
);
|
||||
matcher.CreateLabelAt(matcher.Pos + 10, out var jumpPos);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Labels = [];
|
||||
matcher.InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(ShortcutKeysForStarsName), nameof(_showAllStarsNameStatus))).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_1),
|
||||
@@ -335,9 +337,19 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
private static int _indicatorAstroId;
|
||||
private static bool _speedUp;
|
||||
private static Vector3 _direction;
|
||||
private static EMovementState _movementState = EMovementState.Walk;
|
||||
|
||||
public static int IndicatorAstroId => _indicatorAstroId;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
_canUseWarper = false;
|
||||
_indicatorAstroId = 0;
|
||||
_speedUp = false;
|
||||
_direction = Vector3.zero;
|
||||
_movementState = EMovementState.Walk;
|
||||
}
|
||||
|
||||
public static void ToggleAutoCruise()
|
||||
{
|
||||
AutoCruiseEnabled.Value = !AutoCruiseEnabled.Value;
|
||||
@@ -347,6 +359,16 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
}
|
||||
}
|
||||
|
||||
private static bool UpdateMovementState(PlayerController controller)
|
||||
{
|
||||
var movementStateChanged = controller.movementStateInFrame != _movementState;
|
||||
if (movementStateChanged)
|
||||
{
|
||||
_movementState = controller.movementStateInFrame;
|
||||
}
|
||||
return movementStateChanged;
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(PlayerController), nameof(PlayerController.GameTick))]
|
||||
private static IEnumerable<CodeInstruction> PlayerController_GameTick_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
@@ -361,8 +383,10 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
/* Update target astro if changed */
|
||||
_speedUp = false;
|
||||
var player = controller.player;
|
||||
if (player.mecha.thrusterLevel < 2) return;
|
||||
var navi = player.navigation;
|
||||
if (navi.indicatorAstroId != _indicatorAstroId)
|
||||
var astroChanged = navi.indicatorAstroId != _indicatorAstroId;
|
||||
if (astroChanged)
|
||||
{
|
||||
_indicatorAstroId = navi.indicatorAstroId;
|
||||
Functions.UIFunctions.UpdateToggleAutoCruiseCheckButtonVisiblility();
|
||||
@@ -374,25 +398,33 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
case EMovementState.Drift:
|
||||
if (!AutoCruiseEnabled.Value) return;
|
||||
if (GameMain.localStar?.astroId == _indicatorAstroId) return;
|
||||
UpdateMovementState(controller);
|
||||
/* Press jump key to fly */
|
||||
controller.input0.z = 1f;
|
||||
break;
|
||||
case EMovementState.Fly:
|
||||
if (!AutoCruiseEnabled.Value) return;
|
||||
if (GameMain.localStar?.astroId == _indicatorAstroId) return;
|
||||
UpdateMovementState(controller);
|
||||
/* Keep pressing jump and pullup key to sail */
|
||||
controller.input0.y = 1f;
|
||||
controller.input0.y = -1f;
|
||||
controller.input1.y = 1f;
|
||||
break;
|
||||
case EMovementState.Sail:
|
||||
if (VFInput._pullUp.pressing || VFInput._pushDown.pressing || VFInput._moveLeft.pressing || VFInput._moveRight.pressing ||
|
||||
(!player.warping && UIRoot.instance.uiGame.disableLockCursor && (VFInput._moveForward.pressing || VFInput._moveBackward.pressing)))
|
||||
return;
|
||||
var movementStateChanged = UpdateMovementState(controller);
|
||||
var playerPos = player.uPosition;
|
||||
var isHive = _indicatorAstroId > 1000000;
|
||||
ref var astro = ref isHive ? ref GameMain.spaceSector.astros[_indicatorAstroId - 1000000] : ref GameMain.galaxy.astrosData[_indicatorAstroId];
|
||||
var astroVec = astro.uPos - playerPos;
|
||||
var distance = astroVec.magnitude;
|
||||
astroVec = astroVec.normalized;
|
||||
if (astroChanged || movementStateChanged)
|
||||
{
|
||||
controller.actionSail.sailPoser.targetURotWanted = Quaternion.LookRotation(astroVec);
|
||||
}
|
||||
if (distance < astro.type switch
|
||||
{
|
||||
EAstroType.Planet => 800.0 + astro.uRadius,
|
||||
@@ -410,7 +442,7 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
var autoCruise = AutoCruiseEnabled.Value;
|
||||
if (GameMain.instance.timei % 6 == 0 || _direction == Vector3.zero)
|
||||
{
|
||||
_direction = astroVec.normalized;
|
||||
_direction = astroVec;
|
||||
|
||||
/* Check nearest astroes, try to bypass them */
|
||||
var localStar = GameMain.localStar;
|
||||
@@ -474,11 +506,11 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
var speed = uVel.magnitude;
|
||||
if (player.warping)
|
||||
{
|
||||
_speedUp = false;
|
||||
if (autoCruise)
|
||||
{
|
||||
/* Speed down if too close */
|
||||
var actionSail = controller.actionSail;
|
||||
_speedUp = actionSail.currentWarpSpeed < actionSail.maxWarpSpeed;
|
||||
/* Speed down if too close */
|
||||
if (distance < GalaxyData.LY * 1.5)
|
||||
{
|
||||
if (distance < actionSail.currentWarpSpeed * distance switch
|
||||
@@ -490,9 +522,14 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
})
|
||||
{
|
||||
controller.input0.y = -1f;
|
||||
_speedUp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_speedUp = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -502,6 +539,7 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
{
|
||||
player.warpCommand = true;
|
||||
VFAudio.Create("warp-begin", player.transform, Vector3.zero, true);
|
||||
controller.actionSail.sailPoser.targetURotWanted = Quaternion.LookRotation(astroVec);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -550,10 +588,7 @@ public class PlayerPatch : PatchImpl<PlayerPatch>
|
||||
[HarmonyPatch(typeof(UISailPanel), nameof(UISailPanel._OnOpen))]
|
||||
public static void OnOpen_Prefix()
|
||||
{
|
||||
if (_aimingEnabled)
|
||||
{
|
||||
UIRoot.instance.uiGame.disableLockCursor = true;
|
||||
}
|
||||
UIRoot.instance.uiGame.disableLockCursor = true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UXAssist.Common;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
@@ -63,11 +64,19 @@ public static class TechPatch
|
||||
if (on)
|
||||
{
|
||||
var delim = -26.0f;
|
||||
var x = 9.0f;
|
||||
var y = -27.0f;
|
||||
var tp3301 = techs.Select(3301);
|
||||
if (tp3301 != null && tp3301.IsObsolete)
|
||||
{
|
||||
_protoPatched = false;
|
||||
delim = tp3301.Position.y + 1.0f;
|
||||
var tp3311 = techs.Select(3311);
|
||||
if (tp3311 != null)
|
||||
{
|
||||
x = tp3311.Position.x;
|
||||
y = tp3311.Position.y;
|
||||
delim = y + 1.0f;
|
||||
}
|
||||
}
|
||||
if (_protoPatched) return;
|
||||
|
||||
@@ -78,9 +87,20 @@ public static class TechPatch
|
||||
case >= 3301 and <= 3305:
|
||||
tp.UnlockValues[0] = tp.ID - 3300 + 1;
|
||||
tp.IsObsolete = false;
|
||||
tp.Position = new Vector2(x + 4.0f * (tp.ID - 3301), y);
|
||||
if (tp.ID == 3305)
|
||||
{
|
||||
tp.postTechArray = [];
|
||||
if (UIRoot.instance.uiGame.techTree.nodes.TryGetValue(tp.ID, out var node))
|
||||
{
|
||||
node.outputLine.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case 3306:
|
||||
tp.PreTechs = [];
|
||||
tp.preTechArray = [];
|
||||
tp.Position = new Vector2(x + 4.0f * (tp.ID - 3301), y);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -114,6 +134,10 @@ public static class TechPatch
|
||||
|
||||
_protoPatched = false;
|
||||
}
|
||||
LDB.techs.Signature = ProtoSignature_0_10_30_3100.CalculateSignature(LDB.techs);
|
||||
var techTree = UIRoot.instance?.uiGame?.techTree;
|
||||
if (techTree != null && techTree.isActiveAndEnabled)
|
||||
techTree.OnPageChanged();
|
||||
}
|
||||
|
||||
private static void VFPreload_InvokeOnLoadWorkEnded_Postfix()
|
||||
@@ -245,6 +269,7 @@ public static class TechPatch
|
||||
_originTechPosts.Clear();
|
||||
_protoPatched = false;
|
||||
}
|
||||
LDB.techs.Signature = ProtoSignature_0_10_30_3100.CalculateSignature(LDB.techs);
|
||||
var nodes = UIRoot.instance.uiGame.techTree.nodes;
|
||||
var history = GameMain.history;
|
||||
foreach (var item in nodes)
|
||||
@@ -284,6 +309,9 @@ public static class TechPatch
|
||||
}
|
||||
}
|
||||
}
|
||||
var techTree = UIRoot.instance?.uiGame?.techTree;
|
||||
if (techTree != null && techTree.isActiveAndEnabled)
|
||||
techTree.OnPageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ public class UIPatch : PatchImpl<UIPatch>
|
||||
GameLogicProc.OnGameBegin += PlanetVeinUtilization.OnGameBegin;
|
||||
Enable(true);
|
||||
Functions.UIFunctions.InitMenuButtons();
|
||||
Functions.UIFunctions.InitMilkyWayTopTenPlayers();
|
||||
PlanetVeinUtilization.Enable(PlanetVeinUtilizationEnabled.Value);
|
||||
}
|
||||
|
||||
@@ -121,6 +122,7 @@ public class UIPatch : PatchImpl<UIPatch>
|
||||
#region Helper functions
|
||||
private static void ProcessVeinData(VeinTypeInfo[] veinCount, VeinData[] veinPool)
|
||||
{
|
||||
if (veinPool == null) return;
|
||||
lock (veinPool)
|
||||
{
|
||||
foreach (VeinData veinData in veinPool)
|
||||
@@ -271,21 +273,19 @@ public class UIPatch : PatchImpl<UIPatch>
|
||||
}
|
||||
foreach (PlanetData planet in __instance.star.planets)
|
||||
{
|
||||
if (planet.runtimeVeinGroups == null) { continue; }
|
||||
PlanetFactory factory = planet.factory;
|
||||
if (factory != null)
|
||||
{
|
||||
ProcessVeinData(starVeinCount, factory.veinPool);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
VeinGroup[] veinGroups = planet.veinGroups;
|
||||
if (veinGroups == null) continue;
|
||||
lock (planet.veinGroupsLock)
|
||||
{
|
||||
VeinGroup[] veinGroups = planet.runtimeVeinGroups;
|
||||
lock (planet.veinGroupsLock)
|
||||
for (int i = 1; i < veinGroups.Length; i++)
|
||||
{
|
||||
for (int i = 1; i < veinGroups.Length; i++)
|
||||
{
|
||||
starVeinCount[(int)veinGroups[i].type].numVeinGroups++;
|
||||
}
|
||||
starVeinCount[(int)veinGroups[i].type].numVeinGroups++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-2
@@ -60,10 +60,13 @@
|
||||
* Do not render factory entities (except belts and sorters)
|
||||
* This also makes players click though factory entities but belts and sorters
|
||||
* Drag building power poles in maximum connection range
|
||||
* Auto-construct
|
||||
* Fly to buildings to be contructed automatically
|
||||
* Dismantle blueprint selected buildings
|
||||
* Press shortcut key in blueprint copy mode to dismantle selected buildings.
|
||||
* The default shortcut key is Ctrl+X, you can set it in system options panel.
|
||||
* Re-intialize planet (without reseting veins)
|
||||
* Initialize This Planet (without reseting veins)
|
||||
* 3 Options to return certain items
|
||||
* Quick dismantle all buildings (without drops)
|
||||
* Quick build Orbital Collectors
|
||||
* Belt signals for buy out dark fog items automatically
|
||||
@@ -101,6 +104,9 @@
|
||||
* Real-time logistic stations info panel
|
||||
* Auto-config logistic stations
|
||||
* Auto-config buildings include: Logistics Distributor, PLS, ILS, Advanced Mining Machine
|
||||
* Apply settings to all existing facilities on the current planet
|
||||
* Each setting on the Logistics tab has an `Apply` button that pushes that single value to all facilities of that type on the current planet.
|
||||
* Each category header (Logistics Distributor, Battlefield Analysis Base, PLS, ILS, Advanced Mining Machine) has an `Apply All` button that pushes every setting of that category to all facilities of that type on the current planet.
|
||||
* Player/Mecha
|
||||
* Unlimited interactive range
|
||||
* Enable player actions in globe view
|
||||
@@ -135,6 +141,10 @@
|
||||
* Starmap view:
|
||||
* Add a star name filter, you can filter displayed star names by ores or planet types now.
|
||||
* Add a dropdown box to show all stars' distance and/or planet count.
|
||||
* Show top players in milkyway
|
||||
* The button is available on top-left corner of Milkyway View
|
||||
* Show recent milkyway upload results
|
||||
* The button is on UXAssist `General` tab.
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -216,10 +226,13 @@
|
||||
* 不渲染工厂建筑实体(除了传送带和分拣器)
|
||||
* 这也使玩家可以点穿工厂实体直接点到传送带和分拣器
|
||||
* 拖动建造电线杆时自动使用最大连接距离间隔
|
||||
* 自动建造
|
||||
* 自动飞向待建造的建筑
|
||||
* 拆除蓝图选中的建筑
|
||||
* 在蓝图复制模式下按快捷键拆除选中的建筑
|
||||
* 默认快捷键是Ctrl+X,可以在系统选项面板中设置
|
||||
* 初始化本行星(不重置矿脉)
|
||||
* 有3个可返还特定物品的选项
|
||||
* 快速拆除所有建筑(不掉落)
|
||||
* 快速建造轨道采集器
|
||||
* 用于自动购买黑雾物品的传送带信号
|
||||
@@ -258,6 +271,9 @@
|
||||
* 注意:如果你启用了`Auxilaryfunction`中的`展示物流站信息`,此功能将被隐藏
|
||||
* 自动配置物流站
|
||||
* 自动配置的建筑包括:物流配送器、行星物流站、星际物流站、高级采矿机
|
||||
* 将设置应用到当前行星上所有已建成的物流设施
|
||||
* 物流标签页上每一项设置右侧都有一个`应用`按钮,按下后将该项数值应用到当前行星上所有该类型的物流设施。
|
||||
* 每个大分类标题(物流配送器、战场分析基站、行星物流站、星际物流站、大型采矿机)右侧都有一个`应用全部`按钮,按下后将该分类的所有设置数值应用到当前行星上所有该类型的物流设施。
|
||||
* 玩家/机甲
|
||||
* 无限交互距离
|
||||
* 移除建造数量和范围限制
|
||||
@@ -292,7 +308,11 @@
|
||||
* 星图:
|
||||
* 添加星系名过滤器,现在可以按矿物或行星类型过滤显示的星系名
|
||||
* 添加了一个下拉框用以切换显示所有星系的距离和/或行星数量
|
||||
* 由于缺乏维护,整合内置了[Planet Vein Untilization](https://thunderstore.io/c/dyson-sphere-program/p/testpushpleaseignore/Planet_Vein_Utilization/),并修复了一些小错误。
|
||||
* 由于原MOD缺乏维护,整合内置了[Planet Vein Untilization](https://thunderstore.io/c/dyson-sphere-program/p/testpushpleaseignore/Planet_Vein_Utilization/),并修复了一些小错误。
|
||||
* 显示银河系发电量排行
|
||||
* 按钮位于银河视图左上角
|
||||
* 显示最近银河系上传结果
|
||||
* 按钮在UXAssist的`常规`标签页内
|
||||
|
||||
## 注意事项
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public class MyCheckButton : MonoBehaviour
|
||||
openNormalColor = tankWindow.openNormalColor;
|
||||
closeMouseOverColor = tankWindow.closeMouseOverColor;
|
||||
closePressColor = tankWindow.closePressColor;
|
||||
closeNormalColor = tankWindow.closeNormalColor;
|
||||
closeNormalColor = /*tankWindow.closeNormalColor*/ new Color(0.6557f, 0.9145f, 1f, 0.4f);
|
||||
|
||||
var go = Instantiate(UIRoot.instance.uiGame.beltWindow.reverseButton.gameObject);
|
||||
go.name = "my-checkbutton";
|
||||
@@ -259,7 +259,7 @@ public class MyCheckButton : MonoBehaviour
|
||||
{
|
||||
uiButton.transitions[0].mouseoverColor = closeMouseOverColor;
|
||||
uiButton.transitions[0].pressedColor = closePressColor;
|
||||
uiButton.transitions[0].normalColor = new Color(0.6557f, 0.9145f, 1f, 0.0627f);
|
||||
uiButton.transitions[0].normalColor = closeNormalColor;
|
||||
}
|
||||
uiButton.RefreshTransitionsImmediately();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ public class MyComboBox : MonoBehaviour
|
||||
{
|
||||
private RectTransform _rectTrans;
|
||||
private UIComboBox _comboBox;
|
||||
private Text _text;
|
||||
public Action<int> OnSelChanged;
|
||||
|
||||
private static GameObject _baseObject;
|
||||
@@ -19,24 +18,12 @@ public class MyComboBox : MonoBehaviour
|
||||
{
|
||||
if (_baseObject) return;
|
||||
var fontSource = UIRoot.instance.uiGame.buildMenu.uxFacilityCheck.transform.Find("text")?.GetComponent<Text>();
|
||||
var go = Instantiate(UIRoot.instance.optionWindow.resolutionComp.transform.parent.gameObject);
|
||||
var go = Instantiate(UIRoot.instance.optionWindow.resolutionComp.gameObject);
|
||||
go.name = "my-combobox";
|
||||
go.SetActive(false);
|
||||
|
||||
var txt = go.GetComponent<Text>();
|
||||
if (txt) txt.text = "";
|
||||
if (txt && fontSource)
|
||||
{
|
||||
txt.font = fontSource.font;
|
||||
txt.fontSize = fontSource.fontSize;
|
||||
txt.fontStyle = fontSource.fontStyle;
|
||||
txt.color = new Color(1f, 1f, 1f, 0.6f);
|
||||
}
|
||||
var localizer = go.GetComponent<Localizer>();
|
||||
if (localizer) DestroyImmediate(localizer);
|
||||
|
||||
var rect = (RectTransform)go.transform;
|
||||
var cbctrl = rect.transform.Find("ComboBox").GetComponent<UIComboBox>();
|
||||
var cbctrl = rect.GetComponent<UIComboBox>();
|
||||
foreach (var button in cbctrl.ItemButtons)
|
||||
{
|
||||
Destroy(button.gameObject);
|
||||
@@ -52,7 +39,7 @@ public class MyComboBox : MonoBehaviour
|
||||
txtComp.fontSize = fontSource.fontSize;
|
||||
txtComp.fontStyle = fontSource.fontStyle;
|
||||
}
|
||||
txtComp = cbctrl.transform.Find("Main Button")?.GetComponentInChildren<Text>();
|
||||
txtComp = rect.Find("Main Button/Text")?.GetComponent<Text>();
|
||||
if (txtComp)
|
||||
{
|
||||
txtComp.font = fontSource.font;
|
||||
@@ -73,8 +60,7 @@ public class MyComboBox : MonoBehaviour
|
||||
var cb = gameObject.AddComponent<MyComboBox>();
|
||||
var rtrans = Util.NormalizeRectWithTopLeft(cb, x, y, parent);
|
||||
cb._rectTrans = rtrans;
|
||||
cb._text = gameObject.GetComponent<Text>();
|
||||
var box = rtrans.Find("ComboBox").GetComponent<UIComboBox>();
|
||||
var box = rtrans.GetComponent<UIComboBox>();
|
||||
cb._comboBox = box;
|
||||
box.onItemIndexChange.AddListener(() => { cb.OnSelChanged?.Invoke(box.itemIndex); });
|
||||
cb.UpdateComboBoxPosition();
|
||||
@@ -90,21 +76,11 @@ public class MyComboBox : MonoBehaviour
|
||||
private void UpdateComboBoxPosition()
|
||||
{
|
||||
var rtrans = (RectTransform)_comboBox.transform;
|
||||
var oldPosition = rtrans.localPosition;
|
||||
var pwidth = _text.preferredWidth;
|
||||
rtrans.localPosition = new Vector3(pwidth + 5f, oldPosition.y, oldPosition.z);
|
||||
_rectTrans.sizeDelta = new Vector2(rtrans.localPosition.x + 5f + rtrans.sizeDelta.x, _rectTrans.sizeDelta.y);
|
||||
}
|
||||
|
||||
public void SetPrompt(string prompt)
|
||||
{
|
||||
_text.text = prompt.Translate();
|
||||
UpdateComboBoxPosition();
|
||||
_rectTrans.sizeDelta = new Vector2(rtrans.sizeDelta.x, _rectTrans.sizeDelta.y);
|
||||
}
|
||||
|
||||
public void SetFontSize(int size)
|
||||
{
|
||||
_text.fontSize = size;
|
||||
_comboBox.ItemButtons.ForEach(b => b.GetComponentInChildren<Text>().fontSize = size);
|
||||
_comboBox.m_ListItemRes.GetComponentInChildren<Text>().fontSize = size;
|
||||
var txtComp = _comboBox.transform.Find("Main Button")?.GetComponentInChildren<Text>();
|
||||
@@ -146,12 +122,6 @@ public class MyComboBox : MonoBehaviour
|
||||
config.SettingChanged += _configChanged;
|
||||
}
|
||||
|
||||
public MyComboBox WithPrompt(string prompt)
|
||||
{
|
||||
SetPrompt(prompt);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MyComboBox WithFontSize(int size)
|
||||
{
|
||||
SetFontSize(size);
|
||||
|
||||
@@ -25,7 +25,6 @@ public class MyConfigWindow : MyWindowWithTabs
|
||||
base._OnCreate();
|
||||
_windowTrans = GetComponent<RectTransform>();
|
||||
OnUICreated?.Invoke(this, _windowTrans);
|
||||
AutoFitWindowSize();
|
||||
SetCurrentTab(0);
|
||||
OnUpdateUI?.Invoke();
|
||||
}
|
||||
|
||||
@@ -79,6 +79,15 @@ public class MyFlatButton : MonoBehaviour
|
||||
return this;
|
||||
}
|
||||
|
||||
public MyFlatButton WithFontSize(int fontSize)
|
||||
{
|
||||
if (labelText != null)
|
||||
{
|
||||
labelText.fontSize = fontSize;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MyFlatButton WithTip(string tip, float delay = 1f)
|
||||
{
|
||||
uiButton.tips.type = UIButton.ItemTipType.Other;
|
||||
|
||||
+26
-28
@@ -12,35 +12,25 @@ public class MyKeyBinder : MonoBehaviour
|
||||
private ConfigEntry<KeyboardShortcut> _config;
|
||||
protected event Action OnFree;
|
||||
|
||||
[SerializeField]
|
||||
public Text functionText;
|
||||
[SerializeField] public Text functionText;
|
||||
|
||||
[SerializeField]
|
||||
public Text keyText;
|
||||
[SerializeField] public Text keyText;
|
||||
|
||||
[SerializeField]
|
||||
public InputField setTheKeyInput;
|
||||
[SerializeField] public InputField setTheKeyInput;
|
||||
|
||||
[SerializeField]
|
||||
public Toggle setTheKeyToggle;
|
||||
[SerializeField] public Toggle setTheKeyToggle;
|
||||
|
||||
[SerializeField]
|
||||
public RectTransform rectTrans;
|
||||
[SerializeField] public RectTransform rectTrans;
|
||||
|
||||
[SerializeField]
|
||||
public UIButton inputUIButton;
|
||||
[SerializeField] public UIButton inputUIButton;
|
||||
|
||||
[SerializeField]
|
||||
public Text conflictText;
|
||||
[SerializeField] public Text conflictText;
|
||||
|
||||
[SerializeField]
|
||||
public Text waitingText;
|
||||
[SerializeField] public Text waitingText;
|
||||
|
||||
[SerializeField]
|
||||
public UIButton setDefaultUIButton;
|
||||
[SerializeField] public UIButton setDefaultUIButton;
|
||||
|
||||
[SerializeField]
|
||||
public UIButton setNoneKeyUIButton;
|
||||
[SerializeField] public UIButton setNoneKeyUIButton;
|
||||
|
||||
private bool _nextNotOn;
|
||||
|
||||
@@ -135,10 +125,12 @@ public class MyKeyBinder : MonoBehaviour
|
||||
VFInput.UseEscape();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.Mouse0) || Input.GetKey(KeyCode.Mouse1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var anyKey = GetIunptKeys();
|
||||
if (anyKey || _lastKey == KeyCode.None) return false;
|
||||
var k = GetPressedKey();
|
||||
@@ -146,20 +138,24 @@ public class MyKeyBinder : MonoBehaviour
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_lastKey = KeyCode.None;
|
||||
|
||||
_config.Value = KeyboardShortcut.Deserialize(k);
|
||||
//keyText.text = k;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private KeyCode _lastKey;
|
||||
private static readonly KeyCode[] ModKeys = { KeyCode.RightShift, KeyCode.LeftShift,
|
||||
KeyCode.RightControl, KeyCode.LeftControl,
|
||||
KeyCode.RightAlt, KeyCode.LeftAlt,
|
||||
KeyCode.LeftCommand, KeyCode.LeftApple, KeyCode.LeftWindows,
|
||||
KeyCode.RightCommand, KeyCode.RightApple, KeyCode.RightWindows };
|
||||
|
||||
private static readonly KeyCode[] ModKeys =
|
||||
[
|
||||
KeyCode.RightShift, KeyCode.LeftShift,
|
||||
KeyCode.RightControl, KeyCode.LeftControl,
|
||||
KeyCode.RightAlt, KeyCode.LeftAlt,
|
||||
KeyCode.LeftCommand, KeyCode.LeftApple, KeyCode.LeftWindows,
|
||||
KeyCode.RightCommand, KeyCode.RightApple, KeyCode.RightWindows
|
||||
];
|
||||
|
||||
private string GetPressedKey()
|
||||
{
|
||||
@@ -168,6 +164,7 @@ public class MyKeyBinder : MonoBehaviour
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var mod = "";
|
||||
foreach (var modKey in ModKeys)
|
||||
{
|
||||
@@ -181,6 +178,7 @@ public class MyKeyBinder : MonoBehaviour
|
||||
{
|
||||
key += mod;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -195,8 +193,8 @@ public class MyKeyBinder : MonoBehaviour
|
||||
_lastKey = item;
|
||||
anyKey = true;
|
||||
}
|
||||
return anyKey;
|
||||
|
||||
return anyKey;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
@@ -234,4 +232,4 @@ public class MyKeyBinder : MonoBehaviour
|
||||
{
|
||||
keyText.text = _config.Value.Serialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-3
@@ -30,7 +30,7 @@ public class MyWindow : ManualBehaviour
|
||||
var go = Instantiate(UIRoot.instance.uiGame.inserterWindow.gameObject);
|
||||
go.SetActive(false);
|
||||
go.name = "my-window";
|
||||
Destroy(go.GetComponent<UITankWindow>());
|
||||
Destroy(go.GetComponent<UIInserterWindow>());
|
||||
for (var i = go.transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
var child = go.transform.GetChild(i).gameObject;
|
||||
@@ -63,6 +63,11 @@ public class MyWindow : ManualBehaviour
|
||||
return (T)win;
|
||||
}
|
||||
|
||||
public override void _OnOpen()
|
||||
{
|
||||
AutoFitWindowSize();
|
||||
}
|
||||
|
||||
public override void _OnFree()
|
||||
{
|
||||
OnFree?.Invoke();
|
||||
@@ -99,6 +104,15 @@ public class MyWindow : ManualBehaviour
|
||||
{
|
||||
var trans = GetComponent<RectTransform>();
|
||||
trans.sizeDelta = new Vector2(_maxX + Margin + TabWidth + Spacing + Margin, MaxY + TitleHeight + Margin);
|
||||
// var panelBgTrans = trans.Find("panel-bg")?.GetComponent<RectTransform>();
|
||||
// if (panelBgTrans != null)
|
||||
// {
|
||||
// panelBgTrans.anchorMax = new Vector2(0f, 1f);
|
||||
// panelBgTrans.anchorMin = new Vector2(0f, 1f);
|
||||
// panelBgTrans.pivot = new Vector2(0f, 1f);
|
||||
// panelBgTrans.localPosition = new Vector3(0f, 0f, 0f);
|
||||
// panelBgTrans.sizeDelta = new Vector2(_maxX + Margin + TabWidth + Spacing + Margin, MaxY + TitleHeight + Margin);
|
||||
// }
|
||||
}
|
||||
|
||||
private static void AddElement(float x, float y, RectTransform rect, RectTransform parent = null)
|
||||
@@ -212,9 +226,9 @@ public class MyWindow : ManualBehaviour
|
||||
return cb;
|
||||
}
|
||||
|
||||
public MyComboBox AddComboBox(float x, float y, RectTransform parent, string label = "", int fontSize = 15)
|
||||
public MyComboBox AddComboBox(float x, float y, RectTransform parent, int fontSize = 15)
|
||||
{
|
||||
var comboBox = MyComboBox.CreateComboBox(x, y, parent).WithPrompt(label).WithFontSize(fontSize);
|
||||
var comboBox = MyComboBox.CreateComboBox(x, y, parent).WithFontSize(fontSize);
|
||||
_maxX = Math.Max(_maxX, x + comboBox.Width);
|
||||
MaxY = Math.Max(MaxY, y + comboBox.Height);
|
||||
return comboBox;
|
||||
|
||||
+109
-10
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UXAssist.Common;
|
||||
using UXAssist.Functions;
|
||||
using UXAssist.ModsCompat;
|
||||
@@ -47,6 +48,7 @@ public static class UIConfigWindow
|
||||
I18N.Add("Normal", "Normal", "正常");
|
||||
I18N.Add("Below Normal", "Below Normal", "低于正常");
|
||||
I18N.Add("Idle", "Idle", "空闲");
|
||||
I18N.Add("Show recent milkyway upload results", "Show recent milkyway upload results", "显示最近的银河系发电数据上传结果");
|
||||
I18N.Add("Unlimited interactive range", "Unlimited interactive range", "无限交互距离");
|
||||
I18N.Add("Night Light", "Sunlight at night", "夜间日光灯");
|
||||
I18N.Add("Angle X:", "Angle X:", "入射角度X:");
|
||||
@@ -70,7 +72,11 @@ public static class UIConfigWindow
|
||||
I18N.Add("Do not render factory entities", "Do not render factory entities (except belts and sorters)", "不渲染工厂建筑实体(除了传送带和分拣器)");
|
||||
I18N.Add("Drag building power poles in maximum connection range", "Drag building power poles in maximum connection range", "拖动建造电线杆时自动使用最大连接距离间隔");
|
||||
I18N.Add("Build Tesla Tower and Wireless Power Tower alternately", "Build Tesla Tower and Wireless Power Tower alternately", "交替建造电力感应塔和无线输电塔");
|
||||
I18N.Add("Auto-construct button", "Auto-construct button", "自动建造按钮");
|
||||
I18N.Add("Belt signals for buy out dark fog items automatically", "Belt signals for buy out dark fog items automatically", "用于自动购买黑雾物品的传送带信号");
|
||||
I18N.Add("Ctrl+Shift+Click to pick items from whole belts", "Ctrl+Shift+Click to pick items from whole belts", "按住Ctrl+Shift点击从整条传送带抓取物品");
|
||||
I18N.Add("Include branches of belts", "Include branches of belts", "包含传送带分支");
|
||||
I18N.Add("Include connected inserters", "Include connected inserters (and their connected belts if above is checked)", "包含连接的分拣器(若勾选上面的选项则包含分拣器连接的传送带)");
|
||||
I18N.Add("Auto-config logistic stations", "Auto-config logistic stations", "自动配置物流设施");
|
||||
I18N.Add("Limit auto-replenish count to values below", "Limit auto-replenish count to values below", "限制自动补充数量为下面配置的值");
|
||||
I18N.Add("Dispenser", "Logistics Distributor", "物流配送器");
|
||||
@@ -88,14 +94,19 @@ public static class UIConfigWindow
|
||||
I18N.Add("Vessel transport range", "Vessel transport range", "运输船最远路程");
|
||||
I18N.Add("Warp distance", "Warp distance", "曲速启用路程");
|
||||
I18N.Add("Min. Load of Vessels", "Min. Load of Vessels", "运输船起送量");
|
||||
I18N.Add("Outgoing integration count", "Outgoing integration count", "输出货物集装数量");
|
||||
I18N.Add("Include Orbital Collector", "Include Orbital Collector", "包含轨道采集器");
|
||||
I18N.Add("Warpers required", "Warpers required", "翘曲器必备");
|
||||
I18N.Add("Count of Vessels filled", "Count of Vessels filled", "填充的运输船数量");
|
||||
I18N.Add("Collecting Speed", "Collecting Speed", "开采速度");
|
||||
I18N.Add("Min. Piler Value", "Outgoing integration count", "输出货物集装数量");
|
||||
I18N.Add("Apply config to planet", "Apply", "应用");
|
||||
I18N.Add("Apply all config to planet", "Apply All", "应用全部");
|
||||
I18N.Add("Apply config to planet tips", "Apply this value to all facilities of this type on the current planet", "将此项数值应用到当前行星上所有该类型物流设施");
|
||||
I18N.Add("Apply all config to planet tips", "Apply all settings of this category to all facilities of this type on the current planet", "将本分类的所有设置数值应用到当前行星上所有该类型物流设施");
|
||||
|
||||
I18N.Add("Allow overflow for Logistic Stations and Advanced Mining Machines", "Allow overflow for Logistic Stations and Advanced Mining Machines", "允许物流站和大型采矿机物品溢出");
|
||||
I18N.Add("Increase maximum power usage in Logistic Stations and Advanced Mining Machines", "Increase maximum power usage in Logistic Stations and Advanced Mining Machines",
|
||||
"提升物流塔和大型采矿机的最大功耗");
|
||||
I18N.Add("Enhance control for logistic storage capacities", "Enhance control for logistic storage capacities", "物流塔存储容量控制改进");
|
||||
I18N.Add("Enhance control for logistic storage capacities tips",
|
||||
"Logistic storage capacity limits are not scaled on upgrading 'Logistics Carrier Capacity', if they are not set to maximum capacity or already greater than upgraded maximum capacity.\nUse arrow keys to adjust logistic storage capacities:\n \u2190/\u2192: -/+10 \u2193\u2191: -/+100",
|
||||
@@ -125,6 +136,9 @@ public static class UIConfigWindow
|
||||
I18N.Add("Treat stack items as single in monitor components", "Treat stack items as single in monitor components", "在流速计中将堆叠物品视为单个物品");
|
||||
I18N.Add("Initialize This Planet", "Initialize this planet", "初始化本行星");
|
||||
I18N.Add("Initialize This Planet Confirm", "This operation will destroy all buildings and revert terrains on this planet, are you sure?", "此操作将会摧毁本行星上的所有建筑并恢复地形,确定吗?");
|
||||
I18N.Add("Return buildings to player when initializing planet", "Return buildings to player when initializing planet", "初始化行星时将建筑归还给玩家");
|
||||
I18N.Add("Return logistic storage items to player when initializing planet", "Return logistic storage items to player when initializing planet", "初始化行星时将物流塔存储的物品归还给玩家");
|
||||
I18N.Add("Return belt and factory items to player when initializing planet", "Return belt and factory items to player when initializing planet", "初始化行星时将传送带和工厂里的物品归还给玩家");
|
||||
I18N.Add("Dismantle All Buildings", "Dismantle all buildings", "拆除所有建筑");
|
||||
I18N.Add("Dismantle All Buildings Confirm", "This operation will dismantle all buildings on this planet, are you sure?", "此操作将会拆除本行星上的所有建筑,确定吗?");
|
||||
I18N.Add("Quick build Orbital Collectors", "Quick build Orbital Collectors", "快速建造轨道采集器");
|
||||
@@ -319,6 +333,8 @@ public static class UIConfigWindow
|
||||
wnd.AddInputField(x + 2f, y, 200f, tab1, GamePatch.DefaultProfileName, 15, "input-profile-save-folder");
|
||||
y += 18f;
|
||||
}
|
||||
y += 36f;
|
||||
wnd.AddButton(x, y, 200f, tab1, "Show recent milkyway upload results", 16, "button-show-recent-milkyway-upload-results", () => UIFunctions.ShowRecentMilkywayUploadResults());
|
||||
if (!BulletTimeWrapper.HasBulletTime)
|
||||
{
|
||||
y += 36f;
|
||||
@@ -330,7 +346,8 @@ public static class UIConfigWindow
|
||||
x = 0f;
|
||||
}
|
||||
y += 36f;
|
||||
wnd.AddComboBox(x + 2f, y, tab1, "Process priority").WithItems("High", "Above Normal", "Normal", "Below Normal", "Idle").WithSize(100f, 0f).WithConfigEntry(WindowFunctions.ProcessPriority);
|
||||
txt = wnd.AddText2(x + 2f, y, tab1, "Process priority", 15, "process-priority");
|
||||
wnd.AddComboBox(x + 7f + txt.preferredWidth, y, tab1).WithItems("High", "Above Normal", "Normal", "Below Normal", "Idle").WithSize(100f, 0f).WithConfigEntry(WindowFunctions.ProcessPriority);
|
||||
|
||||
var tab2 = wnd.AddTab(trans, "Factory");
|
||||
x = 0f;
|
||||
@@ -404,12 +421,40 @@ public static class UIConfigWindow
|
||||
}
|
||||
}
|
||||
|
||||
y += 36f;
|
||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.AutoConstructButtonEnabled, "Auto-construct button");
|
||||
|
||||
{
|
||||
y += 36f;
|
||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.PressShiftToTakeWholeBeltItemsEnabled, "Ctrl+Shift+Click to pick items from whole belts");
|
||||
y += 27f;
|
||||
var includeBranches = wnd.AddCheckBox(x + 10, y, tab2, FactoryPatch.PressShiftToTakeWholeBeltItemsIncludeBranches, "Include branches of belts", 13);
|
||||
y += 27f;
|
||||
var includeInserters = wnd.AddCheckBox(x + 10, y, tab2, FactoryPatch.PressShiftToTakeWholeBeltItemsIncludeInserters, "Include connected inserters", 13);
|
||||
FactoryPatch.PressShiftToTakeWholeBeltItemsEnabled.SettingChanged += PressShiftToTakeWholeBeltItemsEnabledChanged;
|
||||
wnd.OnFree += () => { FactoryPatch.PressShiftToTakeWholeBeltItemsEnabled.SettingChanged -= PressShiftToTakeWholeBeltItemsEnabledChanged; };
|
||||
PressShiftToTakeWholeBeltItemsEnabledChanged(null, null);
|
||||
|
||||
void PressShiftToTakeWholeBeltItemsEnabledChanged(object o, EventArgs e)
|
||||
{
|
||||
includeBranches.SetEnable(FactoryPatch.PressShiftToTakeWholeBeltItemsEnabled.Value);
|
||||
includeInserters.SetEnable(FactoryPatch.PressShiftToTakeWholeBeltItemsEnabled.Value);
|
||||
}
|
||||
}
|
||||
|
||||
x = 400f;
|
||||
y = 10f;
|
||||
wnd.AddButton(x, y, tab2, "Initialize This Planet", 16, "button-init-planet", () =>
|
||||
UIMessageBox.Show("Initialize This Planet".Translate(), "Initialize This Planet Confirm".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.QUESTION, null,
|
||||
() => { PlanetFunctions.RecreatePlanet(true); })
|
||||
);
|
||||
y += 24f;
|
||||
wnd.AddCheckBox(x + 10f, y, tab2, PlanetFunctions.ReturnBuildingsOnInitializeEnabled, "Return buildings to player when initializing planet", 13);
|
||||
y += 24f;
|
||||
wnd.AddCheckBox(x + 10f, y, tab2, PlanetFunctions.ReturnLogisticStorageItemsOnInitializeEnabled, "Return logistic storage items to player when initializing planet", 13);
|
||||
y += 24f;
|
||||
wnd.AddCheckBox(x + 10f, y, tab2, PlanetFunctions.ReturnBeltAFactoryItemsOnInitializeEnabled, "Return belt and factory items to player when initializing planet", 13);
|
||||
|
||||
y += 36f;
|
||||
wnd.AddButton(x, y, tab2, "Dismantle All Buildings", 16, "button-dismantle-all", () =>
|
||||
UIMessageBox.Show("Dismantle All Buildings".Translate(), "Dismantle All Buildings Confirm".Translate(), "取消".Translate(), "确定".Translate(), UIMessageBox.QUESTION, null,
|
||||
@@ -470,7 +515,6 @@ public static class UIConfigWindow
|
||||
FactoryPatch.TweakBuildingBufferEnabled.SettingChanged += TweakBuildingBufferChanged;
|
||||
wnd.OnFree += () => { FactoryPatch.TweakBuildingBufferEnabled.SettingChanged -= TweakBuildingBufferChanged; };
|
||||
TweakBuildingBufferChanged(null, null);
|
||||
|
||||
void TweakBuildingBufferChanged(object o, EventArgs e)
|
||||
{
|
||||
assemblerBufferTimeMultiplierSlider.SetEnable(FactoryPatch.TweakBuildingBufferEnabled.Value);
|
||||
@@ -492,6 +536,8 @@ public static class UIConfigWindow
|
||||
wnd.AddTipsButton2(x + checkBoxForMeasureTextWidth.Width + 5f, y + 6f, tab3, "Enhance control for logistic storage capacities", "Enhance control for logistic storage capacities tips", "enhanced-logistic-capacities-tips");
|
||||
y += 36f;
|
||||
wnd.AddCheckBox(x, y, tab3, LogisticsPatch.AllowOverflowInLogisticsEnabled, "Allow overflow for Logistic Stations and Advanced Mining Machines");
|
||||
y += 30f;
|
||||
wnd.AddCheckBox(x, y, tab3, LogisticsPatch.GreaterPowerUsageInLogisticsEnabled, "Increase maximum power usage in Logistic Stations and Advanced Mining Machines");
|
||||
y += 36f;
|
||||
checkBoxForMeasureTextWidth = wnd.AddCheckBox(x, y, tab3, LogisticsPatch.LogisticsConstrolPanelImprovementEnabled, "Logistics Control Panel Improvement");
|
||||
wnd.AddTipsButton2(x + checkBoxForMeasureTextWidth.Width + 5f, y + 6f, tab3, "Logistics Control Panel Improvement", "Logistics Control Panel Improvement tips", "lcp-improvement-tips");
|
||||
@@ -536,6 +582,7 @@ public static class UIConfigWindow
|
||||
y += 16f;
|
||||
var maxWidth = 0f;
|
||||
wnd.AddText2(10f, y, tab3, "Dispenser", 14, "text-dispenser");
|
||||
var dispenserCatY = y;
|
||||
y += 18f;
|
||||
var oy = y;
|
||||
x = 20f;
|
||||
@@ -546,11 +593,13 @@ public static class UIConfigWindow
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
y += 18f;
|
||||
wnd.AddText2(10f, y, tab3, "Battlefield Analysis Base", 14, "text-battlefield-analysis-base");
|
||||
var battleBaseCatY = y;
|
||||
y += 18f;
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Max. Charging Power", 13, "text-battlefield-analysis-base-max-charging-power");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
y += 18f;
|
||||
wnd.AddText2(10f, y, tab3, "PLS", 14, "text-pls");
|
||||
var plsCatY = y;
|
||||
y += 18f;
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Max. Charging Power", 13, "text-pls-max-charging-power");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
@@ -568,6 +617,7 @@ public static class UIConfigWindow
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
y += 18f;
|
||||
wnd.AddText2(10f, y, tab3, "ILS", 14, "text-ils");
|
||||
var ilsCatY = y;
|
||||
y += 18f;
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Max. Charging Power", 13, "text-ils-max-charging-power");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
@@ -577,11 +627,9 @@ public static class UIConfigWindow
|
||||
y += 18f;
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Vessel transport range", 13, "text-ils-vessel-transport-range");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
wnd.AddCheckBox(x + 360f, y + 6f, tab3, LogisticsPatch.AutoConfigILSIncludeOrbitCollector, "Include Orbital Collector", 13).WithSmallerBox();
|
||||
y += 18f;
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Warp distance", 13, "text-ils-warp-distance");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
wnd.AddCheckBox(x + 360f, y + 6f, tab3, LogisticsPatch.AutoConfigILSWarperNecessary, "Warpers required", 13).WithSmallerBox();
|
||||
y += 18f;
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Min. Load of Drones", 13, "text-ils-min-load-of-drones");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
@@ -599,6 +647,7 @@ public static class UIConfigWindow
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
y += 18f;
|
||||
wnd.AddText2(10f, y, tab3, "Advanced Mining Machine", 14, "text-amm");
|
||||
var ammCatY = y;
|
||||
y += 18f;
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Collecting Speed", 13, "text-amm-collecting-speed");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
@@ -606,44 +655,96 @@ public static class UIConfigWindow
|
||||
textForMeasureTextWidth = wnd.AddText2(x, y, tab3, "Min. Piler Value", 13, "text-amm-min-piler-value");
|
||||
maxWidth = Mathf.Max(maxWidth, textForMeasureTextWidth.preferredWidth);
|
||||
y = oy + 1;
|
||||
var nx = x + maxWidth + 5f;
|
||||
var nx = x + maxWidth + 5f + 10f;
|
||||
const float applyBtnWidth = 44f;
|
||||
const float applyBtnHeight = 15f;
|
||||
const int applyBtnFontSize = 11;
|
||||
const float applyAllBtnWidth = 58f;
|
||||
var applyBtnX = nx + 265f;
|
||||
// Right-align the wider "Apply All" buttons with the right edge of the per-option "Apply" buttons.
|
||||
var applyAllBtnX = applyBtnX + applyBtnWidth - applyAllBtnWidth;
|
||||
var checkBoxX = applyBtnX + applyBtnWidth + 12f;
|
||||
|
||||
// Buttons are vertically centered on their row (NormalizeRectWithTopLeft places y at the top edge).
|
||||
void AddApplyButtonAt(float bx, float rowY, string objName, UnityAction onClick) =>
|
||||
wnd.AddFlatButton(bx, rowY + 6f, tab3, "Apply config to planet", applyBtnFontSize, objName, onClick).WithSize(applyBtnWidth, applyBtnHeight)
|
||||
.WithFontSize(applyBtnFontSize).WithTip("Apply config to planet tips".Translate());
|
||||
|
||||
void AddApplyButton(float rowY, string objName, UnityAction onClick) => AddApplyButtonAt(applyBtnX, rowY, objName, onClick);
|
||||
|
||||
void AddCategoryApplyButton(float catY, string objName, UnityAction onClick) =>
|
||||
wnd.AddFlatButton(applyAllBtnX, catY + 7f, tab3, "Apply all config to planet", applyBtnFontSize, objName, onClick).WithSize(applyAllBtnWidth, applyBtnHeight)
|
||||
.WithFontSize(applyBtnFontSize).WithTip("Apply all config to planet tips".Translate());
|
||||
|
||||
AddCategoryApplyButton(dispenserCatY, "btn-apply-all-dispenser", LogisticsPatch.ApplyAllDispenser);
|
||||
AddCategoryApplyButton(battleBaseCatY, "btn-apply-all-battle-base", LogisticsPatch.ApplyAllBattleBase);
|
||||
AddCategoryApplyButton(plsCatY, "btn-apply-all-pls", LogisticsPatch.ApplyAllPLS);
|
||||
AddCategoryApplyButton(ilsCatY, "btn-apply-all-ils", LogisticsPatch.ApplyAllILS);
|
||||
AddCategoryApplyButton(ammCatY, "btn-apply-all-amm", LogisticsPatch.ApplyAllVeinCollector);
|
||||
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigDispenserChargePower, new AutoConfigDispenserChargePowerMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-dispenser-charge-power", LogisticsPatch.ApplyDispenserChargePower);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigDispenserCourierCount, new MyWindow.RangeValueMapper<int>(0, 10), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-dispenser-courier-count", LogisticsPatch.ApplyDispenserCourierCount);
|
||||
y += 36f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigBattleBaseChargePower, new AutoConfigBattleBaseChargePowerMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-battle-base-charge-power", LogisticsPatch.ApplyBattleBaseChargePower);
|
||||
y += 36f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigPLSChargePower, new AutoConfigPLSChargePowerMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-pls-charge-power", LogisticsPatch.ApplyPLSChargePower);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigPLSMaxTripDrone, new MyWindow.RangeValueMapper<int>(1, 180), "0°", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-pls-trip-range-drones", LogisticsPatch.ApplyPLSTripRangeDrones);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigPLSDroneMinDeliver, new AutoConfigCarrierMinDeliverMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-pls-drone-min-deliver", LogisticsPatch.ApplyPLSDroneMinDeliver);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigPLSMinPilerValue, new AutoConfigMinPilerValueMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-pls-min-piler-value", LogisticsPatch.ApplyPLSMinPilerValue);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigPLSDroneCount, new MyWindow.RangeValueMapper<int>(0, 50), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-pls-drone-count", LogisticsPatch.ApplyPLSDroneCount);
|
||||
y += 36f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSChargePower, new AutoConfigILSChargePowerMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-charge-power", LogisticsPatch.ApplyILSChargePower);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSMaxTripDrone, new MyWindow.RangeValueMapper<int>(1, 180), "0°", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-trip-range-drones", LogisticsPatch.ApplyILSTripRangeDrones);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSMaxTripShip, new AutoConfigILSMaxTripShipMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-trip-range-ships", LogisticsPatch.ApplyILSTripRangeShips);
|
||||
var includeOrbitCollectorCheckBox = wnd.AddCheckBox(checkBoxX, y + 4f, tab3, LogisticsPatch.AutoConfigILSIncludeOrbitCollector, "Include Orbital Collector", 13).WithSmallerBox();
|
||||
var includeOrbitCollectorY = y;
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSWarperDistance, new AutoConfigILSWarperDistanceMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-warp-distance", LogisticsPatch.ApplyILSWarpDistance);
|
||||
var warperNecessaryCheckBox = wnd.AddCheckBox(checkBoxX, y + 4f, tab3, LogisticsPatch.AutoConfigILSWarperNecessary, "Warpers required", 13).WithSmallerBox();
|
||||
// Align both checkbox "Apply" buttons in a common column after the widest checkbox label.
|
||||
var checkBoxApplyBtnX = checkBoxX + Mathf.Max(includeOrbitCollectorCheckBox.Width, warperNecessaryCheckBox.Width) + 10f;
|
||||
AddApplyButtonAt(checkBoxApplyBtnX, includeOrbitCollectorY, "btn-apply-ils-include-orbit-collector", LogisticsPatch.ApplyILSIncludeOrbitCollector);
|
||||
AddApplyButtonAt(checkBoxApplyBtnX, y, "btn-apply-ils-warper-necessary", LogisticsPatch.ApplyILSWarperNecessary);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSDroneMinDeliver, new AutoConfigCarrierMinDeliverMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-drone-min-deliver", LogisticsPatch.ApplyILSDroneMinDeliver);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSShipMinDeliver, new AutoConfigCarrierMinDeliverMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-ship-min-deliver", LogisticsPatch.ApplyILSShipMinDeliver);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSMinPilerValue, new AutoConfigMinPilerValueMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-min-piler-value", LogisticsPatch.ApplyILSMinPilerValue);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSDroneCount, new MyWindow.RangeValueMapper<int>(0, 100), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-drone-count", LogisticsPatch.ApplyILSDroneCount);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigILSShipCount, new MyWindow.RangeValueMapper<int>(0, 10), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-ils-ship-count", LogisticsPatch.ApplyILSShipCount);
|
||||
y += 36f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigVeinCollectorHarvestSpeed, new AutoConfigVeinCollectorHarvestSpeedMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-amm-harvest-speed", LogisticsPatch.ApplyVeinCollectorHarvestSpeed);
|
||||
y += 18f;
|
||||
wnd.AddSideSlider(nx, y, tab3, LogisticsPatch.AutoConfigVeinCollectorMinPilerValue, new AutoConfigMinPilerValueMapper(), "G", 150f, -100f).WithFontSize(13);
|
||||
AddApplyButton(y, "btn-apply-amm-min-piler-value", LogisticsPatch.ApplyVeinCollectorMinPilerValue);
|
||||
x = 0f;
|
||||
|
||||
var tab4 = wnd.AddTab(trans, "Player/Mecha");
|
||||
@@ -729,8 +830,7 @@ public static class UIConfigWindow
|
||||
x = 10;
|
||||
y = 10;
|
||||
wnd.AddCheckBox(x, y, tab6, UIPatch.PlanetVeinUtilizationEnabled, "Planet vein utilization");
|
||||
y += 36f;
|
||||
y += 36f;
|
||||
y += 72f;
|
||||
wnd.AddCheckBox(x, y, tab6, TechPatch.BatchBuyoutTechEnabled, "Buy out techs with their prerequisites");
|
||||
y += 36f;
|
||||
wnd.AddCheckBox(x, y, tab6, TechPatch.SorterCargoStackingEnabled, "Restore upgrades of \"Sorter Cargo Stacking\" on panel");
|
||||
@@ -740,8 +840,7 @@ public static class UIConfigWindow
|
||||
wnd.AddButton(x, y, 300f, tab6, "Set \"Sorter Cargo Stacking\" to unresearched state", 16, "button-remove-cargo-stacking", TechFunctions.RemoveCargoStackingTechs);
|
||||
y += 36f;
|
||||
wnd.AddButton(x, y, 300f, tab6, "Unlock all techs with metadata", 16, "button-unlock-all-techs-with-metadata", TechFunctions.UnlockAllProtoWithMetadataAndPrompt);
|
||||
y += 36f;
|
||||
y += 36f;
|
||||
y += 72f;
|
||||
wnd.AddButton(x, y, 300f, tab6, "Open Dark Fog Communicator", 16, "button-open-df-communicator", () =>
|
||||
{
|
||||
if (!(GameMain.data?.gameDesc.isCombatMode ?? false)) return;
|
||||
|
||||
+32
-2
@@ -33,12 +33,13 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
private readonly Harmony _harmony = new(PluginInfo.PLUGIN_GUID);
|
||||
|
||||
#region IModCanSave
|
||||
private const ushort ModSaveVersion = 1;
|
||||
private const ushort ModSaveVersion = 2;
|
||||
|
||||
public void Export(BinaryWriter w)
|
||||
{
|
||||
w.Write(ModSaveVersion);
|
||||
FactoryPatch.Export(w);
|
||||
UIFunctions.ExportClusterUploadResults(w);
|
||||
}
|
||||
|
||||
public void Import(BinaryReader r)
|
||||
@@ -46,6 +47,14 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
var version = r.ReadUInt16();
|
||||
if (version <= 0) return;
|
||||
FactoryPatch.Import(r);
|
||||
if (version > 1)
|
||||
{
|
||||
UIFunctions.ImportClusterUploadResults(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
UIFunctions.ClearClusterUploadResults();
|
||||
}
|
||||
}
|
||||
|
||||
public void IntoOtherSave()
|
||||
@@ -56,6 +65,8 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
UXAssist()
|
||||
{
|
||||
ModsCompat.PlanetVeinUtilization.Run(_harmony);
|
||||
ModsCompat.BlueprintTweaks.Run(_harmony);
|
||||
ModsCompat.CommonAPIWrapper.Run(_harmony);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
@@ -97,6 +108,12 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
FactoryPatch.NightLightAngleY = Config.Bind("Factory", "NightLightAngleY", -2f, "Night light angle Y");
|
||||
PlanetPatch.PlayerActionsInGlobeViewEnabled = Config.Bind("Planet", "PlayerActionsInGlobeView", false,
|
||||
"Enable player actions in globe view");
|
||||
PlanetFunctions.ReturnBuildingsOnInitializeEnabled = Config.Bind("Planet", "ReturnBuildingsOnInitialize", false,
|
||||
"Return buildings to player when initializing planet");
|
||||
PlanetFunctions.ReturnLogisticStorageItemsOnInitializeEnabled = Config.Bind("Planet", "ReturnLogisticStorageItemsOnInitialize", false,
|
||||
"Return logistic storage items to player when initializing planet");
|
||||
PlanetFunctions.ReturnBeltAFactoryItemsOnInitializeEnabled = Config.Bind("Planet", "ReturnBeltAFactoryItemsOnInitialize", false,
|
||||
"Return belt and factory items to player when initializing planet");
|
||||
FactoryPatch.RemoveBuildRangeLimitEnabled = Config.Bind("Factory", "RemoveBuildRangeLimit", false,
|
||||
"Remove limit for build range and maximum count of drag building belts/buildings\nNote: this does not affect range limit for mecha drones' action");
|
||||
FactoryPatch.LargerAreaForUpgradeAndDismantleEnabled = Config.Bind("Factory", "LargerAreaForUpgradeAndDismantle", false,
|
||||
@@ -119,6 +136,10 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
"Drag building power poles in maximum connection range");
|
||||
FactoryPatch.DragBuildPowerPolesAlternatelyEnabled = Config.Bind("Factory", "DragBuildPowerPolesAlternately", true,
|
||||
"Build Tesla Tower and Wireless Power Tower alternately");
|
||||
FactoryPatch.AutoConstructButtonEnabled = Config.Bind("Factory", "AutoConstructButton", false,
|
||||
"Enable auto-construct button");
|
||||
FactoryPatch.AutoConstructEnabled = Config.Bind("Factory", "AutoConstruct", false,
|
||||
"Fly toward the building to be constructed automatically");
|
||||
FactoryPatch.BeltSignalsForBuyOutEnabled = Config.Bind("Factory", "BeltSignalsForBuyOut", false,
|
||||
"Belt signals for buy out dark fog items automatically");
|
||||
FactoryPatch.TankFastFillInAndTakeOutEnabled = Config.Bind("Factory", "TankFastFillInAndTakeOut", false,
|
||||
@@ -138,6 +159,12 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
FactoryPatch.SiloBufferCount = Config.Bind("Factory", "SiloBufferCount", 1, new ConfigDescription("Silo buffer count", new AcceptableValueRange<int>(1, 40)));
|
||||
FactoryPatch.ShortcutKeysForBlueprintCopyEnabled = Config.Bind("Factory", "DismantleBlueprintSelection", false,
|
||||
"Dismantle blueprint selected buildings");
|
||||
FactoryPatch.PressShiftToTakeWholeBeltItemsEnabled = Config.Bind("Factory", "PressShiftToTakeWholeBeltItems", false,
|
||||
"Ctrl+Shift+Click to pick items from whole belts");
|
||||
FactoryPatch.PressShiftToTakeWholeBeltItemsIncludeBranches = Config.Bind("Factory", "PressShiftToTakeWholeBeltItemsIncludeBranches", false,
|
||||
"Include branches of belts");
|
||||
FactoryPatch.PressShiftToTakeWholeBeltItemsIncludeInserters = Config.Bind("Factory", "PressShiftToTakeWholeBeltItemsIncludeInserters", false,
|
||||
"Include connected inserters");
|
||||
LogisticsPatch.AutoConfigLogisticsEnabled = Config.Bind("Factory", "AutoConfigLogistics", false,
|
||||
"Auto-config logistic stations");
|
||||
LogisticsPatch.AutoConfigLimitAutoReplenishCount = Config.Bind("Factory", "AutoConfigLimitAutoReplenishCount", false,
|
||||
@@ -171,6 +198,8 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
"Logistics capacity related tweaks");
|
||||
LogisticsPatch.AllowOverflowInLogisticsEnabled = Config.Bind("Factory", "AllowOverflowInLogistics", false,
|
||||
"Allow overflow in logistic stations");
|
||||
LogisticsPatch.GreaterPowerUsageInLogisticsEnabled = Config.Bind("Build", "GreaterPowerUsageInLogistics", false,
|
||||
"Increase maximum power usage in Logistic Stations and Advanced Mining Machines");
|
||||
LogisticsPatch.LogisticsConstrolPanelImprovementEnabled = Config.Bind("Factory", "LogisticsConstrolPanelImprovement", false,
|
||||
"Logistics control panel improvement");
|
||||
LogisticsPatch.RealtimeLogisticsInfoPanelEnabled = Config.Bind("Factory", "RealtimeLogisticsInfoPanel", false,
|
||||
@@ -217,7 +246,8 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
||||
t => string.Equals(t.Namespace, "UXAssist.Patches", StringComparison.Ordinal) || string.Equals(t.Namespace, "UXAssist.Functions", StringComparison.Ordinal));
|
||||
_patches?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
||||
_compats = Util.GetTypesInNamespace(Assembly.GetExecutingAssembly(), "UXAssist.ModsCompat");
|
||||
_compats?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
||||
object[] parameters = [_harmony];
|
||||
_compats?.Do(type => type.GetMethod("Init")?.Invoke(null, parameters));
|
||||
|
||||
I18N.Apply();
|
||||
}
|
||||
|
||||
@@ -1,35 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<BepInExPluginGuid>org.soardev.uxassist</BepInExPluginGuid>
|
||||
<Description>DSP MOD - UXAssist</Description>
|
||||
<Version>1.4.3</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>1.5.8</Version>
|
||||
<PackageId>UXAssist</PackageId>
|
||||
<RootNamespace>UXAssist</RootNamespace>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2022.3.53" IncludeAssets="compile" />
|
||||
<!-- <PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" /> -->
|
||||
<PackageReference Include="DysonSphereProgram.Modding.CommonAPI" Version="1.6.5" />
|
||||
<PackageReference Include="DysonSphereProgram.Modding.CommonAPI" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\AssemblyFromGame\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>..\AssemblyFromGame\UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="assets/signal/energy-fragment.png" />
|
||||
<EmbeddedResource Include="assets/signal/memory.png" />
|
||||
@@ -56,12 +40,4 @@
|
||||
<EmbeddedResource Include="assets/planet_icon/24.png" />
|
||||
<EmbeddedResource Include="assets/planet_icon/25.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path "$(TargetPath)", package/icon.png, package/manifest.json, README.md, CHANGELOG.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "UXAssist",
|
||||
"version_number": "1.4.3",
|
||||
"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": [
|
||||
|
||||
@@ -4,6 +4,7 @@ using HarmonyLib;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
|
||||
namespace UniverseGenTweaks;
|
||||
|
||||
public static class BirthPlanetPatch
|
||||
{
|
||||
public static ConfigEntry<bool> SitiVeinsOnBirthPlanet;
|
||||
@@ -162,8 +163,8 @@ public static class BirthPlanetPatch
|
||||
|
||||
if (veins.Count > 0)
|
||||
{
|
||||
theme.RareVeins = veins.ToArray();
|
||||
theme.RareSettings = settings.ToArray();
|
||||
theme.RareVeins = [.. veins];
|
||||
theme.RareSettings = [.. settings];
|
||||
}
|
||||
|
||||
if (HighLuminosityBirthStar.Value)
|
||||
|
||||
@@ -1,43 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<AssemblyName>UniverseGenTweaks</AssemblyName>
|
||||
<BepInExPluginGuid>org.soardev.universegentweaks</BepInExPluginGuid>
|
||||
<Description>DSP MOD - UniverseGenTweaks</Description>
|
||||
<Version>1.2.11</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
<PackHasChangelog>true</PackHasChangelog>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2022.3.53" IncludeAssets="compile" />
|
||||
<!-- <PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" /> -->
|
||||
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\AssemblyFromGame\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>..\AssemblyFromGame\UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UXAssist\UXAssist.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path '$(TargetPath)', package/icon.png, package/manifest.json, README.md, CHANGELOG.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
# UpdateGameDlls.ps1
|
||||
# Finds the Dyson Sphere Program installation via Steam registry and libraryfolders.vdf,
|
||||
# then uses assembly-publicizer to refresh AssemblyFromGame/ if the game DLLs are newer.
|
||||
|
||||
param(
|
||||
[string]$ProjectRoot = $PSScriptRoot
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$DSP_APPID = '1366540'
|
||||
$DSP_DLLS = @('Assembly-CSharp.dll', 'UnityEngine.UI.dll')
|
||||
$MANAGED_SUBPATH = 'DSPGAME_Data\Managed'
|
||||
$OUTPUT_DIR = Join-Path $ProjectRoot 'AssemblyFromGame'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. Locate Steam installation via registry
|
||||
# ---------------------------------------------------------------------------
|
||||
$steamPath = $null
|
||||
foreach ($regPath in @(
|
||||
'HKCU:\Software\Valve\Steam',
|
||||
'HKLM:\Software\Valve\Steam',
|
||||
'HKLM:\Software\Wow6432Node\Valve\Steam'
|
||||
)) {
|
||||
try {
|
||||
$val = (Get-ItemProperty -LiteralPath $regPath -Name SteamPath -ErrorAction Stop).SteamPath
|
||||
if ($val -and (Test-Path $val)) {
|
||||
$steamPath = $val
|
||||
break
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
if (-not $steamPath) {
|
||||
Write-Warning 'UpdateGameDlls: Steam installation not found in registry; skipping DLL update.'
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Parse libraryfolders.vdf to find all Steam library paths
|
||||
# ---------------------------------------------------------------------------
|
||||
$vdfPath = Join-Path $steamPath 'steamapps\libraryfolders.vdf'
|
||||
if (-not (Test-Path $vdfPath)) {
|
||||
Write-Warning "UpdateGameDlls: $vdfPath not found; skipping DLL update."
|
||||
exit 0
|
||||
}
|
||||
|
||||
$vdfContent = Get-Content $vdfPath -Raw -Encoding UTF8
|
||||
|
||||
# Extract all library folder paths that contain the DSP app id.
|
||||
# VDF structure: "path" "<library_path>" followed (somewhere) by "<appid>"
|
||||
# Strategy: split into per-library-entry blocks, then check each block.
|
||||
$libraryPaths = @()
|
||||
|
||||
# Match each top-level numbered entry block
|
||||
$blockPattern = '"(?:\d+)"\s*\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}'
|
||||
$pathPattern = '"path"\s+"([^"]+)"'
|
||||
$appPattern = '"' + $DSP_APPID + '"\s+"[^"]+"'
|
||||
|
||||
$blockMatches = [regex]::Matches($vdfContent, $blockPattern, [System.Text.RegularExpressions.RegexOptions]::Singleline)
|
||||
foreach ($block in $blockMatches) {
|
||||
$blockText = $block.Groups[1].Value
|
||||
if ($blockText -match $appPattern) {
|
||||
$pathMatch = [regex]::Match($blockText, $pathPattern)
|
||||
if ($pathMatch.Success) {
|
||||
# VDF uses forward slashes and may double-escape backslashes
|
||||
$libPath = $pathMatch.Groups[1].Value -replace '\\\\', '\' -replace '/', '\'
|
||||
$libraryPaths += $libPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($libraryPaths.Count -eq 0) {
|
||||
Write-Warning "UpdateGameDlls: DSP (AppID $DSP_APPID) not found in any Steam library; skipping DLL update."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Find the game's Managed directory
|
||||
# ---------------------------------------------------------------------------
|
||||
$managedDir = $null
|
||||
foreach ($lib in $libraryPaths) {
|
||||
$candidate = Join-Path $lib "steamapps\common\Dyson Sphere Program\$MANAGED_SUBPATH"
|
||||
if (Test-Path $candidate) {
|
||||
$managedDir = $candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $managedDir) {
|
||||
Write-Warning 'UpdateGameDlls: Dyson Sphere Program Managed directory not found; skipping DLL update.'
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "UpdateGameDlls: Game Managed directory: $managedDir"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Locate assembly-publicizer
|
||||
# ---------------------------------------------------------------------------
|
||||
$publicizer = $null
|
||||
foreach ($candidate in @(
|
||||
'assembly-publicizer', # on PATH
|
||||
"$env:USERPROFILE\.dotnet\tools\assembly-publicizer.exe",
|
||||
"$env:ProgramFiles\dotnet\tools\assembly-publicizer.exe"
|
||||
)) {
|
||||
try {
|
||||
$resolved = (Get-Command $candidate -ErrorAction Stop).Source
|
||||
$publicizer = $resolved
|
||||
break
|
||||
} catch { }
|
||||
}
|
||||
|
||||
if (-not $publicizer) {
|
||||
Write-Host 'UpdateGameDlls: assembly-publicizer not found; installing via dotnet tool install -g BepInEx.AssemblyPublicizer.Cli ...'
|
||||
dotnet tool install -g BepInEx.AssemblyPublicizer.Cli
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning 'UpdateGameDlls: Failed to install assembly-publicizer; skipping DLL update.'
|
||||
exit 0
|
||||
}
|
||||
# Refresh PATH for the current process so the newly installed tool is found
|
||||
$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'User') + ';' + $env:PATH
|
||||
try {
|
||||
$publicizer = (Get-Command 'assembly-publicizer' -ErrorAction Stop).Source
|
||||
} catch {
|
||||
Write-Warning 'UpdateGameDlls: assembly-publicizer still not found after install; skipping DLL update.'
|
||||
exit 0
|
||||
}
|
||||
Write-Host "UpdateGameDlls: assembly-publicizer installed at $publicizer"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. For each DLL: compare timestamps, publicize if game copy is newer
|
||||
# ---------------------------------------------------------------------------
|
||||
$updated = 0
|
||||
foreach ($dll in $DSP_DLLS) {
|
||||
$srcFile = Join-Path $managedDir $dll
|
||||
$dstFile = Join-Path $OUTPUT_DIR $dll
|
||||
|
||||
if (-not (Test-Path $srcFile)) {
|
||||
Write-Warning "UpdateGameDlls: Source DLL not found: $srcFile"
|
||||
continue
|
||||
}
|
||||
|
||||
$srcTime = (Get-Item $srcFile).LastWriteTimeUtc
|
||||
$needsUpdate = $true
|
||||
|
||||
if (Test-Path $dstFile) {
|
||||
$dstTime = (Get-Item $dstFile).LastWriteTimeUtc
|
||||
if ($srcTime -le $dstTime) {
|
||||
Write-Host "UpdateGameDlls: $dll is up-to-date (game: $srcTime, local: $dstTime)"
|
||||
$needsUpdate = $false
|
||||
}
|
||||
}
|
||||
|
||||
if ($needsUpdate) {
|
||||
Write-Host "UpdateGameDlls: Publicizing $dll (game: $srcTime) ..."
|
||||
# --overwrite writes directly to <output>/<dll> (no -publicized postfix)
|
||||
& $publicizer $srcFile --strip --overwrite --output $OUTPUT_DIR
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "UpdateGameDlls: assembly-publicizer failed for $dll (exit code $LASTEXITCODE)"
|
||||
exit 1
|
||||
}
|
||||
# Preserve the source timestamp on the output so future comparisons are stable
|
||||
$outFile = Join-Path $OUTPUT_DIR $dll
|
||||
if (Test-Path $outFile) {
|
||||
(Get-Item $outFile).LastWriteTimeUtc = $srcTime
|
||||
}
|
||||
$updated++
|
||||
Write-Host "UpdateGameDlls: $dll updated."
|
||||
}
|
||||
}
|
||||
|
||||
if ($updated -gt 0) {
|
||||
Write-Host "UpdateGameDlls: $updated DLL(s) refreshed."
|
||||
} else {
|
||||
Write-Host 'UpdateGameDlls: All DLLs are up-to-date.'
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<Project/>
|
||||
@@ -0,0 +1 @@
|
||||
<Project/>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.Build.NoTargets/3.7.56">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<Target Name="UpdateGameDlls" BeforeTargets="BeforeBuild">
|
||||
<Exec
|
||||
Command="powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$(MSBuildThisFileDirectory)..\UpdateGameDlls.ps1" -ProjectRoot "$(MSBuildThisFileDirectory)..""
|
||||
ConsoleToMSBuild="true"
|
||||
IgnoreExitCode="false"
|
||||
WorkingDirectory="$(MSBuildThisFileDirectory).." />
|
||||
</Target>
|
||||
|
||||
<!-- No-op stubs so solution-wide -t:ZipMod / -t:CopyToParentPackage don't fail
|
||||
with MSB4057 "target does not exist in this project". -->
|
||||
<Target Name="ZipMod" />
|
||||
<Target Name="CopyToParentPackage" />
|
||||
</Project>
|
||||
@@ -1,29 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<BepInExPluginGuid>org.soardev.usercloak</BepInExPluginGuid>
|
||||
<Description>DSP MOD - UserCloak</Description>
|
||||
<Version>1.0.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PackageId>UserCloak</PackageId>
|
||||
<RootNamespace>UserCloak</RootNamespace>
|
||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="del /F /Q package\$(ProjectName)-$(Version).zip
powershell Compress-Archive -Force -DestinationPath 'package/$(ProjectName)-$(Version).zip' -Path '$(TargetPath)', package/icon.png, package/manifest.json, README.md" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user