mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-08 16:30:12 +08:00
Compare commits
210
Commits
19194c28ca
...
refactor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e09c17ea0 | ||
|
|
69d5a4b3ce | ||
|
|
53d558a9a4 | ||
|
|
a48ae5ad96 | ||
|
|
82365b3d16 | ||
|
|
010ec73c8d | ||
|
|
66ecebaca7 | ||
|
|
15c5bbdd72 | ||
|
|
6b03801681 | ||
|
|
db15c65961 | ||
|
|
ff7ce158cc | ||
|
|
ab1d20683d | ||
|
|
c2016909ff | ||
|
|
cca8b8594d | ||
|
|
647b130993 | ||
|
|
b74005282e | ||
|
|
76d9d9fa21 | ||
|
|
8d70ce8862 | ||
|
|
51fc080ff2 | ||
|
|
036243fd4a | ||
|
|
34c99701ca | ||
|
|
6e2b21a0a0 | ||
|
|
1939a9cf22 | ||
|
|
25b33144b8 | ||
|
|
a133fd9e14 | ||
|
|
7973cbe358 | ||
|
|
36426d034d | ||
|
|
4fb43c73b5 | ||
|
|
06c3532acc | ||
|
|
54c1700fcd | ||
|
|
6c7f9867d0 | ||
|
|
d843090622 | ||
|
|
439d74c817 | ||
|
|
ed916ebe7f | ||
|
|
f4b163fae9 | ||
|
|
8bfcee2a81 | ||
|
|
b5b2fee14e | ||
|
|
b6657c96c0 | ||
|
|
2dce3a7b93 | ||
|
|
eae4ba0376 | ||
|
|
06015d51d0 | ||
|
|
099f3ee35a | ||
|
|
39bdf06e88 | ||
|
|
87f08f3f8d | ||
|
|
f822c1a5c6 | ||
|
|
ce199374b4 | ||
|
|
dace35a691 | ||
|
|
f2abb7cc2c | ||
|
|
91259bbd17 | ||
|
|
cb7a965d12 | ||
|
|
bfe0787923 | ||
|
|
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 | ||
|
|
be9de43492 | ||
|
|
2dbf017a5e | ||
|
|
3c7744047c | ||
|
|
a9959a2f07 | ||
|
|
77f5803a24 | ||
|
|
e9bbcf5e2c | ||
|
|
a183485286 | ||
|
|
5a6cfb18c9 | ||
|
|
49226001be | ||
|
|
7c1e88f86d | ||
|
|
16429936a9 | ||
|
|
d711dd25ef | ||
|
|
e909b6d9d2 | ||
|
|
2a4008deac | ||
|
|
6b423225fe | ||
|
|
9d9a12c1af | ||
|
|
1d11ba90bd | ||
|
|
a5dc7c5825 | ||
|
|
73ebcf1aa3 | ||
|
|
dc092d7f6f | ||
|
|
d9f87ca4e9 | ||
|
|
a3c60c32ca | ||
|
|
96a9e8a570 | ||
|
|
d6a8275938 | ||
|
|
b995503f58 | ||
|
|
a25f74443d | ||
|
|
5f37b8b6d6 | ||
|
|
4584895345 | ||
|
|
5b4633e54c | ||
|
|
31b1d90d5d | ||
|
|
8446fba0e4 | ||
|
|
688b50344c | ||
|
|
0dd1a11c14 | ||
|
|
f8552d5c34 | ||
|
|
c98c801f27 | ||
|
|
9bfa74edf2 | ||
|
|
9d586d68e0 | ||
|
|
a446a17d02 | ||
|
|
7a7943b001 | ||
|
|
a9dd130f76 | ||
|
|
0178c8cc2e | ||
|
|
4e2b4a8e22 | ||
|
|
4f292bd2d3 | ||
|
|
2949066712 | ||
|
|
b093a62e36 | ||
|
|
f58bd869fe | ||
|
|
b7abb3a32a | ||
|
|
b79cfbc994 | ||
|
|
c91a873e8d | ||
|
|
4b632db315 | ||
|
|
2c4d1b8b0d | ||
|
|
ba095d79f0 | ||
|
|
a9286d2839 | ||
|
|
17aca89249 | ||
|
|
4a3bffd927 | ||
|
|
cb3975ae1a | ||
|
|
4ba1512205 | ||
|
|
c6f1a8bd80 | ||
|
|
dc246170ac | ||
|
|
23aa8c1f13 | ||
|
|
944a4d7948 | ||
|
|
f7e1a27be1 |
@@ -0,0 +1,28 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = crlf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{cs,vb}]
|
||||||
|
# Suggestion-only so existing code does not break the build
|
||||||
|
dotnet_style_qualification_for_field = false:suggestion
|
||||||
|
dotnet_style_qualification_for_property = false:suggestion
|
||||||
|
dotnet_style_qualification_for_method = false:suggestion
|
||||||
|
dotnet_style_qualification_for_event = false:suggestion
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||||
|
dotnet_style_readonly_field = true:suggestion
|
||||||
|
csharp_style_var_for_built_in_types = true:suggestion
|
||||||
|
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||||
|
csharp_style_var_elsewhere = true:suggestion
|
||||||
|
csharp_style_expression_bodied_methods = when_on_single_line:suggestion
|
||||||
|
csharp_style_expression_bodied_properties = true:suggestion
|
||||||
|
csharp_prefer_simple_default_expression = true:suggestion
|
||||||
|
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, master, refactor/*]
|
||||||
|
pull_request:
|
||||||
|
branches: [main, master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Restore
|
||||||
|
run: dotnet restore DSP_Mods.sln
|
||||||
|
|
||||||
|
- name: Build Release
|
||||||
|
run: dotnet build DSP_Mods.sln -c Release --no-restore
|
||||||
|
|
||||||
|
- name: Package main mods
|
||||||
|
run: |
|
||||||
|
dotnet build UXAssist/UXAssist.csproj -t:ZipMod -c Release --no-restore
|
||||||
|
dotnet build CheatEnabler/CheatEnabler.csproj -t:ZipMod -c Release --no-restore
|
||||||
|
dotnet build UniverseGenTweaks/UniverseGenTweaks.csproj -t:ZipMod -c Release --no-restore
|
||||||
@@ -4,9 +4,14 @@
|
|||||||
# Rider project files
|
# Rider project files
|
||||||
/.idea/
|
/.idea/
|
||||||
|
|
||||||
|
# VS Code project files
|
||||||
|
/.vscode/
|
||||||
|
|
||||||
# C# generated folders
|
# C# generated folders
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
|
*.dll
|
||||||
|
!/AssemblyFromGame/*.dll
|
||||||
|
|
||||||
# C++ build folders
|
# C++ build folders
|
||||||
build/
|
build/
|
||||||
@@ -15,3 +20,7 @@ build/
|
|||||||
/*/package/*.zip
|
/*/package/*.zip
|
||||||
/*/package/patchers/
|
/*/package/patchers/
|
||||||
/*/package/plugins/
|
/*/package/plugins/
|
||||||
|
|
||||||
|
# Agent files
|
||||||
|
/.omo/
|
||||||
|
/.worktrees/
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"MD013": false,
|
||||||
|
"MD033": {
|
||||||
|
"allowed_elements": ["details", "summary"]
|
||||||
|
},
|
||||||
|
"MD041": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
# 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 Factory tab's building-buffer controls include a comparison tip with the original game values. The Logistics tab can push auto-config values to all existing facilities of a type on the current planet (per-setting `Apply` and per-category `Apply All` buttons), and can set both product limits of every Orbital Collector across all loaded factories; logic is in `LogisticsPatch.Apply*`/`ForEach*` and wired in `UIConfigWindow`. |
|
||||||
|
| **CheatEnabler** | `org.soardev.cheatenabler` | Cheat pack (depends on UXAssist). Instant build, architect mode, infinite resources, power boosts, Dyson Sphere cheats with a bounded shell-count input (1–99,999), 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.
|
||||||
|
- **Centralized mod-feature lifecycle:** `UXAssist.Common.ModFeatures.ModFeatureRegistry` holds shared static lists of mod features discovered across all mods. **Only UXAssist drives the shared deferred lifecycle** (`StartAll`/`UninitAll`/`OnInputUpdateAll`/`OnUpdateAll`); these dispatchers are `internal` so dependent mods (separate assemblies, no `InternalsVisibleTo`) cannot call them and re-trigger other mods' features. A feature's `Init` runs **eagerly** when it is registered (via `Discover`/`Register`), preserving the original `Awake`-phase timing that keybind registration and other early setup rely on — the game's `UIOptionWindow._OnCreate` copies registered keybinds only after all plugins have finished loading. Dependent mods only call `ModFeatureRegistry.Discover(Assembly.GetExecutingAssembly())` (and optionally `Register<T>()`) in their `Awake`. UXAssist begins the deferred lifecycle from its own `Start`; if a dependent feature is discovered after that transition, the registry starts it immediately after initialization so it cannot miss `Start`. The registry also guards start idempotency per feature (start at most once; uninit resets) and per-frame re-entrancy (`Time.frameCount`) for the update dispatchers, as defense-in-depth.
|
||||||
|
- **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. Localization keys are declared as `public const string` in per-project registration classes (`UXAssist/Common/I18NKeys.cs`, `CheatEnabler/Localization.cs`, `UniverseGenTweaks/Localization.cs`) and registered through a single `Register()` call from each mod's `Awake()`. Do not pass Chinese string literals to `.Translate()` at call sites.
|
||||||
|
- **Centralized game constants:** Hard-coded item IDs, tech IDs, logistics capacities, and Dyson sphere geometry defaults live in `UXAssist/Common/GameConstants` (`ItemIds`, `TechIds`, `LogisticsConstants`, `DysonSphereConstants`). Prefer these constants over inline literals in UXAssist patches.
|
||||||
|
- **Game source facts:** In the original DSP `Assembly-CSharp.dll`, `PlanetFactory.prebuildCount` is computed as `prebuildCursor - prebuildRecycleCursor - 1`, and normal prebuild add/remove paths maintain those cursors. If Auto Construct UI reports zero while visible construction ghosts exist, first suspect the wrong planet/factory, non-prebuild preview state, or a missed UI refresh path before replacing this property with a pool scan.
|
||||||
|
- **Illegal Dyson shell generation:** Estimated triangle vertex counts mirror the original `DysonShell.GenerateGeometry` rasterization as closely as possible, but can still differ from the final frame-generated shell polygon at numerical boundaries. Max-output generation must treat `QuickAddDysonShell` failure as a candidate rejection and try the next candidate rather than assuming the estimate is exact.
|
||||||
|
- **Fail-soft patch application:** `PatchImpl<T>.Enable(true)` applies Harmony patches inside a try/catch. Runtime patching can fail through no fault of ours (Harmony re-runs other mods' transpilers on shared target methods), and an escaping exception would abort the calling `ConfigEntry.SettingChanged` delegate chain, desyncing config UI from config values. On failure it logs a `LogError` with the feature type name, rolls back via `UnpatchSelf()`, and leaves `_patch` null so a later `Enable(true)` can retry.
|
||||||
|
- **Convergent in-game UI state:** In-game overlay widgets whose visibility depends on game state (e.g. `AutoConstructUI`) must not rely solely on one-shot event-driven refreshes (`SettingChanged` handlers, patch `OnEnable`/`OnDisable`), because a thrown exception earlier in a delegate chain or a failed patch application silently drops the refresh. `AutoConstructUI.OnUpdate()` reconciles button visibility and the pending-construction count with actual game state every 30 frames (also effective while paused); the `AutoConstructPatch` postfix on `PlayerAction_Rts.GameTick` only implements the fly-to-target behavior, and `AutoConstructPatch.OnEnable` logs its visibility predicate inputs once per enable as a remote-diagnosis aid.
|
||||||
|
- **Auto-navigation modes:** The legacy auto-navigation and the new navigation algorithm are mutually exclusive; legacy mode wins if both configuration values load as enabled. The shared `ToggleAutoCruise` key dispatches to only the selected implementation. New-navigation teardown is unconditional for configuration, target, capability, and lifecycle failures, while the manual-input option controls only user-override behavior. Its session state and cloned status label are reset through `GameLogic.OnGameEnd` and patch teardown.
|
||||||
|
- **Transpiler patches:** Performance-critical mods (LabOpt, MechaDronesTweaks) use `[HarmonyTranspiler]` to rewrite IL instructions directly for maximum efficiency. All transpilers in UXAssist, CheatEnabler, and UniverseGenTweaks carry a standard header comment (`// Harmony transpiler:`, `// Target:`, `// Fallback:`) documenting the target method and fallback behavior. `UXAssist.Common.Patching.TranspilerGuard` provides a reusable `CodeMatcher.Finish` helper that returns original instructions when a matcher becomes invalid.
|
||||||
|
- **Mod-compatibility reflection:** Use `UXAssist.Common.ModCompat.ModCompatHelper` for BepInEx plugin detection, external mod type/method/field resolution, and property-setter lookup. Preserve the old public type identity with a forwarding or inherited compatibility facade when a refactor moves a type that external mods may locate through reflection; build and verify that the legacy reflection target forwards to the refactored implementation. Use `UXAssist.Common.Utils.DysonSphereReflection` for the DSPOptimizations-compatible `DysonSphereLayer` private fields (`totalNodeSP`, `totalFrameSP`, `totalCP`) instead of resolving them locally in each consumer.
|
||||||
|
- **Build quality gates:** Root `.editorconfig` defines suggestion-only C# style conventions. `Directory.Build.props` enables `TreatWarningsAsErrors` with `NoWarn>0618` for the expected obsolete-API usage, so any new warning fails the build. `.github/workflows/build.yml` runs a Release build and packages the three main mods on every push/PR.
|
||||||
|
- **Save persistence:** Mods that need to persist data use the `IModCanSave` interface from DSPModSave.
|
||||||
Binary file not shown.
Binary file not shown.
+272
-204
@@ -3,151 +3,185 @@
|
|||||||
|
|
||||||
## Changlog
|
## 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.
|
||||||
|
* 2.3.32
|
||||||
|
* `Complete Dyson Sphere Shells instantly`: Fix a crash.
|
||||||
* 2.3.31
|
* 2.3.31
|
||||||
+ New feature: `Unlock Dyson Sphere max orbit radius`
|
* New feature: `Unlock Dyson Sphere max orbit radius`
|
||||||
+ `Remove metadata consumption record in current game`: Fix implementation
|
* `Remove metadata consumption record in current game`: Fix implementation
|
||||||
|
* Add 3 buttons for creating illegal Dyson Sphere Shells, you must enable `IllegalDysonShellFunctionsEnabled` of `DysonSphere` section in config to see them.
|
||||||
|
* `Generate an illegal dyson shell`
|
||||||
|
* `Keep max production shells and remove others`
|
||||||
|
* `Duplicate shells from that with highest production`
|
||||||
* 2.3.30
|
* 2.3.30
|
||||||
+ Fix a warning issue while `No condition build` or `No collision` is enabled.
|
* Fix a warning issue while `No condition build` or `No collision` is enabled.
|
||||||
+ Increase performance for `Finish build immediately` greatly on pasting large blueprints.
|
* Increase performance for `Finish build immediately` greatly on pasting large blueprints.
|
||||||
* 2.3.29
|
* 2.3.29
|
||||||
+ Fix compatibility with game update 0.10.32.25779
|
* Fix compatibility with game update 0.10.32.25779
|
||||||
* 2.3.28
|
* 2.3.28
|
||||||
+ New feature: `Instant hand-craft`.
|
* New feature: `Instant hand-craft`.
|
||||||
+ Fix some panels' display while `Infinite Natural Resources` is enabled.
|
* Fix some panels' display while `Infinite Natural Resources` is enabled.
|
||||||
* 2.3.27
|
* 2.3.27
|
||||||
+ `Skip bullet period` & `Eject anyway`: Fix compatibility with `Dyson Sphere Program v0.10.32.25496`.
|
* `Skip bullet period` & `Eject anyway`: Fix compatibility with `Dyson Sphere Program v0.10.32.25496`.
|
||||||
* 2.3.26
|
* 2.3.26
|
||||||
+ Refactor codes to adapt to UXAssist 1.2.0
|
* Refactor codes to adapt to UXAssist 1.2.0
|
||||||
- You should update UXAssist to 1.2.0 or later before using this version.
|
* You should update UXAssist to 1.2.0 or later before using this version.
|
||||||
+ `Complete Dyson Sphere Shells instantly`: Fix possible wrong production records.
|
* `Complete Dyson Sphere Shells instantly`: Fix possible wrong production records.
|
||||||
* 2.3.25
|
* 2.3.25
|
||||||
+ New feature: `Enable warp without space warpers`
|
* New feature: `Enable warp without space warpers`
|
||||||
+ New feature: `Wind Turbines do global power coverage`
|
* New feature: `Wind Turbines do global power coverage`
|
||||||
+ Fix an issue that `Complete Dyson Sphere Shells instantly` does not generate production records for solar sails.
|
* Fix an issue that `Complete Dyson Sphere Shells instantly` does not generate production records for solar sails.
|
||||||
* 2.3.24
|
* 2.3.24
|
||||||
+ `Complete Dyson Sphere Shells instantly`: Fix a bug that may cause negative power in some cases
|
* `Complete Dyson Sphere Shells instantly`: Fix a bug that may cause negative power in some cases
|
||||||
* 2.3.23
|
* 2.3.23
|
||||||
+ New feature: `Complete Dyson Sphere Shells instantly`
|
* New feature: `Complete Dyson Sphere Shells instantly`
|
||||||
+ Fix a crash when config panel is opened before game is fully loaded
|
* Fix a crash when config panel is opened before game is fully loaded
|
||||||
* 2.3.22
|
* 2.3.22
|
||||||
+ Fix `Pump Anywhere`
|
* Fix `Pump Anywhere`
|
||||||
* 2.3.21
|
* 2.3.21
|
||||||
+ `Retrieve/Place items from/to remote planets on logistics control panel`: Items are put back to player's inventory when a slot is removed from the logistics station on remote planet.
|
* `Retrieve/Place items from/to remote planets on logistics control panel`: Items are put back to player's inventory when a slot is removed from the logistics station on remote planet.
|
||||||
+ `Dev Shortcuts`: Camera Pose related shortcurts are working now.
|
* `Dev Shortcuts`: Camera Pose related shortcurts are working now.
|
||||||
* 2.3.20
|
* 2.3.20
|
||||||
+ New feature: `Retrieve/Place items from/to remote planets on logistics control panel`
|
* New feature: `Retrieve/Place items from/to remote planets on logistics control panel`
|
||||||
* 2.3.19
|
* 2.3.19
|
||||||
+ New features:
|
* New features:
|
||||||
+ `Remove all metadata consumption records`
|
* `Remove all metadata consumption records`
|
||||||
+ `Remove metadata consumption record in current game`
|
* `Remove metadata consumption record in current game`
|
||||||
+ `Clear metadata flag which bans achievements`
|
* `Clear metadata flag which bans achievements`
|
||||||
* 2.3.18
|
* 2.3.18
|
||||||
+ New features:
|
* New features:
|
||||||
+ `Teleport to outer space`, this will teleport you to the outer space which is 50 LYs far from the farthest star.
|
* `Teleport to outer space`, this will teleport you to the outer space which is 50 LYs far from the farthest star.
|
||||||
+ `Teleport to selected astronomical`
|
* `Teleport to selected astronomical`
|
||||||
+ Fix logic of `Unlock techs with key-modifiers`.
|
* Fix logic of `Unlock techs with key-modifiers`.
|
||||||
+ `No condition build` does not hide rotation info of belts now.
|
* `No condition build` does not hide rotation info of belts now.
|
||||||
* 2.3.17
|
* 2.3.17
|
||||||
+ Make compatible with game version 0.10.30.23292
|
* Make compatible with game version 0.10.30.23292
|
||||||
* 2.3.16
|
* 2.3.16
|
||||||
+ Add 2 options to `Belt signal item generation`:
|
* Add 2 options to `Belt signal item generation`:
|
||||||
- `Count generations as production in statistics`
|
* `Count generations as production in statistics`
|
||||||
- `Count removals as consumption in statistics`
|
* `Count removals as consumption in statistics`
|
||||||
+ New feature: `Increase maximum power usage in Logistic Stations and Advanced Mining Machines`
|
* New feature: `Increase maximum power usage in Logistic Stations and Advanced Mining Machines`
|
||||||
- Logistic Stations: Increased max charging power to 3GW(ILS) and 600MW(PLS) (10x of original)
|
* Logistic Stations: Increased max charging power to 3GW(ILS) and 600MW(PLS) (10x of original)
|
||||||
- Advanced Mining Machines: Increased max mining speed to 1000%
|
* Advanced Mining Machines: Increased max mining speed to 1000%
|
||||||
* 2.3.15
|
* 2.3.15
|
||||||
+ New features:
|
* New features:
|
||||||
- `Instant teleport (like that in Sandbox mode)`
|
* `Instant teleport (like that in Sandbox mode)`
|
||||||
- `Mecha and Drones/Fleets invicible`
|
* `Mecha and Drones/Fleets invicible`
|
||||||
- `Buildings invicible`
|
* `Buildings invicible`
|
||||||
* 2.3.14
|
* 2.3.14
|
||||||
+ Remove default shortcut key for `No condition build` and `No collision`, to avoid misoperation. You can still set them in system settings window manually if needed.
|
* Remove default shortcut key for `No condition build` and `No collision`, to avoid misoperation. You can still set them in system settings window manually if needed.
|
||||||
+ Fix translation issue.
|
* Fix translation issue.
|
||||||
* 2.3.13
|
* 2.3.13
|
||||||
+ Fix a bug that shortcuts are not working and have display issue on settings window.
|
* Fix a bug that shortcuts are not working and have display issue on settings window.
|
||||||
* 2.3.12
|
* 2.3.12
|
||||||
+ Add a shortcut to toggle `No collision`, you can modify the shortcut on system settings window.
|
* Add a shortcut to toggle `No collision`, you can modify the shortcut on system settings window.
|
||||||
+ Add realtime tips when toggling `No condition build` and `No collision` with shortcuts.
|
* Add realtime tips when toggling `No condition build` and `No collision` with shortcuts.
|
||||||
* 2.3.11
|
* 2.3.11
|
||||||
+ Add a shortcut to toggle `No condition build`, you can modify the shortcut on system settings window. This depends on [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) 1.0.15 or later.
|
* Add a shortcut to toggle `No condition build`, you can modify the shortcut on system settings window. This depends on [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) 1.0.15 or later.
|
||||||
* 2.3.10
|
* 2.3.10
|
||||||
+ Fix following functions not working in new game updates:
|
* Fix following functions not working in new game updates:
|
||||||
- `Pump Anywhere`
|
* `Pump Anywhere`
|
||||||
- `Terraform without enough soil piles`
|
* `Terraform without enough soil piles`
|
||||||
* 2.3.9
|
* 2.3.9
|
||||||
+ Support game version 0.10.28.21219
|
* Support game version 0.10.28.21219
|
||||||
* 2.3.8
|
* 2.3.8
|
||||||
+ Fix a crash on starting new games while `Finish build immediately` is enabled.
|
* Fix a crash on starting new games while `Finish build immediately` is enabled.
|
||||||
+ Fix UI button width.
|
* Fix UI button width.
|
||||||
* 2.3.7
|
* 2.3.7
|
||||||
+ Support game version 0.10.28.20759
|
* Support game version 0.10.28.20759
|
||||||
+ Fix belt signal that items' generation speed is not fit to number set sometimes.
|
* Fix belt signal that items' generation speed is not fit to number set sometimes.
|
||||||
* 2.3.6
|
* 2.3.6
|
||||||
+ Support for UXAssist's new function within `Finish build immediately`.
|
* Support for UXAssist's new function within `Finish build immediately`.
|
||||||
+ Add a warning message when `Build without condition` is enabled.
|
* Add a warning message when `Build without condition` is enabled.
|
||||||
+ Fix an issue in `Finish build immediately` that some buildings are not finished immediately.
|
* Fix an issue in `Finish build immediately` that some buildings are not finished immediately.
|
||||||
* 2.3.5
|
* 2.3.5
|
||||||
+ Fix another crash in `Skip bullet period`.
|
* Fix another crash in `Skip bullet period`.
|
||||||
* 2.3.4
|
* 2.3.4
|
||||||
+ Use new tab layout of UXAssist 1.0.2
|
* Use new tab layout of UXAssist 1.0.2
|
||||||
+ Minor bug fixes
|
* Minor bug fixes
|
||||||
* 2.3.3
|
* 2.3.3
|
||||||
+ Fix a crash in `Skip bullet period`.
|
* Fix a crash in `Skip bullet period`.
|
||||||
+ Unlock techs with Alt unlocks VeinUtil to 10000 instead of 7200 now, as bug fixed in UXAssist.
|
* Unlock techs with Alt unlocks VeinUtil to 10000 instead of 7200 now, as bug fixed in UXAssist.
|
||||||
* 2.3.2
|
* 2.3.2
|
||||||
+ Birth star options moved to [UniverseGenTweaks](https://dsp.thunderstore.io/package/soarqin/UniverseGenTweaks/)
|
* Birth star options moved to [UniverseGenTweaks](https://dsp.thunderstore.io/package/soarqin/UniverseGenTweaks/)
|
||||||
+ Optimize `Quick absorb`, consumes less CPU time and take turns firing to nodes.
|
* Optimize `Quick absorb`, consumes less CPU time and take turns firing to nodes.
|
||||||
+ `Fast Mining` ensures full output of oil extractors now.
|
* `Fast Mining` ensures full output of oil extractors now.
|
||||||
+ Fix issue that `Belt signal generator` not working after switched off then on again.
|
* Fix issue that `Belt signal generator` not working after switched off then on again.
|
||||||
+ Fix absorption issue by `Quick absorb` and `Skip bullet period` enabled at the same time.
|
* Fix absorption issue by `Quick absorb` and `Skip bullet period` enabled at the same time.
|
||||||
+ Crash fix for some options
|
* Crash fix for some options
|
||||||
* 2.3.1
|
* 2.3.1
|
||||||
+ Add UXAssist to dependencies in manifest.
|
* Add UXAssist to dependencies in manifest.
|
||||||
* 2.3.0
|
* 2.3.0
|
||||||
+ Move some functions to an individual mod: [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
|
* Move some functions to an individual mod: [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
|
||||||
+ Depends on [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) now, so that config panel is unified with UXAssist.
|
* Depends on [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) now, so that config panel is unified with UXAssist.
|
||||||
+ Remove `LCtrl+A` from Dev Shortcuts, to avoid misoperation.
|
* Remove `LCtrl+A` from Dev Shortcuts, to avoid misoperation.
|
||||||
+ Infinite bots/drones/vessels in `Architect mode` now.
|
* Infinite bots/drones/vessels in `Architect mode` now.
|
||||||
* 2.2.7
|
* 2.2.7
|
||||||
+ New function: `Construct only nodes but frames`
|
* New function: `Construct only nodes but frames`
|
||||||
+ Opening config panel does not close inventory panel now
|
* Opening config panel does not close inventory panel now
|
||||||
+ Remove `Input direction conflict` check while using `Remove some build conditions`
|
* Remove `Input direction conflict` check while using `Remove some build conditions`
|
||||||
+ Fix a bug that prevents `Belt signal alt format` from switching number formats for current belt signals
|
* Fix a bug that prevents `Belt signal alt format` from switching number formats for current belt signals
|
||||||
* 2.2.6
|
* 2.2.6
|
||||||
+ New function: `Stop ejectors when available nodes are all filled up`
|
* New function: `Stop ejectors when available nodes are all filled up`
|
||||||
+ Fix a bug that absorb solar sails on unfinised nodes
|
* Fix a bug that absorb solar sails on unfinised nodes
|
||||||
* 2.2.5
|
* 2.2.5
|
||||||
+ Skip all intermediate states and absorb solar sails instantly while enable `Quick absorb`, `Skip bullet period` and `Skip absorption period` at the same time.
|
* Skip all intermediate states and absorb solar sails instantly while enable `Quick absorb`, `Skip bullet period` and `Skip absorption period` at the same time.
|
||||||
+ Fix a problem that `Quick absorb` does not absorb all solar sails instantly when most nodes are full.
|
* Fix a problem that `Quick absorb` does not absorb all solar sails instantly when most nodes are full.
|
||||||
+ Fix crash while using with some mods
|
* Fix crash while using with some mods
|
||||||
* 2.2.4
|
* 2.2.4
|
||||||
+ New function: `Enable player actions in globe view`
|
* New function: `Enable player actions in globe view`
|
||||||
+ Fix UI bug
|
* Fix UI bug
|
||||||
* 2.2.3
|
* 2.2.3
|
||||||
+ New function: `Remove some build conditions`
|
* New function: `Remove some build conditions`
|
||||||
+ Fix compatibility with some mods
|
* Fix compatibility with some mods
|
||||||
* 2.2.2
|
* 2.2.2
|
||||||
+ New function: `Assign gamesave to currrnet account`
|
* New function: `Assign gamesave to currrnet account`
|
||||||
+ New subfunction: `Belt signal alt format`
|
* New subfunction: `Belt signal alt format`
|
||||||
+ Fix a crash on using `Initialize this Planet`
|
* Fix a crash on using `Initialize this Planet`
|
||||||
+ Fix belt build in `Finish build immediately`
|
* Fix belt build in `Finish build immediately`
|
||||||
* 2.2.1
|
* 2.2.1
|
||||||
+ Check condition for miners even when `Build without condition` is enabled.
|
* Check condition for miners even when `Build without condition` is enabled.
|
||||||
+ Fix a patch issue that may cause `Build without condition` not working.
|
* Fix a patch issue that may cause `Build without condition` not working.
|
||||||
* 2.2.0
|
* 2.2.0
|
||||||
+ Add some power related functions
|
* Add some power related functions
|
||||||
+ Add a subfunction to belt signal item generation, which simulates production process of raws and intermediates on statistics
|
* Add a subfunction to belt signal item generation, which simulates production process of raws and intermediates on statistics
|
||||||
+ Split some functions from Architect mode
|
* Split some functions from Architect mode
|
||||||
* 2.1.0
|
* 2.1.0
|
||||||
+ Belt signal item generation
|
* Belt signal item generation
|
||||||
+ Fix window display priority which may cause tips to be covered by main window
|
* Fix window display priority which may cause tips to be covered by main window
|
||||||
* 2.0.0
|
* 2.0.0
|
||||||
+ Refactorying codes
|
* Refactorying codes
|
||||||
+ UI implementation
|
* UI implementation
|
||||||
+ Add a lot of functions
|
* Add a lot of functions
|
||||||
* 1.0.0
|
* 1.0.0
|
||||||
+ Initial release
|
* Initial release
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@@ -156,150 +190,184 @@
|
|||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
|
* 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
|
||||||
|
* `生成仙术戴森壳`:此功能现在对所有用户开放,不再需要启用特定的配置项。
|
||||||
|
* 2.3.32
|
||||||
|
* `立即完成戴森壳建造`:修复了一个崩溃问题
|
||||||
* 2.3.31
|
* 2.3.31
|
||||||
+ 新功能:`解锁戴森球最大轨道半径`
|
* 新功能:`解锁戴森球最大轨道半径`
|
||||||
+ `移除当前存档的元数据消耗记录`:修复实现
|
* `移除当前存档的元数据消耗记录`:修复实现
|
||||||
|
* 增加了3个用于制作仙术戴森壳的按钮,你必须在设置文件里开启`DysonSphere`分类的`IllegalDysonShellFunctionsEnabled`才能看到它们
|
||||||
|
* `生成单层仙术戴森壳`
|
||||||
|
* `保留发电量最高的戴森壳并移除其他戴森壳`
|
||||||
|
* `从发电量最高的壳复制戴森壳`
|
||||||
* 2.3.30
|
* 2.3.30
|
||||||
+ 修复了启用`无条件建造`或`无碰撞`时的警告问题
|
* 修复了启用`无条件建造`或`无碰撞`时的警告问题
|
||||||
+ 粘贴大规模蓝图时大幅提升`立即完成建造`的性能表现
|
* 粘贴大规模蓝图时大幅提升`立即完成建造`的性能表现
|
||||||
* 2.3.29
|
* 2.3.29
|
||||||
+ 修复了与游戏更新0.10.32.25779的兼容性
|
* 修复了与游戏更新0.10.32.25779的兼容性
|
||||||
* 2.3.28
|
* 2.3.28
|
||||||
+ 新功能:`快速手动制造`
|
* 新功能:`快速手动制造`
|
||||||
+ 修复了启用`自然资源采集不消耗`时部分面板的显示问题
|
* 修复了启用`自然资源采集不消耗`时部分面板的显示问题
|
||||||
* 2.3.27
|
* 2.3.27
|
||||||
+ `跳过子弹阶段`和`全球弹射`:修复了与`戴森球计划 v0.10.32.25496`的兼容性
|
* `跳过子弹阶段`和`全球弹射`:修复了与`戴森球计划 v0.10.32.25496`的兼容性
|
||||||
* 2.3.26
|
* 2.3.26
|
||||||
+ 重构代码以适应UXAssist 1.2.0
|
* 重构代码以适应UXAssist 1.2.0
|
||||||
- 在使用此版本之前,您应先更新UXAssist到1.2.0或更高版本。
|
* 在使用此版本之前,您应先更新UXAssist到1.2.0或更高版本。
|
||||||
+ `立即完成戴森壳建造`:修复了可能导致错误的生产记录的问题
|
* `立即完成戴森壳建造`:修复了可能导致错误的生产记录的问题
|
||||||
* 2.3.25
|
* 2.3.25
|
||||||
+ 新功能:`无需空间翘曲器即可曲速飞行`
|
* 新功能:`无需空间翘曲器即可曲速飞行`
|
||||||
+ 新功能:`风力涡轮机供电覆盖全球`
|
* 新功能:`风力涡轮机供电覆盖全球`
|
||||||
+ 修复了`立即完成戴森壳建造`未生成太阳帆生产记录的问题
|
* 修复了`立即完成戴森壳建造`未生成太阳帆生产记录的问题
|
||||||
* 2.3.24
|
* 2.3.24
|
||||||
+ `立即完成戴森壳建造`:修复了在某些情况下可能导致发电为负的问题
|
* `立即完成戴森壳建造`:修复了在某些情况下可能导致发电为负的问题
|
||||||
* 2.3.23
|
* 2.3.23
|
||||||
+ 新功能:`立即完成戴森壳建造`
|
* 新功能:`立即完成戴森壳建造`
|
||||||
+ 修复了在游戏完全加载前打开配置面板可能导致的崩溃问题
|
* 修复了在游戏完全加载前打开配置面板可能导致的崩溃问题
|
||||||
* 2.3.22
|
* 2.3.22
|
||||||
+ 修复了`平地抽水`
|
* 修复了`平地抽水`
|
||||||
* 2.3.21
|
* 2.3.21
|
||||||
+ `在物流总控面板上可以从非本地行星取放物品`:当从非本地星球的物流站移除槽位时,物品会放回玩家的背包
|
* `在物流总控面板上可以从非本地行星取放物品`:当从非本地星球的物流站移除槽位时,物品会放回玩家的背包
|
||||||
+ `开发模式快捷键`:摄像机位(Pose)相关的快捷键现在生效了
|
* `开发模式快捷键`:摄像机位(Pose)相关的快捷键现在生效了
|
||||||
* 2.3.20
|
* 2.3.20
|
||||||
+ 新功能:`在物流总控面板上可以从非本地行星取放物品`
|
* 新功能:`在物流总控面板上可以从非本地行星取放物品`
|
||||||
* 2.3.19
|
* 2.3.19
|
||||||
+ 新功能:
|
* 新功能:
|
||||||
+ `移除所有元数据消耗记录`
|
* `移除所有元数据消耗记录`
|
||||||
+ `移除当前存档的元数据消耗记录`
|
* `移除当前存档的元数据消耗记录`
|
||||||
+ `解除当前存档因使用元数据导致的成就限制`
|
* `解除当前存档因使用元数据导致的成就限制`
|
||||||
* 2.3.18
|
* 2.3.18
|
||||||
+ 新功能:
|
* 新功能:
|
||||||
+ `传送到外太空`,这会将你传送到距离最远星球50光年的外太空
|
* `传送到外太空`,这会将你传送到距离最远星球50光年的外太空
|
||||||
+ `传送到选中天体`
|
* `传送到选中天体`
|
||||||
+ 修复了`组合键解锁科技`的逻辑
|
* 修复了`组合键解锁科技`的逻辑
|
||||||
+ `无条件建造`现在不会隐藏传送带的旋转信息了
|
* `无条件建造`现在不会隐藏传送带的旋转信息了
|
||||||
* 2.3.17
|
* 2.3.17
|
||||||
+ 适配游戏版本0.10.30.23292
|
* 适配游戏版本0.10.30.23292
|
||||||
* 2.3.16
|
* 2.3.16
|
||||||
+ 为`传送带信号物品生成`添加了两个选项:
|
* 为`传送带信号物品生成`添加了两个选项:
|
||||||
- `统计信息里将生成计算为产物`
|
* `统计信息里将生成计算为产物`
|
||||||
- `统计信息里将移除计算为消耗`
|
* `统计信息里将移除计算为消耗`
|
||||||
+ 新功能:`提升物流塔和大型采矿机的最大功耗`
|
* 新功能:`提升物流塔和大型采矿机的最大功耗`
|
||||||
- 物流塔:将最大充电功率提高到3GW(星际物流塔)和600MW(行星物流塔)(原来的10倍)
|
* 物流塔:将最大充电功率提高到3GW(星际物流塔)和600MW(行星物流塔)(原来的10倍)
|
||||||
- 大型采矿机:将最大采矿速度提高到1000%
|
* 大型采矿机:将最大采矿速度提高到1000%
|
||||||
* 2.3.15
|
* 2.3.15
|
||||||
+ 新功能:
|
* 新功能:
|
||||||
- `快速传送(和沙盒模式一样)`
|
* `快速传送(和沙盒模式一样)`
|
||||||
- `机甲和战斗无人机无敌`
|
* `机甲和战斗无人机无敌`
|
||||||
- `建筑无敌`
|
* `建筑无敌`
|
||||||
* 2.3.14
|
* 2.3.14
|
||||||
+ 移除了`无条件建造`和`无碰撞`的默认快捷键,以避免误操作。如有需要请手动在系统选项窗口中设置。
|
* 移除了`无条件建造`和`无碰撞`的默认快捷键,以避免误操作。如有需要请手动在系统选项窗口中设置。
|
||||||
+ 修复了翻译问题。
|
* 修复了翻译问题。
|
||||||
* 2.3.13
|
* 2.3.13
|
||||||
+ 修复了快捷键无效和设置窗口上的按键显示问题
|
* 修复了快捷键无效和设置窗口上的按键显示问题
|
||||||
* 2.3.12
|
* 2.3.12
|
||||||
+ 添加了一个快捷键来切换`无碰撞`,你可以在系统设置面板中修改快捷键。
|
* 添加了一个快捷键来切换`无碰撞`,你可以在系统设置面板中修改快捷键。
|
||||||
+ 在使用快捷键切换`无条件建造`和`无碰撞`时添加了实时提示信息。
|
* 在使用快捷键切换`无条件建造`和`无碰撞`时添加了实时提示信息。
|
||||||
* 2.3.11
|
* 2.3.11
|
||||||
+ 添加了一个快捷键来切换`无条件建造`,你可以在系统设置面板中修改快捷键。这依赖于[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) 1.0.15或更高版本
|
* 添加了一个快捷键来切换`无条件建造`,你可以在系统设置面板中修改快捷键。这依赖于[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) 1.0.15或更高版本
|
||||||
* 2.3.10
|
* 2.3.10
|
||||||
+ 修复了以下功能在新游戏版本中不生效的问题:
|
* 修复了以下功能在新游戏版本中不生效的问题:
|
||||||
- `平地抽水`
|
* `平地抽水`
|
||||||
- `沙土不够时依然可以整改地形`
|
* `沙土不够时依然可以整改地形`
|
||||||
* 2.3.9
|
* 2.3.9
|
||||||
+ 支持游戏版本0.10.28.21219
|
* 支持游戏版本0.10.28.21219
|
||||||
* 2.3.8
|
* 2.3.8
|
||||||
+ 修复了启用`建造秒完成`时开新游戏可能导致崩溃的问题
|
* 修复了启用`建造秒完成`时开新游戏可能导致崩溃的问题
|
||||||
+ 修复了UI按钮宽度
|
* 修复了UI按钮宽度
|
||||||
* 2.3.7
|
* 2.3.7
|
||||||
+ 支持游戏版本0.10.28.20759
|
* 支持游戏版本0.10.28.20759
|
||||||
+ 修复了传送带信号有时候物品生成速度和设置不匹配的问题
|
* 修复了传送带信号有时候物品生成速度和设置不匹配的问题
|
||||||
* 2.3.6
|
* 2.3.6
|
||||||
+ 在`建造秒完成`中支持UXAssist的新功能
|
* 在`建造秒完成`中支持UXAssist的新功能
|
||||||
+ 在启用`无条件建造`时添加警告信息
|
* 在启用`无条件建造`时添加警告信息
|
||||||
+ 修复了`建造秒完成`可能导致部分建筑无法立即完成的问题
|
* 修复了`建造秒完成`可能导致部分建筑无法立即完成的问题
|
||||||
* 2.3.5
|
* 2.3.5
|
||||||
+ 修复了`跳过子弹阶段`可能导致崩溃的问题
|
* 修复了`跳过子弹阶段`可能导致崩溃的问题
|
||||||
* 2.3.4
|
* 2.3.4
|
||||||
+ 使用UXAssist 1.0.2的新页签布局
|
* 使用UXAssist 1.0.2的新页签布局
|
||||||
+ 修复了一些小bug
|
* 修复了一些小bug
|
||||||
* 2.3.3
|
* 2.3.3
|
||||||
+ 修复了`跳过子弹阶段`可能导致崩溃的问题
|
* 修复了`跳过子弹阶段`可能导致崩溃的问题
|
||||||
+ 使用Alt解锁科技时,现在`矿物利用`的科技解锁到10000级而不是7200级,因为UXAssist已修复对应bug
|
* 使用Alt解锁科技时,现在`矿物利用`的科技解锁到10000级而不是7200级,因为UXAssist已修复对应bug
|
||||||
* 2.3.2
|
* 2.3.2
|
||||||
+ 母星系的选项移动到了[UniverseGenTweaks](https://dsp.thunderstore.io/package/soarqin/UniverseGenTweaks/)
|
* 母星系的选项移动到了[UniverseGenTweaks](https://dsp.thunderstore.io/package/soarqin/UniverseGenTweaks/)
|
||||||
+ 优化了`快速吸收`,现在消耗更少的CPU,并且会轮流打向各节点
|
* 优化了`快速吸收`,现在消耗更少的CPU,并且会轮流打向各节点
|
||||||
+ `高速采集`现在可以保证油井的最大产出
|
* `高速采集`现在可以保证油井的最大产出
|
||||||
+ 修复了`传送带信号物品生成`在选项关闭后再次启用时不生效的问题
|
* 修复了`传送带信号物品生成`在选项关闭后再次启用时不生效的问题
|
||||||
+ 修复了`快速吸收`和`跳过子弹阶段`同时启用时可能导致吸收计算错误的问题
|
* 修复了`快速吸收`和`跳过子弹阶段`同时启用时可能导致吸收计算错误的问题
|
||||||
+ 修复了一些选项可能导致崩溃的问题
|
* 修复了一些选项可能导致崩溃的问题
|
||||||
* 2.3.1
|
* 2.3.1
|
||||||
+ 在manifest中添加UXAssist到依赖
|
* 在manifest中添加UXAssist到依赖
|
||||||
* 2.3.0
|
* 2.3.0
|
||||||
+ 将部分功能移动到单独的mod:[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
|
* 将部分功能移动到单独的mod:[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
|
||||||
+ 现在依赖[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist),因此配置面板与UXAssist合并
|
* 现在依赖[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist),因此配置面板与UXAssist合并
|
||||||
+ 从开发模式快捷键中移除`LCtrl+A`,以避免误操作
|
* 从开发模式快捷键中移除`LCtrl+A`,以避免误操作
|
||||||
+ 现在`建筑师模式`中配送机/物流机/物流船也无限了
|
* 现在`建筑师模式`中配送机/物流机/物流船也无限了
|
||||||
* 2.2.7
|
* 2.2.7
|
||||||
+ 新功能:`只建造节点不建造框架`
|
* 新功能:`只建造节点不建造框架`
|
||||||
+ 打开设置面板时不再关闭背包面板
|
* 打开设置面板时不再关闭背包面板
|
||||||
+ 在`移除部分不影响游戏逻辑的建造条件`启用时移除`输入方向冲突`的检查条件
|
* 在`移除部分不影响游戏逻辑的建造条件`启用时移除`输入方向冲突`的检查条件
|
||||||
+ 修复导致`传送带信号替换格式`不切换传送带信号数字格式的问题
|
* 修复导致`传送带信号替换格式`不切换传送带信号数字格式的问题
|
||||||
* 2.2.6
|
* 2.2.6
|
||||||
+ 新功能:`可用节点全部造完时停止弹射`
|
* 新功能:`可用节点全部造完时停止弹射`
|
||||||
+ 修复了在未完成的节点上吸收太阳帆的问题
|
* 修复了在未完成的节点上吸收太阳帆的问题
|
||||||
* 2.2.5
|
* 2.2.5
|
||||||
+ 在同时启用`快速吸收`、`跳过子弹阶段`和`跳过吸收阶段`时,所有弹射的太阳帆会跳过所有中间环节立即吸收
|
* 在同时启用`快速吸收`、`跳过子弹阶段`和`跳过吸收阶段`时,所有弹射的太阳帆会跳过所有中间环节立即吸收
|
||||||
+ 修复了`快速吸收`在大部分节点已满时无法立即吸收所有太阳帆的问题
|
* 修复了`快速吸收`在大部分节点已满时无法立即吸收所有太阳帆的问题
|
||||||
+ 修复了与一些mod的兼容性问题
|
* 修复了与一些mod的兼容性问题
|
||||||
* 2.2.4
|
* 2.2.4
|
||||||
+ 新功能:`在行星视图中允许玩家操作`
|
* 新功能:`在行星视图中允许玩家操作`
|
||||||
+ 修复了UI显示问题
|
* 修复了UI显示问题
|
||||||
* 2.2.3
|
* 2.2.3
|
||||||
+ 新功能:`移除部分不影响游戏逻辑的建造条件`
|
* 新功能:`移除部分不影响游戏逻辑的建造条件`
|
||||||
+ 修复了与一些mod的兼容性问题
|
* 修复了与一些mod的兼容性问题
|
||||||
* 2.2.2
|
* 2.2.2
|
||||||
+ 新功能:`将游戏存档绑定给当前账号`
|
* 新功能:`将游戏存档绑定给当前账号`
|
||||||
+ 新子功能:`传送带信号替换格式`
|
* 新子功能:`传送带信号替换格式`
|
||||||
+ 修复了`初始化本行星`可能导致崩溃的问题
|
* 修复了`初始化本行星`可能导致崩溃的问题
|
||||||
+ 修复了`建造秒完成`中传送带建造的问题
|
* 修复了`建造秒完成`中传送带建造的问题
|
||||||
* 2.2.1
|
* 2.2.1
|
||||||
+ 即使在启用`无条件建造`时依然检查矿机的建造条件
|
* 即使在启用`无条件建造`时依然检查矿机的建造条件
|
||||||
+ 修复一个可能导致`无条件建造`不生效的问题
|
* 修复一个可能导致`无条件建造`不生效的问题
|
||||||
* 2.2.0
|
* 2.2.0
|
||||||
+ 添加了一些发电相关功能
|
* 添加了一些发电相关功能
|
||||||
+ 为传送带信号物品生成添加了一个子功能,在统计面板模拟了原材料和中间产物的生产过程
|
* 为传送带信号物品生成添加了一个子功能,在统计面板模拟了原材料和中间产物的生产过程
|
||||||
+ 从建筑师模式中分离了一些功能
|
* 从建筑师模式中分离了一些功能
|
||||||
* 2.1.0
|
* 2.1.0
|
||||||
+ 传送带信号物品生成
|
* 传送带信号物品生成
|
||||||
+ 修复窗口显示优先级可能导致提示信息被主窗口遮挡的问题
|
* 修复窗口显示优先级可能导致提示信息被主窗口遮挡的问题
|
||||||
* 2.0.0
|
* 2.0.0
|
||||||
+ 重构代码
|
* 重构代码
|
||||||
+ UI实现
|
* UI实现
|
||||||
+ 添加了很多功能
|
* 添加了很多功能
|
||||||
* 1.0.0
|
* 1.0.0
|
||||||
+ 初始版本
|
* 初始版本
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
using System;
|
using System.Reflection;
|
||||||
using System.Reflection;
|
|
||||||
using BepInEx;
|
using BepInEx;
|
||||||
|
using BepInEx.Configuration;
|
||||||
using CheatEnabler.Patches;
|
using CheatEnabler.Patches;
|
||||||
using HarmonyLib;
|
using CheatEnabler.Patches.Factory;
|
||||||
|
using FactoryPatch = CheatEnabler.Patches.Factory.FactoryPatch;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler;
|
namespace CheatEnabler;
|
||||||
|
|
||||||
@@ -16,6 +18,8 @@ public class CheatEnabler : BaseUnityPlugin
|
|||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
|
I18N.Init();
|
||||||
|
|
||||||
GamePatch.DevShortcutsEnabled = Config.Bind("General", "DevShortcuts", false, "Enable DevMode shortcuts");
|
GamePatch.DevShortcutsEnabled = Config.Bind("General", "DevShortcuts", false, "Enable DevMode shortcuts");
|
||||||
GamePatch.AbnormalDisablerEnabled = Config.Bind("General", "DisableAbnormalChecks", false,
|
GamePatch.AbnormalDisablerEnabled = Config.Bind("General", "DisableAbnormalChecks", false,
|
||||||
"disable all abnormal checks");
|
"disable all abnormal checks");
|
||||||
@@ -39,6 +43,8 @@ public class CheatEnabler : BaseUnityPlugin
|
|||||||
"Belt signal count removals as comsumption in statistics");
|
"Belt signal count removals as comsumption in statistics");
|
||||||
FactoryPatch.BeltSignalCountRecipeEnabled = Config.Bind("Build", "BeltSignalCountRecipe", false,
|
FactoryPatch.BeltSignalCountRecipeEnabled = Config.Bind("Build", "BeltSignalCountRecipe", false,
|
||||||
"Belt signal count all raws and intermediates in statistics");
|
"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,
|
FactoryPatch.RemovePowerSpaceLimitEnabled = Config.Bind("Build", "RemovePowerDistanceLimit", false,
|
||||||
"Remove distance limit for wind turbines and geothermals");
|
"Remove distance limit for wind turbines and geothermals");
|
||||||
FactoryPatch.BoostWindPowerEnabled = Config.Bind("Build", "BoostWindPower", false,
|
FactoryPatch.BoostWindPowerEnabled = Config.Bind("Build", "BoostWindPower", false,
|
||||||
@@ -51,8 +57,6 @@ public class CheatEnabler : BaseUnityPlugin
|
|||||||
"Boost geothermal power");
|
"Boost geothermal power");
|
||||||
FactoryPatch.WindTurbinesPowerGlobalCoverageEnabled = Config.Bind("Build", "PowerGlobalCoverage", false,
|
FactoryPatch.WindTurbinesPowerGlobalCoverageEnabled = Config.Bind("Build", "PowerGlobalCoverage", false,
|
||||||
"Global power coverage");
|
"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,
|
FactoryPatch.ControlPanelRemoteLogisticsEnabled = Config.Bind("Build", "ControlPanelRemoteLogistics", false,
|
||||||
"Retrieve/Place items from/to remote planets on logistics control panel");
|
"Retrieve/Place items from/to remote planets on logistics control panel");
|
||||||
ResourcePatch.InfiniteResourceEnabled = Config.Bind("Planet", "AlwaysInfiniteResource", false,
|
ResourcePatch.InfiniteResourceEnabled = Config.Bind("Planet", "AlwaysInfiniteResource", false,
|
||||||
@@ -71,6 +75,8 @@ public class CheatEnabler : BaseUnityPlugin
|
|||||||
"Enable warp without warper");
|
"Enable warp without warper");
|
||||||
DysonSpherePatch.SkipBulletEnabled = Config.Bind("DysonSphere", "SkipBullet", false,
|
DysonSpherePatch.SkipBulletEnabled = Config.Bind("DysonSphere", "SkipBullet", false,
|
||||||
"Skip bullet");
|
"Skip bullet");
|
||||||
|
DysonSpherePatch.FireAllBulletsEnabled = Config.Bind("DysonSphere", "FireAllBullets", false,
|
||||||
|
"Fire all bullets at once");
|
||||||
DysonSpherePatch.SkipAbsorbEnabled = Config.Bind("DysonSphere", "SkipAbsorb", false,
|
DysonSpherePatch.SkipAbsorbEnabled = Config.Bind("DysonSphere", "SkipAbsorb", false,
|
||||||
"Skip absorption");
|
"Skip absorption");
|
||||||
DysonSpherePatch.QuickAbsorbEnabled = Config.Bind("DysonSphere", "QuickAbsorb", false,
|
DysonSpherePatch.QuickAbsorbEnabled = Config.Bind("DysonSphere", "QuickAbsorb", false,
|
||||||
@@ -85,31 +91,22 @@ public class CheatEnabler : BaseUnityPlugin
|
|||||||
"Unlock Dyson Sphere max orbit radius");
|
"Unlock Dyson Sphere max orbit radius");
|
||||||
DysonSpherePatch.UnlockMaxOrbitRadiusValue = Config.Bind("DysonSphere", "MaxOrbitRadiusValue", 10_000_000f,
|
DysonSpherePatch.UnlockMaxOrbitRadiusValue = Config.Bind("DysonSphere", "MaxOrbitRadiusValue", 10_000_000f,
|
||||||
"Unlocked Dyson Sphere max orbit radius value");
|
"Unlocked Dyson Sphere max orbit radius value");
|
||||||
|
Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled = Config.Bind("DysonSphere", "IllegalDysonShellFunctions", false,
|
||||||
|
"Enable illegal dyson shell functions");
|
||||||
|
Functions.DysonSphereFunctions.ShellsCountForFunctions = Config.Bind("DysonSphere", "ShellsCountForFunctions", 2048,
|
||||||
|
new ConfigDescription("Shells count for various functions", new AcceptableValueRange<int>(
|
||||||
|
Functions.DysonSphereFunctions.MinShellsCountForFunctions,
|
||||||
|
Functions.DysonSphereFunctions.MaxShellsCountForFunctions)));
|
||||||
CombatPatch.MechaInvincibleEnabled = Config.Bind("Battle", "MechaInvincible", false,
|
CombatPatch.MechaInvincibleEnabled = Config.Bind("Battle", "MechaInvincible", false,
|
||||||
"Mecha and Drones/Fleets invincible");
|
"Mecha and Drones/Fleets invincible");
|
||||||
CombatPatch.BuildingsInvincibleEnabled = Config.Bind("Battle", "BuildingsInvincible", false,
|
CombatPatch.BuildingsInvincibleEnabled = Config.Bind("Battle", "BuildingsInvincible", false,
|
||||||
"Buildings invincible");
|
"Buildings invincible");
|
||||||
|
Localization.Register();
|
||||||
UIConfigWindow.Init();
|
UIConfigWindow.Init();
|
||||||
_patches = Util.GetTypesFiltered(Assembly.GetExecutingAssembly(),
|
// Register features (Init runs eagerly here); UXAssist drives the deferred lifecycle and starts
|
||||||
t => string.Equals(t.Namespace, "CheatEnabler.Patches", StringComparison.Ordinal) || string.Equals(t.Namespace, "CheatEnabler.Functions", StringComparison.Ordinal));
|
// this feature set immediately if its lifecycle has already begun.
|
||||||
_patches?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
ModFeatureRegistry.Discover(Assembly.GetExecutingAssembly());
|
||||||
}
|
|
||||||
|
|
||||||
private Type[] _patches;
|
I18N.Apply();
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
|
||||||
_patches?.Do(type => type.GetMethod("Start")?.Invoke(null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
_patches?.Do(type => type.GetMethod("Uninit")?.Invoke(null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if (VFInput.inputing) return;
|
|
||||||
FactoryPatch.OnInputUpdate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,45 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<BepInExPluginGuid>org.soardev.cheatenabler</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.cheatenabler</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - CheatEnabler</Description>
|
<Description>DSP MOD - CheatEnabler</Description>
|
||||||
<Version>2.3.31</Version>
|
<Version>2.4.4</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<PackageId>CheatEnabler</PackageId>
|
<PackageId>CheatEnabler</PackageId>
|
||||||
<RootNamespace>CheatEnabler</RootNamespace>
|
<RootNamespace>CheatEnabler</RootNamespace>
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
<PackHasChangelog>true</PackHasChangelog>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<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>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\UXAssist\UXAssist.csproj" />
|
<ProjectReference Include="..\UXAssist\UXAssist.csproj" />
|
||||||
</ItemGroup>
|
</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>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using CheatEnabler;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Functions.DysonSphere;
|
||||||
|
|
||||||
|
[ModFeature("DysonSphereResolver")]
|
||||||
|
public static class DysonSphereResolver
|
||||||
|
{
|
||||||
|
public static (global::DysonSphere sphere, StarData star)? ResolveCurrent()
|
||||||
|
{
|
||||||
|
var star = GameMain.localStar;
|
||||||
|
if (star == null) return null;
|
||||||
|
var sphere = GameMain.data.dysonSpheres[star.index];
|
||||||
|
if (sphere == null) return null;
|
||||||
|
return (sphere, star);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StarData ResolveEditorOrLocalStar()
|
||||||
|
{
|
||||||
|
var dysonEditor = UIRoot.instance?.uiGame?.dysonEditor;
|
||||||
|
if (dysonEditor != null && dysonEditor.gameObject.activeSelf)
|
||||||
|
{
|
||||||
|
return dysonEditor.selection.viewStar;
|
||||||
|
}
|
||||||
|
var star = GameMain.localStar;
|
||||||
|
if (star == null)
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.CheatEnabler.Translate(), Localization.YouAreNotInAnySystem.Translate(), Localization.OK.Translate(), UIMessageBox.ERROR, null);
|
||||||
|
}
|
||||||
|
return star;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (global::DysonSphere sphere, StarData star)? ResolveEditorOrLocalSphere(bool requireLayer = true)
|
||||||
|
{
|
||||||
|
var star = ResolveEditorOrLocalStar();
|
||||||
|
if (star == null) return null;
|
||||||
|
var sphere = GameMain.data?.dysonSpheres[star.index];
|
||||||
|
if (sphere == null)
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.CheatEnabler.Translate(), string.Format(Localization.ThereIsNoDysonSphereDataOn0.Translate(), star.displayName), Localization.OK.Translate(), UIMessageBox.ERROR, null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (requireLayer && sphere.layerCount == 0)
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.CheatEnabler.Translate(), string.Format(Localization.ThereIsNoDysonSphereShellOn0.Translate(), star.displayName), Localization.OK.Translate(), UIMessageBox.ERROR, null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (sphere, star);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.GameConstants;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using UXAssist.Common.Utils;
|
||||||
|
using CheatEnabler;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Functions.DysonSphere;
|
||||||
|
|
||||||
|
[ModFeature("FrameRemovalFunctions")]
|
||||||
|
public static class FrameRemovalFunctions
|
||||||
|
{
|
||||||
|
public static void RemoveAllFrames()
|
||||||
|
{
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere();
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, star) = resolved.Value;
|
||||||
|
|
||||||
|
UIMessageBox.Show(Localization.CheatEnabler.Translate(), string.Format(Localization.ThisWillRemoveAllFramesOn0AreYouSure.Translate(), star.displayName), Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.QUESTION, null, () =>
|
||||||
|
{
|
||||||
|
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(DysonSphereConstants.DefaultLayerPoolCapacity);
|
||||||
|
DysonSphereReflection.SetTotalFrameSP(dysonSphereLayer, 0);
|
||||||
|
}
|
||||||
|
dysonSphere.CheckAutoNodes();
|
||||||
|
dysonSphere.PickAutoNode();
|
||||||
|
dysonSphere.modelRenderer.RebuildModels();
|
||||||
|
dysonSphere.needRecalculatePower = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,792 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Functions.DysonSphere;
|
||||||
|
|
||||||
|
public static class GeometryHelpers
|
||||||
|
{
|
||||||
|
const ulong rawNum0 = 0x3FED4D1BA3920BFAUL; // cosr
|
||||||
|
const ulong rawNum1 = 0x3FD9B9832ADBFC16UL; // sinr
|
||||||
|
const ulong rawNum2 = 0x3FE279A74590331DUL;
|
||||||
|
const ulong rawNum3 = 0x3FEBB67AE8584CAAUL; // cos30
|
||||||
|
private static readonly double factor0 = RawToDouble(rawNum0);
|
||||||
|
private static readonly double factor1 = RawToDouble(rawNum1);
|
||||||
|
private static readonly double factor2 = RawToDouble(rawNum2);
|
||||||
|
private static readonly double factor3 = RawToDouble(rawNum3);
|
||||||
|
public static readonly PrecalculatedTriangle[] PrecalculatedTriangles = [
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 6869, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x45D66000U)}, PosB = new Vector3() { x = RawToFloat(0x2C88BEC4U), y = RawToFloat(0x00000000U), z = RawToFloat(0xC5D66000U)}, PosC = new Vector3() { x = RawToFloat(0xC5D66000U), y = RawToFloat(0x00000000U), z = RawToFloat(0xABB1589BU)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 13573, PosA = new Vector3() { x = RawToFloat(0x46540800U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2C87400AU)}, PosB = new Vector3() { x = RawToFloat(0x4652DEA6U), y = RawToFloat(0x00000000U), z = RawToFloat(0xC4B14E71U)}, PosC = new Vector3() { x = RawToFloat(0xC6540800U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAC2F683EU)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 21257, PosA = new Vector3() { x = RawToFloat(0x46A60400U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2CD3CBAAU)}, PosB = new Vector3() { x = RawToFloat(0xC6070C9DU), y = RawToFloat(0x00000000U), z = RawToFloat(0xC697A9AEU)}, PosC = new Vector3() { x = RawToFloat(0xC6A60400U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAC8956FFU)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 29718, PosA = new Vector3() { x = RawToFloat(0x469B4FBEU), y = RawToFloat(0x00000000U), z = RawToFloat(0x46AC7DAAU)}, PosB = new Vector3() { x = RawToFloat(0x46E81C00U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2D140EBCU)}, PosC = new Vector3() { x = RawToFloat(0xC6E81C00U), y = RawToFloat(0x00000000U), z = RawToFloat(0xACC0046AU)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 38834, PosA = new Vector3() { x = RawToFloat(0x4717AE00U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2D4181A3U)}, PosB = new Vector3() { x = RawToFloat(0x45FC49B0U), y = RawToFloat(0x00000000U), z = RawToFloat(0xC7145D79U)}, PosC = new Vector3() { x = RawToFloat(0xC717AE00U), y = RawToFloat(0x00000000U), z = RawToFloat(0xACFAF5D4U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 48523, PosA = new Vector3() { x = RawToFloat(0x473D8800U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2D71CBB9U)}, PosB = new Vector3() { x = RawToFloat(0xC73D8800U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAD1CCB2AU)}, PosC = new Vector3() { x = RawToFloat(0xC72D2539U), y = RawToFloat(0x00000000U), z = RawToFloat(0x469A2DB9U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 58724, PosA = new Vector3() { x = RawToFloat(0x47656000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2D925038U)}, PosB = new Vector3() { x = RawToFloat(0xC7656000U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAD3DC153U)}, PosC = new Vector3() { x = RawToFloat(0xC7518B63U), y = RawToFloat(0x00000000U), z = RawToFloat(0x46BA9727U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 69389, PosA = new Vector3() { x = RawToFloat(0x47878200U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2DACE001U)}, PosB = new Vector3() { x = RawToFloat(0xC7878200U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAD603407U)}, PosC = new Vector3() { x = RawToFloat(0xC7078200U), y = RawToFloat(0x00000000U), z = RawToFloat(0x476AB4D7U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 80481, PosA = new Vector3() { x = RawToFloat(0x479D3000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2DC88874U)}, PosB = new Vector3() { x = RawToFloat(0xC79D3000U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAD82095EU)}, PosC = new Vector3() { x = RawToFloat(0xC71D3000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x478820DDU)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 91970, PosA = new Vector3() { x = RawToFloat(0x47B2A01EU), y = RawToFloat(0x00000000U), z = RawToFloat(0x461631C0U)}, PosB = new Vector3() { x = RawToFloat(0x47B39C00U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2DE5234DU)}, PosC = new Vector3() { x = RawToFloat(0xC7B39C00U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAD9495E6U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 103831, PosA = new Vector3() { x = RawToFloat(0x476E65BEU), y = RawToFloat(0x00000000U), z = RawToFloat(0x47A4101EU)}, PosB = new Vector3() { x = RawToFloat(0x47CACB00U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2E015B75U)}, PosC = new Vector3() { x = RawToFloat(0xC7CACB00U), y = RawToFloat(0x00000000U), z = RawToFloat(0xADA7C3C0U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 116040, PosA = new Vector3() { x = RawToFloat(0x47E29F00U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2E108E84U)}, PosB = new Vector3() { x = RawToFloat(0xC7E29F00U), y = RawToFloat(0x00000000U), z = RawToFloat(0xADBB7A19U)}, PosC = new Vector3() { x = RawToFloat(0xC70C0F3EU), y = RawToFloat(0x00000000U), z = RawToFloat(0x47D7878CU)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 128580, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x47FB1D00U)}, PosB = new Vector3() { x = RawToFloat(0x47A80710U), y = RawToFloat(0x00000000U), z = RawToFloat(0x47BA9D10U)}, PosC = new Vector3() { x = RawToFloat(0x2EA02E04U), y = RawToFloat(0x00000000U), z = RawToFloat(0xC7FB1D00U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 141433, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x480A1D80U)}, PosB = new Vector3() { x = RawToFloat(0x47A25D3CU), y = RawToFloat(0x00000000U), z = RawToFloat(0x47DF79A3U)}, PosC = new Vector3() { x = RawToFloat(0x2EB03393U), y = RawToFloat(0x00000000U), z = RawToFloat(0xC80A1D80U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 154586, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x4816F500U)}, PosB = new Vector3() { x = RawToFloat(0x47B175ECU), y = RawToFloat(0x00000000U), z = RawToFloat(0x47F440EDU)}, PosC = new Vector3() { x = RawToFloat(0x2EC0959FU), y = RawToFloat(0x00000000U), z = RawToFloat(0xC816F500U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 168025, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x48241500U)}, PosB = new Vector3() { x = RawToFloat(0x48241500U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2E51542AU)}, PosC = new Vector3() { x = RawToFloat(0xC8241500U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAE07BD7FU)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 181738, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x48317880U)}, PosB = new Vector3() { x = RawToFloat(0x48317880U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2E6268D3U)}, PosC = new Vector3() { x = RawToFloat(0xC8317880U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAE12D0F8U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 195715, PosA = new Vector3() { x = RawToFloat(0x469FD288U), y = RawToFloat(0x00000000U), z = RawToFloat(0x483E1379U)}, PosB = new Vector3() { x = RawToFloat(0x483F1F80U), y = RawToFloat(0x00000000U), z = RawToFloat(0x2E73D398U)}, PosC = new Vector3() { x = RawToFloat(0xC83F1F80U), y = RawToFloat(0x00000000U), z = RawToFloat(0xAE1E1C47U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 209946, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x484D0500U)}, PosB = new Vector3() { x = RawToFloat(0x48092F52U), y = RawToFloat(0x00000000U), z = RawToFloat(0x48185BF5U)}, PosC = new Vector3() { x = RawToFloat(0x2F02C70CU), y = RawToFloat(0x00000000U), z = RawToFloat(0xC84D0500U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 224422, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x485B2900U)}, PosB = new Vector3() { x = RawToFloat(0x4812A593U), y = RawToFloat(0x00000000U), z = RawToFloat(0x4822DE24U)}, PosC = new Vector3() { x = RawToFloat(0x2F0BCC2BU), y = RawToFloat(0x00000000U), z = RawToFloat(0xC85B2900U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = 239136, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x48698680U)}, PosB = new Vector3() { x = RawToFloat(0x481C424DU), y = RawToFloat(0x00000000U), z = RawToFloat(0x482D8B0EU)}, PosC = new Vector3() { x = RawToFloat(0x2F14F5F7U), y = RawToFloat(0x00000000U), z = RawToFloat(0xC8698680U)} },
|
||||||
|
new PrecalculatedTriangle() { MaxOrbitRadius = DysonSphereConstants.MaxOrbitRadius, PosA = new Vector3() { x = RawToFloat(0x00000000U), y = RawToFloat(0x00000000U), z = RawToFloat(0x48742180U)}, PosB = new Vector3() { x = RawToFloat(0x48235AFEU), y = RawToFloat(0x00000000U), z = RawToFloat(0x48356CB1U)}, PosC = new Vector3() { x = RawToFloat(0x2F1BB9CEU), y = RawToFloat(0x00000000U), z = RawToFloat(0xC8742180U)} },
|
||||||
|
];
|
||||||
|
|
||||||
|
public struct PrecalculatedTriangle
|
||||||
|
{
|
||||||
|
public int MaxOrbitRadius;
|
||||||
|
public Vector3 PosA;
|
||||||
|
public Vector3 PosB;
|
||||||
|
public Vector3 PosC;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double RawToDouble(ulong value)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return *(double*)&value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float RawToFloat(uint value)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return *(float*)&value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DysonNode QuickAddDysonNode(this DysonSphereLayer layer, int protoId, Vector3 pos)
|
||||||
|
{
|
||||||
|
int nodeId;
|
||||||
|
if (layer.nodeRecycleCursor > 0)
|
||||||
|
{
|
||||||
|
int[] array = layer.nodeRecycle;
|
||||||
|
int num = layer.nodeRecycleCursor - 1;
|
||||||
|
layer.nodeRecycleCursor = num;
|
||||||
|
nodeId = array[num];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int nodePoolIndex = layer.nodeCursor;
|
||||||
|
layer.nodeCursor = nodePoolIndex + 1;
|
||||||
|
nodeId = nodePoolIndex;
|
||||||
|
if (nodeId == layer.nodeCapacity)
|
||||||
|
{
|
||||||
|
layer.SetNodeCapacity(layer.nodeCapacity * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DysonNode node = null;
|
||||||
|
if (layer.nodePool[nodeId] == null)
|
||||||
|
{
|
||||||
|
node = new DysonNode();
|
||||||
|
layer.nodePool[nodeId] = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = layer.nodePool[nodeId];
|
||||||
|
node.SetEmpty();
|
||||||
|
}
|
||||||
|
node.id = nodeId;
|
||||||
|
node.protoId = protoId;
|
||||||
|
node.layerId = layer.id;
|
||||||
|
node.pos = pos;
|
||||||
|
node.reserved = false;
|
||||||
|
node.sp = 0;
|
||||||
|
node.spMax = DysonNode.kSpPerNode;
|
||||||
|
layer.dysonSphere.AddDysonNodeRData(node, true);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
public static DysonFrame QuickAddDysonFrame(this DysonSphereLayer layer, int protoId, DysonNode nodeA, DysonNode nodeB, bool euler)
|
||||||
|
{
|
||||||
|
int newId;
|
||||||
|
if (layer.frameRecycleCursor > 0)
|
||||||
|
{
|
||||||
|
var array = layer.frameRecycle;
|
||||||
|
var index = layer.frameRecycleCursor - 1;
|
||||||
|
layer.frameRecycleCursor = index;
|
||||||
|
newId = array[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var index = layer.frameCursor;
|
||||||
|
layer.frameCursor = index + 1;
|
||||||
|
newId = index;
|
||||||
|
if (newId == layer.frameCapacity)
|
||||||
|
{
|
||||||
|
layer.SetFrameCapacity(layer.frameCapacity * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DysonFrame frame = layer.framePool[newId];
|
||||||
|
if (frame == null)
|
||||||
|
{
|
||||||
|
frame = new DysonFrame();
|
||||||
|
layer.framePool[newId] = frame;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frame = layer.framePool[newId];
|
||||||
|
frame.SetEmpty();
|
||||||
|
}
|
||||||
|
frame.id = newId;
|
||||||
|
frame.layerId = layer.id;
|
||||||
|
frame.protoId = protoId + DysonSphereSegmentRenderer.nodeProtoCount;
|
||||||
|
frame.reserved = false;
|
||||||
|
frame.nodeA = nodeA;
|
||||||
|
frame.nodeB = nodeB;
|
||||||
|
frame.euler = euler;
|
||||||
|
frame.spA = 0;
|
||||||
|
frame.spB = 0;
|
||||||
|
frame.spMax = frame.segCount * DysonFrame.kSpPerSeg;
|
||||||
|
nodeA.frames.Add(frame);
|
||||||
|
nodeB.frames.Add(frame);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
private static readonly ThreadLocal<Dictionary<int, Vector3>> _vmap = new(() => new(16384));
|
||||||
|
public static int CalculateTriangleVertCount(Vector3[] pos)
|
||||||
|
{
|
||||||
|
if (pos.Length != 3) return -1;
|
||||||
|
VectorLF3[] polygon = [pos[0], pos[1], pos[2]];
|
||||||
|
VectorLF3 sum = VectorLF3.zero;
|
||||||
|
double num = 0.0;
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
float num2 = Vector3.Distance(pos[i], pos[(i + 1) % 3]);
|
||||||
|
VectorLF3 vectorLF2 = ((VectorLF3)pos[i] + (VectorLF3)pos[(i + 1) % 3]) * 0.5;
|
||||||
|
sum += vectorLF2 * num2;
|
||||||
|
num += (double)num2;
|
||||||
|
}
|
||||||
|
var radius = Math.Round(polygon[0].magnitude * 10.0) / 10.0;
|
||||||
|
for (int j = 0; j < polygon.Length; j++)
|
||||||
|
{
|
||||||
|
polygon[j] = polygon[j].normalized * radius;
|
||||||
|
}
|
||||||
|
var normalized = (sum / num).normalized;
|
||||||
|
var center = normalized * radius;
|
||||||
|
float num3 = 0f;
|
||||||
|
for (int k = 0; k < 3; k++)
|
||||||
|
{
|
||||||
|
float num4 = Vector3.Distance(center, polygon[k]);
|
||||||
|
if (num4 > num3)
|
||||||
|
{
|
||||||
|
num3 = num4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var gridScale = (int)(Math.Pow(radius / DysonSphereConstants.GridScaleBaseRadius, 0.75) + 0.5);
|
||||||
|
gridScale = ((gridScale < 1) ? 1 : gridScale);
|
||||||
|
var gridSize = gridScale * DysonSphereConstants.GridSizeBase;
|
||||||
|
var gridSizeDouble = (double)gridSize;
|
||||||
|
var cpPerVertex = gridScale * gridScale * DysonSphereConstants.CpPerVertexFactor;
|
||||||
|
|
||||||
|
var num5 = (int)((double)num3 / factor3 / gridSizeDouble + 2.5);
|
||||||
|
var xaxis = VectorLF3.Cross(normalized, Vector3.up).normalized;
|
||||||
|
if (xaxis.magnitude < 0.1)
|
||||||
|
{
|
||||||
|
xaxis = new VectorLF3(0f, 0f, 1f);
|
||||||
|
}
|
||||||
|
var yaxis = VectorLF3.Cross(xaxis, normalized).normalized;
|
||||||
|
var raydir = xaxis * factor0 + yaxis * factor1;
|
||||||
|
var w1axis = xaxis * (0.5 * gridSizeDouble) - yaxis * (factor3 * gridSizeDouble);
|
||||||
|
var w2axis = xaxis * (0.5 * gridSizeDouble) + yaxis * (factor3 * gridSizeDouble);
|
||||||
|
var w0axis = xaxis * gridSizeDouble;
|
||||||
|
var t1axis = yaxis * (gridSizeDouble * factor2 * 0.5) - xaxis * (gridSizeDouble * 0.5);
|
||||||
|
var t2axis = yaxis * (gridSizeDouble * factor2 * 0.5) + xaxis * (gridSizeDouble * 0.5);
|
||||||
|
var t0axis = yaxis * (gridSizeDouble / factor3 * 0.5);
|
||||||
|
var polyn = new VectorLF3[3];
|
||||||
|
var polynu = new double[3];
|
||||||
|
for (int l = 0; l < 3; l++)
|
||||||
|
{
|
||||||
|
Vector3 vector = polygon[l];
|
||||||
|
Vector3 vector2 = polygon[(l + 1) % 3];
|
||||||
|
polyn[l] = VectorLF3.Cross(vector, vector2).normalized;
|
||||||
|
polynu[l] = polyn[l].x * raydir.x + polyn[l].y * raydir.y + polyn[l].z * raydir.z;
|
||||||
|
}
|
||||||
|
var vmap = _vmap.Value;
|
||||||
|
vmap.Clear();
|
||||||
|
double num7 = gridSizeDouble * 0.5;
|
||||||
|
for (int m = -num5; m <= num5; m++)
|
||||||
|
{
|
||||||
|
for (int n = -num5; n <= num5; n++)
|
||||||
|
{
|
||||||
|
if (m - n <= num5 && m - n >= -num5)
|
||||||
|
{
|
||||||
|
VectorLF3 vectorLF3;
|
||||||
|
vectorLF3.x = center.x + w0axis.x * m - w1axis.x * n;
|
||||||
|
vectorLF3.y = center.y + w0axis.y * m - w1axis.y * n;
|
||||||
|
vectorLF3.z = center.z + w0axis.z * m - w1axis.z * n;
|
||||||
|
double num8 = radius / vectorLF3.magnitude;
|
||||||
|
vectorLF3 *= num8;
|
||||||
|
int num9 = 0;
|
||||||
|
for (int num10 = 0; num10 < 3; num10++)
|
||||||
|
{
|
||||||
|
double num11 = -(polyn[num10].x * vectorLF3.x + polyn[num10].y * vectorLF3.y + polyn[num10].z * vectorLF3.z) / polynu[num10];
|
||||||
|
if (num11 >= 0.0)
|
||||||
|
{
|
||||||
|
VectorLF3 normalized2 = new VectorLF3(vectorLF3.x + num11 * raydir.x, vectorLF3.y + num11 * raydir.y, vectorLF3.z + num11 * raydir.z).normalized;
|
||||||
|
normalized2 *= radius;
|
||||||
|
VectorLF3 vectorLF4 = polygon[num10] - normalized2;
|
||||||
|
VectorLF3 vectorLF5 = polygon[(num10 + 1) % 3] - normalized2;
|
||||||
|
double num12 = vectorLF4.x * vectorLF5.x + vectorLF4.y * vectorLF5.y + vectorLF4.z * vectorLF5.z;
|
||||||
|
if (num12 < 0.0 || (num12 == 0.0 && vectorLF4.x == 0.0 && vectorLF4.y == 0.0 && vectorLF4.z == 0.0))
|
||||||
|
{
|
||||||
|
num9++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((num9 & 1) == 1)
|
||||||
|
{
|
||||||
|
int num13 = DysonShell._get_key(m, n);
|
||||||
|
vmap[num13] = vectorLF3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int num14 = 0; num14 < 3; num14++)
|
||||||
|
{
|
||||||
|
VectorLF3 vectorLF6 = polygon[num14];
|
||||||
|
VectorLF3 vectorLF7 = polyn[num14];
|
||||||
|
VectorLF3 vectorLF8 = vectorLF3 - vectorLF6;
|
||||||
|
double num15 = vectorLF7.x * vectorLF8.x + vectorLF7.y * vectorLF8.y + vectorLF7.z * vectorLF8.z;
|
||||||
|
double num16 = Math.Abs(num15);
|
||||||
|
if (num16 <= num7)
|
||||||
|
{
|
||||||
|
VectorLF3 vectorLF9 = polygon[(num14 + 1) % 3];
|
||||||
|
VectorLF3 vectorLF10 = vectorLF3 - vectorLF7 * num15;
|
||||||
|
VectorLF3 vectorLF11 = vectorLF9 - vectorLF6;
|
||||||
|
double magnitude = vectorLF11.magnitude;
|
||||||
|
VectorLF3 vectorLF12 = vectorLF11 / magnitude;
|
||||||
|
VectorLF3 vectorLF13 = vectorLF10 - vectorLF6;
|
||||||
|
double num17 = vectorLF12.x * vectorLF13.x + vectorLF12.y * vectorLF13.y + vectorLF12.z * vectorLF13.z;
|
||||||
|
double num18;
|
||||||
|
if (num17 < 0.0)
|
||||||
|
{
|
||||||
|
num18 = vectorLF8.magnitude;
|
||||||
|
}
|
||||||
|
else if (num17 > magnitude)
|
||||||
|
{
|
||||||
|
num18 = (vectorLF3 - vectorLF9).magnitude;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num18 = num16;
|
||||||
|
}
|
||||||
|
if (num18 <= num7)
|
||||||
|
{
|
||||||
|
int num19 = DysonShell._get_key(m, n);
|
||||||
|
vmap[num19] = vectorLF3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vmap.Count;
|
||||||
|
}
|
||||||
|
public static bool GenerateCustomShellGeometry(this DysonShell shell)
|
||||||
|
{
|
||||||
|
VectorLF3 sum = VectorLF3.zero;
|
||||||
|
double num = 0.0;
|
||||||
|
for (int i = 0; i < shell.frames.Count; i++)
|
||||||
|
{
|
||||||
|
double num2 = Vector3.Distance(shell.frames[i].nodeA.pos, shell.frames[i].nodeB.pos);
|
||||||
|
VectorLF3 vectorLF2 = ((VectorLF3)shell.frames[i].nodeA.pos + (VectorLF3)shell.frames[i].nodeB.pos) * 0.5;
|
||||||
|
sum += vectorLF2 * num2;
|
||||||
|
num += num2;
|
||||||
|
}
|
||||||
|
shell.radius = Math.Round(shell.polygon[0].magnitude * 10.0) / 10.0;
|
||||||
|
for (int j = 0; j < shell.polygon.Count; j++)
|
||||||
|
{
|
||||||
|
shell.polygon[j] = shell.polygon[j].normalized * shell.radius;
|
||||||
|
}
|
||||||
|
var normalized = (sum / num).normalized;
|
||||||
|
shell.center = normalized * shell.radius;
|
||||||
|
float num3 = 0f;
|
||||||
|
for (int k = 0; k < shell.polygon.Count; k++)
|
||||||
|
{
|
||||||
|
float num4 = Vector3.Distance(shell.center, shell.polygon[k]);
|
||||||
|
if (num4 > num3)
|
||||||
|
{
|
||||||
|
num3 = num4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell.gridScale = (int)(Math.Pow(shell.radius / DysonSphereConstants.GridScaleBaseRadius, 0.75) + 0.5);
|
||||||
|
shell.gridScale = ((shell.gridScale < 1) ? 1 : shell.gridScale);
|
||||||
|
shell.gridSize = shell.gridScale * DysonSphereConstants.GridSizeBase;
|
||||||
|
var gridSizeDouble = (double)shell.gridSize;
|
||||||
|
shell.cpPerVertex = shell.gridScale * shell.gridScale * DysonSphereConstants.CpPerVertexFactor;
|
||||||
|
int num5 = (int)((double)num3 / factor3 / gridSizeDouble + 2.5);
|
||||||
|
shell.xaxis = VectorLF3.Cross(normalized, Vector3.up).normalized;
|
||||||
|
if (shell.xaxis.magnitude < 0.1)
|
||||||
|
{
|
||||||
|
shell.xaxis = new VectorLF3(0f, 0f, 1f);
|
||||||
|
}
|
||||||
|
shell.yaxis = VectorLF3.Cross(shell.xaxis, normalized).normalized;
|
||||||
|
shell.raydir = shell.xaxis * factor0 + shell.yaxis * factor1;
|
||||||
|
shell.w1axis = shell.xaxis * (0.5 * gridSizeDouble) - shell.yaxis * (factor3 * gridSizeDouble);
|
||||||
|
shell.w2axis = shell.xaxis * (0.5 * gridSizeDouble) + shell.yaxis * (factor3 * gridSizeDouble);
|
||||||
|
shell.w0axis = shell.xaxis * gridSizeDouble;
|
||||||
|
shell.t1axis = shell.yaxis * (gridSizeDouble * factor2 * 0.5) - shell.xaxis * (gridSizeDouble * 0.5);
|
||||||
|
shell.t2axis = shell.yaxis * (gridSizeDouble * factor2 * 0.5) + shell.xaxis * (gridSizeDouble * 0.5);
|
||||||
|
shell.t0axis = shell.yaxis * (gridSizeDouble / factor3 * 0.5);
|
||||||
|
int count = shell.polygon.Count;
|
||||||
|
shell.polyn = new VectorLF3[count];
|
||||||
|
shell.polynu = new double[count];
|
||||||
|
for (int l = 0; l < count; l++)
|
||||||
|
{
|
||||||
|
shell.polyn[l] = VectorLF3.Cross(shell.polygon[l], shell.polygon[(l + 1) % count]).normalized;
|
||||||
|
shell.polynu[l] = shell.polyn[l].x * shell.raydir.x + shell.polyn[l].y * shell.raydir.y + shell.polyn[l].z * shell.raydir.z;
|
||||||
|
}
|
||||||
|
DysonShell.s_vmap.Clear();
|
||||||
|
DysonShell.s_outvmap.Clear();
|
||||||
|
DysonShell.s_ivmap.Clear();
|
||||||
|
double num7 = gridSizeDouble * 0.5;
|
||||||
|
for (int m = -num5; m <= num5; m++)
|
||||||
|
{
|
||||||
|
for (int n = -num5; n <= num5; n++)
|
||||||
|
{
|
||||||
|
if (m - n <= num5 && m - n >= -num5)
|
||||||
|
{
|
||||||
|
VectorLF3 vectorLF3;
|
||||||
|
vectorLF3.x = shell.center.x + shell.w0axis.x * m - shell.w1axis.x * n;
|
||||||
|
vectorLF3.y = shell.center.y + shell.w0axis.y * m - shell.w1axis.y * n;
|
||||||
|
vectorLF3.z = shell.center.z + shell.w0axis.z * m - shell.w1axis.z * n;
|
||||||
|
double num8 = shell.radius / vectorLF3.magnitude;
|
||||||
|
vectorLF3 *= num8;
|
||||||
|
int num9 = 0;
|
||||||
|
for (int num10 = 0; num10 < count; num10++)
|
||||||
|
{
|
||||||
|
double num11 = -(shell.polyn[num10].x * vectorLF3.x + shell.polyn[num10].y * vectorLF3.y + shell.polyn[num10].z * vectorLF3.z) / shell.polynu[num10];
|
||||||
|
if (num11 >= 0.0)
|
||||||
|
{
|
||||||
|
VectorLF3 normalized2 = new VectorLF3(vectorLF3.x + num11 * shell.raydir.x, vectorLF3.y + num11 * shell.raydir.y, vectorLF3.z + num11 * shell.raydir.z).normalized;
|
||||||
|
normalized2 *= shell.radius;
|
||||||
|
VectorLF3 vectorLF4 = shell.polygon[num10] - normalized2;
|
||||||
|
VectorLF3 vectorLF5 = shell.polygon[(num10 + 1) % count] - normalized2;
|
||||||
|
double num12 = vectorLF4.x * vectorLF5.x + vectorLF4.y * vectorLF5.y + vectorLF4.z * vectorLF5.z;
|
||||||
|
if (num12 < 0.0 || (num12 == 0.0 && vectorLF4.x == 0.0 && vectorLF4.y == 0.0 && vectorLF4.z == 0.0))
|
||||||
|
{
|
||||||
|
num9++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((num9 & 1) == 1)
|
||||||
|
{
|
||||||
|
int num13 = DysonShell._get_key(m, n);
|
||||||
|
DysonShell.s_vmap[num13] = vectorLF3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int num14 = 0; num14 < count; num14++)
|
||||||
|
{
|
||||||
|
VectorLF3 vectorLF6 = shell.polygon[num14];
|
||||||
|
VectorLF3 vectorLF7 = shell.polyn[num14];
|
||||||
|
VectorLF3 vectorLF8 = vectorLF3 - vectorLF6;
|
||||||
|
double num15 = vectorLF7.x * vectorLF8.x + vectorLF7.y * vectorLF8.y + vectorLF7.z * vectorLF8.z;
|
||||||
|
double num16 = Math.Abs(num15);
|
||||||
|
if (num16 <= num7)
|
||||||
|
{
|
||||||
|
VectorLF3 vectorLF9 = shell.polygon[(num14 + 1) % count];
|
||||||
|
VectorLF3 vectorLF10 = vectorLF3 - vectorLF7 * num15;
|
||||||
|
VectorLF3 vectorLF11 = vectorLF9 - vectorLF6;
|
||||||
|
double magnitude = vectorLF11.magnitude;
|
||||||
|
VectorLF3 vectorLF12 = vectorLF11 / magnitude;
|
||||||
|
VectorLF3 vectorLF13 = vectorLF10 - vectorLF6;
|
||||||
|
double num17 = vectorLF12.x * vectorLF13.x + vectorLF12.y * vectorLF13.y + vectorLF12.z * vectorLF13.z;
|
||||||
|
double num18;
|
||||||
|
if (num17 < 0.0)
|
||||||
|
{
|
||||||
|
num18 = vectorLF8.magnitude;
|
||||||
|
}
|
||||||
|
else if (num17 > magnitude)
|
||||||
|
{
|
||||||
|
num18 = (vectorLF3 - vectorLF9).magnitude;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num18 = num16;
|
||||||
|
}
|
||||||
|
if (num18 <= num7)
|
||||||
|
{
|
||||||
|
int num19 = DysonShell._get_key(m, n);
|
||||||
|
DysonShell.s_vmap[num19] = vectorLF3;
|
||||||
|
DysonShell.s_outvmap[num19] = vectorLF3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int count2 = DysonShell.s_vmap.Count;
|
||||||
|
if (count2 > DysonSphereConstants.MaxShellVertices)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
shell.verts = new Vector3[count2];
|
||||||
|
shell.uvs = new Vector2[count2];
|
||||||
|
shell.uv2s = new Vector2[count2];
|
||||||
|
shell.vkeys = new int[count2];
|
||||||
|
shell._gen_points_topo_indices(count2);
|
||||||
|
shell.vAdjs = new short[count2 * 6];
|
||||||
|
for (int num20 = 0; num20 < shell.vAdjs.Length; num20++)
|
||||||
|
{
|
||||||
|
shell.vAdjs[num20] = -1;
|
||||||
|
}
|
||||||
|
int num21 = 0;
|
||||||
|
foreach (KeyValuePair<int, Vector3> keyValuePair in DysonShell.s_vmap)
|
||||||
|
{
|
||||||
|
Vector3 value = keyValuePair.Value;
|
||||||
|
DysonShell.s_ivmap[keyValuePair.Key] = num21;
|
||||||
|
shell.verts[num21] = value;
|
||||||
|
shell.uv2s[num21].x = DysonShell.s_outvmap.ContainsKey(keyValuePair.Key) ? 0 : 1;
|
||||||
|
shell.vkeys[num21] = keyValuePair.Key;
|
||||||
|
num21++;
|
||||||
|
}
|
||||||
|
foreach (KeyValuePair<int, int> keyValuePair2 in DysonShell.s_ivmap)
|
||||||
|
{
|
||||||
|
int key = keyValuePair2.Key;
|
||||||
|
int num22 = DysonShell.s_ivmap[key];
|
||||||
|
int num23 = key + 65536;
|
||||||
|
int num24 = key - 1;
|
||||||
|
int num25 = key - 65537;
|
||||||
|
int num26 = key - 65536;
|
||||||
|
int num27 = key + 1;
|
||||||
|
int num28 = key + 65537;
|
||||||
|
bool flag = DysonShell.s_ivmap.ContainsKey(num23);
|
||||||
|
bool flag2 = DysonShell.s_ivmap.ContainsKey(num24);
|
||||||
|
bool flag3 = DysonShell.s_ivmap.ContainsKey(num25);
|
||||||
|
bool flag4 = DysonShell.s_ivmap.ContainsKey(num26);
|
||||||
|
bool flag5 = DysonShell.s_ivmap.ContainsKey(num27);
|
||||||
|
bool flag6 = DysonShell.s_ivmap.ContainsKey(num28);
|
||||||
|
shell.vAdjs[num22 * 6] = (short)(flag ? DysonShell.s_ivmap[num23] : (-1));
|
||||||
|
shell.vAdjs[num22 * 6 + 1] = (short)(flag2 ? DysonShell.s_ivmap[num24] : (-1));
|
||||||
|
shell.vAdjs[num22 * 6 + 2] = (short)(flag3 ? DysonShell.s_ivmap[num25] : (-1));
|
||||||
|
shell.vAdjs[num22 * 6 + 3] = (short)(flag4 ? DysonShell.s_ivmap[num26] : (-1));
|
||||||
|
shell.vAdjs[num22 * 6 + 4] = (short)(flag5 ? DysonShell.s_ivmap[num27] : (-1));
|
||||||
|
shell.vAdjs[num22 * 6 + 5] = (short)(flag6 ? DysonShell.s_ivmap[num28] : (-1));
|
||||||
|
}
|
||||||
|
int num29 = 0;
|
||||||
|
int num30 = 0;
|
||||||
|
for (int num31 = 0; num31 < count2; num31++)
|
||||||
|
{
|
||||||
|
double num32 = shell.radius * 2.0;
|
||||||
|
int num33 = -1;
|
||||||
|
VectorLF3 vectorLF14 = shell.verts[num31];
|
||||||
|
for (int num34 = 0; num34 < count; num34++)
|
||||||
|
{
|
||||||
|
VectorLF3 vectorLF15 = shell.polygon[num34];
|
||||||
|
VectorLF3 vectorLF16 = shell.polygon[(num34 + 1) % count];
|
||||||
|
VectorLF3 vectorLF17 = shell.polyn[num34];
|
||||||
|
VectorLF3 vectorLF18 = vectorLF14 - vectorLF15;
|
||||||
|
double num35 = vectorLF17.x * vectorLF18.x + vectorLF17.y * vectorLF18.y + vectorLF17.z * vectorLF18.z;
|
||||||
|
VectorLF3 vectorLF19 = vectorLF14 - vectorLF17 * num35;
|
||||||
|
VectorLF3 vectorLF20 = vectorLF14 - vectorLF16;
|
||||||
|
double num36 = vectorLF17.x * vectorLF20.x + vectorLF17.y * vectorLF20.y + vectorLF17.z * vectorLF20.z;
|
||||||
|
VectorLF3 vectorLF21 = vectorLF16 - vectorLF15;
|
||||||
|
double magnitude2 = vectorLF21.magnitude;
|
||||||
|
VectorLF3 vectorLF22 = vectorLF21 / magnitude2;
|
||||||
|
VectorLF3 vectorLF23 = vectorLF19 - vectorLF15;
|
||||||
|
double num37 = vectorLF22.x * vectorLF23.x + vectorLF22.y * vectorLF23.y + vectorLF22.z * vectorLF23.z;
|
||||||
|
double num38;
|
||||||
|
if (num37 < 0.0)
|
||||||
|
{
|
||||||
|
num38 = (vectorLF14 - vectorLF15).magnitude;
|
||||||
|
num38 -= Math.Abs(num35) * 0.001;
|
||||||
|
}
|
||||||
|
else if (num37 > magnitude2)
|
||||||
|
{
|
||||||
|
num38 = (vectorLF14 - vectorLF16).magnitude;
|
||||||
|
num38 -= Math.Abs(num36) * 0.001;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num38 = Math.Abs(num35);
|
||||||
|
num38 -= Math.Abs(num35) * 0.001;
|
||||||
|
}
|
||||||
|
if (num38 < num32)
|
||||||
|
{
|
||||||
|
num32 = num38;
|
||||||
|
num33 = num34;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell.uv2s[num31].y = num33;
|
||||||
|
if (num29 + num30 < 49 && shell._is_point_in_shell(vectorLF14))
|
||||||
|
{
|
||||||
|
double num39 = VectorLF3.Dot(vectorLF14 - shell.polygon[num33], shell.polyn[num33]);
|
||||||
|
if (num39 > 0.1)
|
||||||
|
{
|
||||||
|
num29++;
|
||||||
|
}
|
||||||
|
else if (num39 < -0.1)
|
||||||
|
{
|
||||||
|
num30++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num29 > num30)
|
||||||
|
{
|
||||||
|
shell.clockwise = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shell.clockwise = false;
|
||||||
|
}
|
||||||
|
shell.vertAttr = new int[count2];
|
||||||
|
shell.vertsq = new short[count2];
|
||||||
|
shell.vertsqOffset = new int[shell.nodes.Count + 1];
|
||||||
|
int count3 = shell.nodes.Count;
|
||||||
|
int num40 = count3 / 2;
|
||||||
|
for (int num41 = 0; num41 < count2; num41++)
|
||||||
|
{
|
||||||
|
Vector3 vector3 = shell.verts[num41];
|
||||||
|
double num42 = double.MaxValue;
|
||||||
|
int num43 = 0;
|
||||||
|
int num44 = 0;
|
||||||
|
int num45 = num41 + 479001600;
|
||||||
|
for (int num46 = 0; num46 < count3; num46++)
|
||||||
|
{
|
||||||
|
int num47 = num45 % count3 - num46;
|
||||||
|
if (num47 < 0)
|
||||||
|
{
|
||||||
|
num47 = -num47;
|
||||||
|
}
|
||||||
|
if (num47 > num40)
|
||||||
|
{
|
||||||
|
num47 = count3 - num47;
|
||||||
|
}
|
||||||
|
double num48 = (double)(vector3 - shell.nodes[num46].pos).sqrMagnitude;
|
||||||
|
num48 += num47;
|
||||||
|
if (num48 < num42)
|
||||||
|
{
|
||||||
|
num42 = num48;
|
||||||
|
num43 = shell.nodes[num46].id;
|
||||||
|
num44 = num46;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell.vertAttr[num41] = num43;
|
||||||
|
shell.vertsqOffset[num44]++;
|
||||||
|
}
|
||||||
|
int num49 = 0;
|
||||||
|
for (int num50 = 0; num50 < shell.vertsqOffset.Length; num50++)
|
||||||
|
{
|
||||||
|
num49 += shell.vertsqOffset[num50];
|
||||||
|
}
|
||||||
|
Assert.True(num49 == count2);
|
||||||
|
for (int num51 = shell.vertsqOffset.Length - 1; num51 >= 0; num51--)
|
||||||
|
{
|
||||||
|
shell.vertsqOffset[num51] = num49;
|
||||||
|
if (num51 > 0)
|
||||||
|
{
|
||||||
|
num49 -= shell.vertsqOffset[num51 - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.Zero(num49);
|
||||||
|
shell._openListPrepare();
|
||||||
|
int num52 = shell.randSeed;
|
||||||
|
int num53 = 0;
|
||||||
|
while (num53 < count3)
|
||||||
|
{
|
||||||
|
Vector3 pos = shell.nodes[num53].pos;
|
||||||
|
int num54 = shell.nodes[num53].id;
|
||||||
|
float num55 = float.MaxValue;
|
||||||
|
int num56 = -1;
|
||||||
|
for (int num57 = 0; num57 < count2; num57++)
|
||||||
|
{
|
||||||
|
if (shell.vertAttr[num57] == num54 && (shell.vAdjs[num57 * 6] >= 0 || shell.vAdjs[num57 * 6 + 1] >= 0 || shell.vAdjs[num57 * 6 + 2] >= 0 || shell.vAdjs[num57 * 6 + 3] >= 0 || shell.vAdjs[num57 * 6 + 4] >= 0 || shell.vAdjs[num57 * 6 + 5] >= 0))
|
||||||
|
{
|
||||||
|
float sqrMagnitude = (shell.verts[num57] - pos).sqrMagnitude;
|
||||||
|
if (sqrMagnitude < num55)
|
||||||
|
{
|
||||||
|
num55 = sqrMagnitude;
|
||||||
|
num56 = num57;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num56 >= 0)
|
||||||
|
{
|
||||||
|
shell._openListAdd(num56);
|
||||||
|
}
|
||||||
|
int num58 = shell.vertsqOffset[num53];
|
||||||
|
int num59 = shell.vertsqOffset[num53 + 1] - shell.vertsqOffset[num53];
|
||||||
|
double num60 = 0.0;
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
|
int num61 = shell._traverseRandomVertex(shell.nodes[num53].id, ref num52);
|
||||||
|
if (num61 < 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
shell.vertsq[num58++] = (short)num61;
|
||||||
|
num60 += 1.0;
|
||||||
|
shell.uvs[num61].x = num53;
|
||||||
|
shell.uvs[num61].y = (float)(num60 / num59);
|
||||||
|
if (num58 == shell.vertsqOffset[num53 + 1])
|
||||||
|
{
|
||||||
|
goto Block_57;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IL_1329:
|
||||||
|
if (num58 < shell.vertsqOffset[num53 + 1])
|
||||||
|
{
|
||||||
|
for (int num62 = 0; num62 < count2; num62++)
|
||||||
|
{
|
||||||
|
if (shell.vertAttr[num62] == num54 && !shell._tmp_marked[num62])
|
||||||
|
{
|
||||||
|
shell.vertsq[num58++] = (short)num62;
|
||||||
|
num60 += 1.0;
|
||||||
|
shell.uvs[num62].x = num53;
|
||||||
|
shell.uvs[num62].y = (float)(num60 / num59);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.False(num58 > shell.vertsqOffset[num53 + 1]);
|
||||||
|
Assert.False(num58 < shell.vertsqOffset[num53 + 1]);
|
||||||
|
shell._openListClear();
|
||||||
|
num53++;
|
||||||
|
continue;
|
||||||
|
Block_57:
|
||||||
|
Assert.Zero(shell._tmp_openCount);
|
||||||
|
goto IL_1329;
|
||||||
|
}
|
||||||
|
shell._openListFree();
|
||||||
|
shell.vertexCount = count2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public static int QuickAddDysonShell(this DysonSphereLayer layer, int protoId, DysonNode[] nodes, DysonFrame[] frames, bool limit)
|
||||||
|
{
|
||||||
|
int shellId = 0;
|
||||||
|
if (layer.shellRecycleCursor > 0)
|
||||||
|
{
|
||||||
|
int[] array = layer.shellRecycle;
|
||||||
|
int index = layer.shellRecycleCursor - 1;
|
||||||
|
layer.shellRecycleCursor = index;
|
||||||
|
shellId = array[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int index = layer.shellCursor;
|
||||||
|
layer.shellCursor = index + 1;
|
||||||
|
shellId = index;
|
||||||
|
if (shellId == layer.shellCapacity)
|
||||||
|
{
|
||||||
|
layer.SetShellCapacity(layer.shellCapacity * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var shell = layer.shellPool[shellId];
|
||||||
|
if (shell == null)
|
||||||
|
{
|
||||||
|
shell = new DysonShell(layer);
|
||||||
|
layer.shellPool[shellId] = shell;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shell.SetEmpty();
|
||||||
|
}
|
||||||
|
shell.id = shellId;
|
||||||
|
shell.layerId = layer.id;
|
||||||
|
shell.protoId = protoId;
|
||||||
|
shell.randSeed = layer.id * DysonSphereConstants.ShellRandSeedMultiplier + shellId;
|
||||||
|
for (int j = 0; j < nodes.Length; j++)
|
||||||
|
{
|
||||||
|
DysonNode dysonNode = nodes[j];
|
||||||
|
DysonFrame dysonFrame = frames[j];
|
||||||
|
List<Vector3> segments = dysonFrame.GetSegments();
|
||||||
|
if (dysonNode == dysonFrame.nodeA)
|
||||||
|
{
|
||||||
|
for (int k = 0; k < segments.Count - 1; k++)
|
||||||
|
{
|
||||||
|
shell.polygon.Add(segments[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int l = segments.Count - 1; l >= 1; l--)
|
||||||
|
{
|
||||||
|
shell.polygon.Add(segments[l]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell.nodeIndexMap[dysonNode.id] = shell.nodes.Count;
|
||||||
|
shell.nodes.Add(dysonNode);
|
||||||
|
shell.frames.Add(dysonFrame);
|
||||||
|
}
|
||||||
|
if (!shell.GenerateCustomShellGeometry() || (limit && DysonShell.s_vmap.Count < DysonSphereConstants.MinShellVertexThreshold))
|
||||||
|
{
|
||||||
|
CheatEnabler.Logger.LogDebug($"Stripped VertCount: {DysonShell.s_vmap.Count}");
|
||||||
|
shell.Free();
|
||||||
|
layer.shellPool[shellId] = null;
|
||||||
|
int recycleIndex = layer.shellRecycleCursor;
|
||||||
|
layer.shellRecycleCursor = recycleIndex + 1;
|
||||||
|
layer.shellRecycle[recycleIndex] = shellId;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// CheatEnabler.Logger.LogDebug($"Shell {shellId} My VertCount: {DysonShell.s_vmap.Count}");
|
||||||
|
// shell.GenerateGeometry();
|
||||||
|
// CheatEnabler.Logger.LogDebug($"Shell {shellId} Orig VertCount: {DysonShell.s_vmap.Count}");
|
||||||
|
// CheatEnabler.Logger.LogDebug($"Shell {shellId} Calc VertCount: {CalculateTriangleVertCount2([shell.nodes[0].pos, shell.nodes[1].pos, shell.nodes[2].pos])}");
|
||||||
|
for (int j = 0; j < shell.nodes.Count; j++)
|
||||||
|
{
|
||||||
|
shell.nodes[j].shells.Add(shell);
|
||||||
|
}
|
||||||
|
shell.GenerateModelObjects();
|
||||||
|
return shellId;
|
||||||
|
}
|
||||||
|
public static void QuickRemoveDysonNode(this DysonSphereLayer layer, int nodeId)
|
||||||
|
{
|
||||||
|
var node = layer.nodePool[nodeId];
|
||||||
|
if (node == null || node.id != nodeId) return;
|
||||||
|
var dysonSphere = layer.dysonSphere;
|
||||||
|
dysonSphere.swarm.OnNodeRemove(layer.id, nodeId);
|
||||||
|
dysonSphere.RemoveAutoNode(node);
|
||||||
|
dysonSphere.RemoveNodeRocket(node);
|
||||||
|
dysonSphere.RemoveDysonNodeRData(node);
|
||||||
|
node.Free();
|
||||||
|
layer.nodePool[nodeId] = null;
|
||||||
|
int recycleIndex = layer.nodeRecycleCursor;
|
||||||
|
layer.nodeRecycleCursor = recycleIndex + 1;
|
||||||
|
layer.nodeRecycle[recycleIndex] = nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void QuickRemoveDysonFrame(this DysonSphereLayer layer, int frameId)
|
||||||
|
{
|
||||||
|
var frame = layer.framePool[frameId];
|
||||||
|
frame.nodeA.frames.Remove(frame);
|
||||||
|
frame.nodeB.frames.Remove(frame);
|
||||||
|
frame.Free();
|
||||||
|
layer.framePool[frameId] = null;
|
||||||
|
int recycleIndex = layer.frameRecycleCursor;
|
||||||
|
layer.frameRecycleCursor = recycleIndex + 1;
|
||||||
|
layer.frameRecycle[recycleIndex] = frameId;
|
||||||
|
}
|
||||||
|
public static int AlignUpToPowerOfTwo(int value)
|
||||||
|
{
|
||||||
|
value--;
|
||||||
|
value |= value >> 1;
|
||||||
|
value |= value >> 2;
|
||||||
|
value |= value >> 4;
|
||||||
|
value |= value >> 8;
|
||||||
|
value |= value >> 16;
|
||||||
|
return value + 1;
|
||||||
|
}
|
||||||
|
public class SupposedShell
|
||||||
|
{
|
||||||
|
public Vector3 posA;
|
||||||
|
public Vector3 posB;
|
||||||
|
public Vector3 posC;
|
||||||
|
|
||||||
|
public float area;
|
||||||
|
public int vertCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,576 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CheatEnabler.Functions;
|
||||||
|
using static CheatEnabler.Functions.DysonSphere.GeometryHelpers;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.GameConstants;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using CheatEnabler;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Functions.DysonSphere;
|
||||||
|
|
||||||
|
[ModFeature("IllegalShellFunctions")]
|
||||||
|
public static class IllegalShellFunctions
|
||||||
|
{
|
||||||
|
private static void EnsureDysonShellMaps()
|
||||||
|
{
|
||||||
|
DysonShell.s_vmap ??= new Dictionary<int, Vector3>(16384);
|
||||||
|
DysonShell.s_outvmap ??= new Dictionary<int, Vector3>(16384);
|
||||||
|
DysonShell.s_ivmap ??= new Dictionary<int, int>(16384);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ResetLayerPools(DysonSphereLayer layer)
|
||||||
|
{
|
||||||
|
layer.nodePool = new DysonNode[DysonSphereConstants.DefaultLayerPoolCapacity];
|
||||||
|
layer.nodeRecycle = new int[DysonSphereConstants.DefaultLayerPoolCapacity];
|
||||||
|
layer.nodeRecycleCursor = 0;
|
||||||
|
layer.nodeCapacity = DysonSphereConstants.DefaultLayerPoolCapacity;
|
||||||
|
layer.nodeCursor = 1;
|
||||||
|
layer.framePool = new DysonFrame[DysonSphereConstants.DefaultLayerPoolCapacity];
|
||||||
|
layer.frameRecycle = new int[DysonSphereConstants.DefaultLayerPoolCapacity];
|
||||||
|
layer.frameRecycleCursor = 0;
|
||||||
|
layer.frameCapacity = DysonSphereConstants.DefaultLayerPoolCapacity;
|
||||||
|
layer.frameCursor = 1;
|
||||||
|
layer.shellPool = new DysonShell[DysonSphereConstants.DefaultLayerPoolCapacity];
|
||||||
|
layer.shellRecycle = new int[DysonSphereConstants.DefaultLayerPoolCapacity];
|
||||||
|
layer.shellRecycleCursor = 0;
|
||||||
|
layer.shellCapacity = DysonSphereConstants.DefaultLayerPoolCapacity;
|
||||||
|
layer.shellCursor = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FinalizeDysonSphereChanges(global::DysonSphere sphere, DysonSphereLayer layer, bool notify = false, bool resetRenderMasks = false)
|
||||||
|
{
|
||||||
|
if (sphere == null) return;
|
||||||
|
sphere.CheckAutoNodes();
|
||||||
|
if (sphere.autoNodeCount <= 0) sphere.PickAutoNode();
|
||||||
|
sphere.modelRenderer.RebuildModels();
|
||||||
|
if (notify) GameMain.gameScenario?.NotifyOnPlanDysonShell();
|
||||||
|
if (resetRenderMasks)
|
||||||
|
{
|
||||||
|
sphere.inEditorRenderMaskS = 0;
|
||||||
|
sphere.inEditorRenderMaskL = 0;
|
||||||
|
sphere.inGameRenderMaskS = 0;
|
||||||
|
sphere.inGameRenderMaskL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DuplicateShellsWithHighestProduction()
|
||||||
|
{
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere();
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, star) = resolved.Value;
|
||||||
|
EnsureDysonShellMaps();
|
||||||
|
DysonSphereLayer layer = null;
|
||||||
|
var nodePos = new List<Vector3>();
|
||||||
|
var isEuler = new List<bool>();
|
||||||
|
DysonShell shell = null;
|
||||||
|
for (var i = 1; i < dysonSphere.layersIdBased.Length; i++)
|
||||||
|
{
|
||||||
|
layer = dysonSphere.layersIdBased[i];
|
||||||
|
if (layer == null || layer.id != i) continue;
|
||||||
|
for (var j = 1; j < layer.shellCursor; j++)
|
||||||
|
{
|
||||||
|
shell = layer.shellPool[j];
|
||||||
|
if (shell == null) continue;
|
||||||
|
if (shell.id != j)
|
||||||
|
{
|
||||||
|
shell = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nodePos.AddRange(shell.nodes.Select(node => node.pos));
|
||||||
|
isEuler.AddRange(shell.frames.Select(frame => frame.euler));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nodePos.Count > 0) break;
|
||||||
|
}
|
||||||
|
if (nodePos.Count == 0)
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.CheatEnabler.Translate(), string.Format(Localization.ThereIsNoDysonSphereShellOn0.Translate(), star.displayName), Localization.OK.Translate(), UIMessageBox.ERROR, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var currentShellCount = layer.shellCount;
|
||||||
|
var keepCount = DysonSphereFunctions.ShellsCountForFunctions.Value;
|
||||||
|
if (currentShellCount >= keepCount) return;
|
||||||
|
CheatEnabler.Logger.LogDebug($"NodePositions: {nodePos[0]}, {nodePos[1]}, {nodePos[2]}");
|
||||||
|
var nodeCount = nodePos.Count;
|
||||||
|
DysonNode[] nodes = [.. shell.nodes];
|
||||||
|
DysonFrame[] frames = [.. shell.frames];
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
cpMax[i] = (shell.vertsqOffset[i + 1] - shell.vertsqOffset[i]) * shell.cpPerVertex;
|
||||||
|
}
|
||||||
|
long[] totalCpMax = [.. nodes.Select(node => node.totalCpMax)];
|
||||||
|
var dirtyFrames = new HashSet<int>();
|
||||||
|
for (var i = currentShellCount; i < keepCount; i++)
|
||||||
|
{
|
||||||
|
dirtyFrames.Clear();
|
||||||
|
for (var j = 0; j < nodeCount; j++)
|
||||||
|
{
|
||||||
|
totalCpMax[j] += cpMax[j];
|
||||||
|
if (totalCpMax[j] > DysonSphereConstants.TotalCpMaxCeiling)
|
||||||
|
{
|
||||||
|
totalCpMax[j] = cpMax[j];
|
||||||
|
dirtyFrames.Add(j > 0 ? j - 1 : nodeCount - 1);
|
||||||
|
dirtyFrames.Add(j);
|
||||||
|
nodes[j] = layer.QuickAddDysonNode(0, nodePos[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var frameId in dirtyFrames)
|
||||||
|
{
|
||||||
|
frames[frameId] = layer.QuickAddDysonFrame(0, nodes[frameId], nodes[(frameId + 1) % nodeCount], isEuler[frameId]);
|
||||||
|
}
|
||||||
|
layer.QuickAddDysonShell(0, nodes, frames, false);
|
||||||
|
}
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
node.RecalcSpReq();
|
||||||
|
node.RecalcCpReq();
|
||||||
|
}
|
||||||
|
FinalizeDysonSphereChanges(dysonSphere, layer, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void KeepMaxProductionShells()
|
||||||
|
{
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere();
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, star) = resolved.Value;
|
||||||
|
int retainCount = DysonSphereFunctions.ShellsCountForFunctions.Value;
|
||||||
|
for (var i = 1; i < dysonSphere.layersIdBased.Length; i++)
|
||||||
|
{
|
||||||
|
var layer = dysonSphere.layersIdBased[i];
|
||||||
|
if (layer == null || layer.id != i) continue;
|
||||||
|
var shells = layer.shellPool.Where(shell => shell != null).OrderByDescending(shell => shell.vertexCount).ToArray();
|
||||||
|
if (shells.Length < 1) continue;
|
||||||
|
for (var j = retainCount; j < shells.Length; j++)
|
||||||
|
{
|
||||||
|
var shell = shells[j];
|
||||||
|
var id = shell.id;
|
||||||
|
layer.shellPool[id] = null;
|
||||||
|
for (var k = 0; k < shell.nodes.Count; k++)
|
||||||
|
{
|
||||||
|
shell.nodes[k].shells.Remove(shell);
|
||||||
|
}
|
||||||
|
shell.Free();
|
||||||
|
shells[j] = null;
|
||||||
|
}
|
||||||
|
var poolCapacity = GeometryHelpers.AlignUpToPowerOfTwo(retainCount + 1);
|
||||||
|
if (poolCapacity < DysonSphereConstants.DefaultLayerPoolCapacity) poolCapacity = DysonSphereConstants.DefaultLayerPoolCapacity;
|
||||||
|
layer.shellPool = new DysonShell[poolCapacity];
|
||||||
|
layer.shellRecycle = new int[poolCapacity];
|
||||||
|
layer.shellRecycleCursor = 0;
|
||||||
|
layer.shellCapacity = poolCapacity;
|
||||||
|
layer.shellCursor = retainCount + 1;
|
||||||
|
HashSet<int> retainNodes = [];
|
||||||
|
HashSet<(int, int)> retainFrames = [];
|
||||||
|
for (var j = 0; j < retainCount; j++)
|
||||||
|
{
|
||||||
|
var shell = shells[j];
|
||||||
|
retainNodes.UnionWith(shell.nodes.Select(node => node.id));
|
||||||
|
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;
|
||||||
|
var idB = shell.nodes[(k + 1) % shell.nodes.Count].id;
|
||||||
|
retainFrames.Add((idA, idB));
|
||||||
|
retainFrames.Add((idB, idA));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var nodes = layer.nodePool.Where(node => node != null && retainNodes.Contains(node.id)).ToArray();
|
||||||
|
var frames = layer.framePool.Where(frame => frame != null && retainFrames.Contains((frame.nodeA.id, frame.nodeB.id))).ToArray();
|
||||||
|
poolCapacity = GeometryHelpers.AlignUpToPowerOfTwo(frames.Length + 1);
|
||||||
|
if (poolCapacity < DysonSphereConstants.DefaultLayerPoolCapacity) poolCapacity = DysonSphereConstants.DefaultLayerPoolCapacity;
|
||||||
|
layer.framePool = new DysonFrame[poolCapacity];
|
||||||
|
layer.frameRecycle = new int[poolCapacity];
|
||||||
|
layer.frameRecycleCursor = 0;
|
||||||
|
layer.frameCapacity = poolCapacity;
|
||||||
|
layer.frameCursor = frames.Length + 1;
|
||||||
|
for (var j = 0; j < frames.Length; j++)
|
||||||
|
{
|
||||||
|
int id = j + 1;
|
||||||
|
layer.framePool[id] = frames[j];
|
||||||
|
frames[j].id = id;
|
||||||
|
}
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
if (node != null && node.id > 0)
|
||||||
|
{
|
||||||
|
dysonSphere.RemoveDysonNodeRData(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poolCapacity = GeometryHelpers.AlignUpToPowerOfTwo(nodes.Length + 1);
|
||||||
|
if (poolCapacity < DysonSphereConstants.DefaultLayerPoolCapacity) poolCapacity = DysonSphereConstants.DefaultLayerPoolCapacity;
|
||||||
|
layer.nodePool = new DysonNode[poolCapacity];
|
||||||
|
layer.nodeRecycle = new int[poolCapacity];
|
||||||
|
layer.nodeRecycleCursor = 0;
|
||||||
|
layer.nodeCapacity = poolCapacity;
|
||||||
|
layer.nodeCursor = nodes.Length + 1;
|
||||||
|
for (var j = 0; j < nodes.Length; j++)
|
||||||
|
{
|
||||||
|
int id = j + 1;
|
||||||
|
layer.nodePool[id] = nodes[j];
|
||||||
|
nodes[j].id = id;
|
||||||
|
}
|
||||||
|
for (var j = 1; j < layer.shellCursor; j++)
|
||||||
|
{
|
||||||
|
var shell = layer.shellPool[j];
|
||||||
|
if (shell == null || shell.id != j) continue;
|
||||||
|
shell.nodeIndexMap.Clear();
|
||||||
|
for (var k = 0; k < shell.nodes.Count; k++)
|
||||||
|
{
|
||||||
|
shell.nodeIndexMap[shell.nodes[k].id] = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var j = 1; j < layer.nodeCursor; j++)
|
||||||
|
{
|
||||||
|
var node = layer.nodePool[j];
|
||||||
|
if (node == null || node.id != j) continue;
|
||||||
|
dysonSphere.AddDysonNodeRData(node, true);
|
||||||
|
node.RecalcSpReq();
|
||||||
|
node.RecalcCpReq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FinalizeDysonSphereChanges(dysonSphere, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateIllegalDysonShellQuickly(int triangleCount)
|
||||||
|
{
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere(requireLayer: false);
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, _) = resolved.Value;
|
||||||
|
|
||||||
|
EnsureDysonShellMaps();
|
||||||
|
|
||||||
|
for (int i = 1; i <= 10; i++)
|
||||||
|
{
|
||||||
|
var layer = dysonSphere.layersIdBased[i];
|
||||||
|
if (layer != null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var radius = dysonSphere.maxOrbitRadius;
|
||||||
|
for (; radius > DysonSphereConstants.MinOrbitRadiusSearch; radius -= DysonSphereConstants.OrbitRadiusSearchStep)
|
||||||
|
{
|
||||||
|
if (dysonSphere.CheckLayerRadius(radius) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrecalculatedTriangle triangle;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
triangle = GeometryHelpers.PrecalculatedTriangles.First(t => t.MaxOrbitRadius > radius);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.CheatEnabler.Translate(), string.Format(Localization.NoPrecalculatedShellFoundForRadius0.Translate(), radius), Localization.OK.Translate(), UIMessageBox.ERROR, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layer = dysonSphere.AddLayerOnId(i, radius, Quaternion.Euler(0f, 0f, 0f), Mathf.Sqrt(dysonSphere.gravity / radius) / radius * DysonSphereConstants.RadiansToDegrees);
|
||||||
|
if (layer == null) return;
|
||||||
|
Vector3[] nodePos = [triangle.PosA.normalized * radius, triangle.PosB.normalized * radius, triangle.PosC.normalized * radius];
|
||||||
|
DysonNode[] nodes = [layer.QuickAddDysonNode(0, nodePos[0]), layer.QuickAddDysonNode(0, nodePos[1]), layer.QuickAddDysonNode(0, nodePos[2])];
|
||||||
|
DysonFrame[] frames = [layer.QuickAddDysonFrame(0, nodes[0], nodes[1], false), layer.QuickAddDysonFrame(0, nodes[1], nodes[2], false), layer.QuickAddDysonFrame(0, nodes[2], nodes[0], false)];
|
||||||
|
var shellId = layer.QuickAddDysonShell(0, nodes, frames, false);
|
||||||
|
if (shellId == 0) return;
|
||||||
|
var shell = layer.shellPool[shellId];
|
||||||
|
long[] cpMax = [.. nodes.Select(node => node.totalCpMax)];
|
||||||
|
long[] totalCpMax = [.. cpMax];
|
||||||
|
var dirtyFrames = new HashSet<int>();
|
||||||
|
for (var j = 1; j < triangleCount; j++)
|
||||||
|
{
|
||||||
|
dirtyFrames.Clear();
|
||||||
|
for (var k = 0; k < 3; k++)
|
||||||
|
{
|
||||||
|
totalCpMax[k] += cpMax[k];
|
||||||
|
if (totalCpMax[k] > DysonSphereConstants.TotalCpMaxCeiling)
|
||||||
|
{
|
||||||
|
totalCpMax[k] = cpMax[k];
|
||||||
|
dirtyFrames.Add(k > 0 ? k - 1 : 2);
|
||||||
|
dirtyFrames.Add(k);
|
||||||
|
nodes[k] = layer.QuickAddDysonNode(0, nodePos[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var frameId in dirtyFrames)
|
||||||
|
{
|
||||||
|
frames[frameId] = layer.QuickAddDysonFrame(0, nodes[frameId], nodes[(frameId + 1) % 3], false);
|
||||||
|
}
|
||||||
|
layer.QuickAddDysonShell(0, nodes, frames, false);
|
||||||
|
}
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
node.RecalcSpReq();
|
||||||
|
node.RecalcCpReq();
|
||||||
|
}
|
||||||
|
FinalizeDysonSphereChanges(dysonSphere, layer, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CreateIllegalDysonShellWithMaxOutputForLayer(DysonSphereLayer layer)
|
||||||
|
{
|
||||||
|
EnsureDysonShellMaps();
|
||||||
|
var shellsChanged = false;
|
||||||
|
var mutex = new object();
|
||||||
|
var supposedShells = new List<SupposedShell>(DysonSphereConstants.MaxShellSearchCombinations);
|
||||||
|
Vector3[] nodePos = new Vector3[DysonSphereConstants.MaxShellSearchNodeCount];
|
||||||
|
for (var i = 0; i < DysonSphereConstants.MaxShellSearchNodeCount; i++)
|
||||||
|
{
|
||||||
|
nodePos[i] = new Vector3((float)Math.Sin(Math.PI * 2 * i / DysonSphereConstants.MaxShellSearchNodeCount), 0, (float)Math.Cos(Math.PI * 2 * i / DysonSphereConstants.MaxShellSearchNodeCount)) * layer.orbitRadius;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < DysonSphereConstants.MaxShellSearchNodeCount - 2; i++)
|
||||||
|
{
|
||||||
|
for (var j = i + 1; j < DysonSphereConstants.MaxShellSearchNodeCount - 1; j++)
|
||||||
|
{
|
||||||
|
for (var k = j + 1; k < DysonSphereConstants.MaxShellSearchNodeCount; k++)
|
||||||
|
{
|
||||||
|
var area = Vector3.Cross(nodePos[j] - nodePos[i], nodePos[k] - nodePos[i]).sqrMagnitude;
|
||||||
|
supposedShells.Add(new SupposedShell { posA = nodePos[i], posB = nodePos[j], posC = nodePos[k], area = area });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
supposedShells.Sort((a, b) => b.area.CompareTo(a.area));
|
||||||
|
CheatEnabler.Logger.LogDebug($"Finished Area Sort");
|
||||||
|
var maxVertCount = -1;
|
||||||
|
var maxJ = -1;
|
||||||
|
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1 };
|
||||||
|
|
||||||
|
var gridScale = (int)(Math.Pow(layer.orbitRadius / DysonSphereConstants.GridScaleBaseRadius, 0.75) + 0.5);
|
||||||
|
gridScale = (gridScale < 1) ? 1 : gridScale;
|
||||||
|
var cpPerVertex = gridScale * gridScale * DysonSphereConstants.CpPerVertexFactor;
|
||||||
|
var barrier = DysonSphereConstants.TotalCpMaxCeiling / cpPerVertex;
|
||||||
|
if (barrier > DysonSphereConstants.MaxShellVertices) barrier = DysonSphereConstants.MaxShellVertices;
|
||||||
|
var truncValue = barrier / 1000 * 1000;
|
||||||
|
CheatEnabler.Logger.LogDebug($"cpPerVertex: {cpPerVertex}, Barrier: {barrier}, TruncValue: {truncValue}");
|
||||||
|
|
||||||
|
Parallel.For(0, supposedShells.Count, options, (j, loopState) =>
|
||||||
|
{
|
||||||
|
var sshell = supposedShells[j];
|
||||||
|
var vertCount = GeometryHelpers.CalculateTriangleVertCount([sshell.posA, sshell.posB, sshell.posC]);
|
||||||
|
sshell.vertCount = vertCount <= barrier ? vertCount : -1;
|
||||||
|
if (vertCount <= barrier)
|
||||||
|
{
|
||||||
|
lock (mutex)
|
||||||
|
{
|
||||||
|
if (loopState.ShouldExitCurrentIteration) return;
|
||||||
|
if (vertCount > maxVertCount)
|
||||||
|
{
|
||||||
|
maxVertCount = vertCount;
|
||||||
|
maxJ = j;
|
||||||
|
if (maxVertCount >= truncValue)
|
||||||
|
{
|
||||||
|
CheatEnabler.Logger.LogDebug($"!!STOP!! Triangle {j}[{sshell.posA:F2} {sshell.posB:F2} {sshell.posC:F2}] has {vertCount} vertices");
|
||||||
|
loopState.Stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CheatEnabler.Logger.LogDebug($"Triangle {j}[{sshell.posA:F2} {sshell.posB:F2} {sshell.posC:F2}] has {vertCount} vertices");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (maxJ >= 0)
|
||||||
|
{
|
||||||
|
ResetLayerPools(layer);
|
||||||
|
foreach (var sshell in supposedShells.OrderByDescending(shell => shell.vertCount))
|
||||||
|
{
|
||||||
|
if (sshell.vertCount <= 0) break;
|
||||||
|
|
||||||
|
DysonNode[] newNodes = [layer.QuickAddDysonNode(0, sshell.posA), layer.QuickAddDysonNode(0, sshell.posB), layer.QuickAddDysonNode(0, sshell.posC)];
|
||||||
|
DysonFrame[] newFrames = [layer.QuickAddDysonFrame(0, newNodes[0], newNodes[1], false), layer.QuickAddDysonFrame(0, newNodes[1], newNodes[2], false), layer.QuickAddDysonFrame(0, newNodes[2], newNodes[0], false)];
|
||||||
|
if (layer.QuickAddDysonShell(0, newNodes, newFrames, false) == 0)
|
||||||
|
{
|
||||||
|
foreach (var frame in newFrames)
|
||||||
|
{
|
||||||
|
layer.QuickRemoveDysonFrame(frame.id);
|
||||||
|
}
|
||||||
|
foreach (var node in newNodes)
|
||||||
|
{
|
||||||
|
layer.QuickRemoveDysonNode(node.id);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (var node in newNodes)
|
||||||
|
{
|
||||||
|
node.RecalcSpReq();
|
||||||
|
node.RecalcCpReq();
|
||||||
|
}
|
||||||
|
shellsChanged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shellsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateIllegalDysonShellWithMaxOutput()
|
||||||
|
{
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere(requireLayer: false);
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, star) = resolved.Value;
|
||||||
|
UXAssist.Functions.DysonSphereFunctions.InitCurrentDysonLayer(star, 0);
|
||||||
|
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 * DysonSphereConstants.RadiansToDegrees);
|
||||||
|
if (layer == null) return;
|
||||||
|
|
||||||
|
var shellsChanged = CreateIllegalDysonShellWithMaxOutputForLayer(layer);
|
||||||
|
|
||||||
|
FinalizeDysonSphereChanges(dysonSphere, layer, shellsChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateIllegalDysonShellWithMaxOutputForAllLayers()
|
||||||
|
{
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere(requireLayer: false);
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, _) = resolved.Value;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
FinalizeDysonSphereChanges(dysonSphere, dysonSphere.layersSorted.FirstOrDefault(l => l != null), shellsChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateIllegalDysonShellsSpecially()
|
||||||
|
{
|
||||||
|
var lastGridScale = 0;
|
||||||
|
var radiusList = new List<int>();
|
||||||
|
for (var r = DysonSphereConstants.MinOrbitRadiusSearch; r <= DysonSphereConstants.MaxOrbitRadius; r++)
|
||||||
|
{
|
||||||
|
var gridScale = (int)(Math.Pow(r / DysonSphereConstants.GridScaleBaseRadius, 0.75) + 0.5);
|
||||||
|
gridScale = (gridScale < 1) ? 1 : gridScale;
|
||||||
|
if (gridScale == lastGridScale) continue;
|
||||||
|
lastGridScale = gridScale;
|
||||||
|
radiusList.Add(r);
|
||||||
|
CheatEnabler.Logger.LogDebug($"Grid Scale: {gridScale} from {r}");
|
||||||
|
}
|
||||||
|
radiusList.Add(DysonSphereConstants.MaxOrbitRadius);
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere(requireLayer: false);
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, star) = resolved.Value;
|
||||||
|
UXAssist.Functions.DysonSphereFunctions.InitCurrentDysonLayer(star, 0);
|
||||||
|
|
||||||
|
EnsureDysonShellMaps();
|
||||||
|
var shellsChanged = false;
|
||||||
|
var mutex = new object();
|
||||||
|
|
||||||
|
for (var idx = 1; idx <= 2; idx++)
|
||||||
|
{
|
||||||
|
Dictionary<(int, int), int> availableFrames = [];
|
||||||
|
HashSet<int> unusedFrameIds = [];
|
||||||
|
var layer = dysonSphere.layersIdBased[idx];
|
||||||
|
if (layer != null)
|
||||||
|
{
|
||||||
|
dysonSphere.RemoveLayer(idx);
|
||||||
|
}
|
||||||
|
var orbitRadius = (radiusList[idx] - 1) / 10 * 10f;
|
||||||
|
layer = dysonSphere.AddLayerOnId(idx, orbitRadius, Quaternion.Euler(0f, 0f, 0f), Mathf.Sqrt(dysonSphere.gravity / orbitRadius) / orbitRadius * DysonSphereConstants.RadiansToDegrees);
|
||||||
|
if (layer == null) return;
|
||||||
|
|
||||||
|
var supposedShells = new List<SupposedShell>(DysonSphereConstants.MaxShellSearchCombinations);
|
||||||
|
Vector3[] nodePos = new Vector3[DysonSphereConstants.MaxShellSearchNodeCount];
|
||||||
|
for (var i = 0; i < DysonSphereConstants.MaxShellSearchNodeCount; i++)
|
||||||
|
{
|
||||||
|
nodePos[i] = new Vector3((float)Math.Sin(Math.PI * 2 * i / DysonSphereConstants.MaxShellSearchNodeCount), 0, (float)Math.Cos(Math.PI * 2 * i / DysonSphereConstants.MaxShellSearchNodeCount));
|
||||||
|
}
|
||||||
|
for (var i = 0; i < DysonSphereConstants.MaxShellSearchNodeCount - 2; i++)
|
||||||
|
{
|
||||||
|
for (var j = i + 1; j < DysonSphereConstants.MaxShellSearchNodeCount - 1; j++)
|
||||||
|
{
|
||||||
|
for (var k = j + 1; k < DysonSphereConstants.MaxShellSearchNodeCount; k++)
|
||||||
|
{
|
||||||
|
var area = Vector3.Cross(nodePos[j] - nodePos[i], nodePos[k] - nodePos[i]).sqrMagnitude;
|
||||||
|
supposedShells.Add(new SupposedShell { posA = nodePos[i], posB = nodePos[j], posC = nodePos[k], area = area });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
supposedShells.Sort((a, b) => b.area.CompareTo(a.area));
|
||||||
|
|
||||||
|
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1 };
|
||||||
|
|
||||||
|
var gridScale = (int)(Math.Pow(orbitRadius / DysonSphereConstants.GridScaleBaseRadius, 0.75) + 0.5);
|
||||||
|
gridScale = (gridScale < 1) ? 1 : gridScale;
|
||||||
|
var cpPerVertex = gridScale * gridScale * DysonSphereConstants.CpPerVertexFactor;
|
||||||
|
var barrier = DysonSphereConstants.TotalCpMaxCeiling / cpPerVertex;
|
||||||
|
if (barrier > 30000) barrier = 30000;
|
||||||
|
|
||||||
|
Parallel.For(0, supposedShells.Count, options, (j, _) =>
|
||||||
|
{
|
||||||
|
var sshell = supposedShells[j];
|
||||||
|
var vertCount = GeometryHelpers.CalculateTriangleVertCount([sshell.posA * orbitRadius, sshell.posB * orbitRadius, sshell.posC * orbitRadius]);
|
||||||
|
if (vertCount > barrier)
|
||||||
|
{
|
||||||
|
sshell.vertCount = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sshell.vertCount = vertCount;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
supposedShells.Sort((a, b) => b.vertCount.CompareTo(a.vertCount));
|
||||||
|
for (var j = 0; j < supposedShells.Count && supposedShells[j].vertCount > 0; j++)
|
||||||
|
{
|
||||||
|
var sshell = supposedShells[j];
|
||||||
|
CheatEnabler.Logger.LogDebug($"Checking Triangle {j}[{orbitRadius}] with {sshell.vertCount} vertices");
|
||||||
|
var result = Parallel.For((radiusList[idx - 1] + 9) / 10, (radiusList[idx] + 9) / 10, options, (k, loopState) =>
|
||||||
|
{
|
||||||
|
var orbitRadius = k * 10f;
|
||||||
|
var gridScale = (int)(Math.Pow(orbitRadius / DysonSphereConstants.GridScaleBaseRadius, 0.75) + 0.5);
|
||||||
|
gridScale = (gridScale < 1) ? 1 : gridScale;
|
||||||
|
var cpPerVertex = gridScale * gridScale * DysonSphereConstants.CpPerVertexFactor;
|
||||||
|
var barrier = DysonSphereConstants.TotalCpMaxCeiling / cpPerVertex;
|
||||||
|
if (barrier > 31000) barrier = 31000;
|
||||||
|
if (loopState.ShouldExitCurrentIteration) return;
|
||||||
|
var vertCount = GeometryHelpers.CalculateTriangleVertCount([sshell.posA * orbitRadius, sshell.posB * orbitRadius, sshell.posC * orbitRadius]);
|
||||||
|
lock (mutex)
|
||||||
|
{
|
||||||
|
if (loopState.ShouldExitCurrentIteration) return;
|
||||||
|
if (vertCount > barrier)
|
||||||
|
{
|
||||||
|
CheatEnabler.Logger.LogDebug($"EXCEEDED: Triangle {j}[{orbitRadius}] has {vertCount} vertices");
|
||||||
|
loopState.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!result.IsCompleted)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ResetLayerPools(layer);
|
||||||
|
DysonNode[] newNodes = [layer.QuickAddDysonNode(0, sshell.posA * orbitRadius), layer.QuickAddDysonNode(0, sshell.posB * orbitRadius), layer.QuickAddDysonNode(0, sshell.posC * orbitRadius)];
|
||||||
|
DysonFrame[] newFrames = [layer.QuickAddDysonFrame(0, newNodes[0], newNodes[1], false), layer.QuickAddDysonFrame(0, newNodes[1], newNodes[2], false), layer.QuickAddDysonFrame(0, newNodes[2], newNodes[0], false)];
|
||||||
|
layer.QuickAddDysonShell(0, newNodes, newFrames, false);
|
||||||
|
foreach (var node in newNodes)
|
||||||
|
{
|
||||||
|
node.RecalcSpReq();
|
||||||
|
node.RecalcCpReq();
|
||||||
|
}
|
||||||
|
shellsChanged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FinalizeDysonSphereChanges(dysonSphere, dysonSphere.layersIdBased[2], shellsChanged, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using UXAssist.Common.Utils;
|
||||||
|
using CheatEnabler;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Functions.DysonSphere;
|
||||||
|
|
||||||
|
[ModFeature("ShellCompletionFunctions")]
|
||||||
|
public static class ShellCompletionFunctions
|
||||||
|
{
|
||||||
|
public static void CompleteShellsInstantly()
|
||||||
|
{
|
||||||
|
var resolved = DysonSphereResolver.ResolveEditorOrLocalSphere();
|
||||||
|
if (resolved == null) return;
|
||||||
|
var (dysonSphere, star) = resolved.Value;
|
||||||
|
|
||||||
|
UIMessageBox.Show(Localization.CheatEnabler.Translate(), string.Format(Localization.ThisWillCompleteAllDysonSphereShellsOn0InstantlyAreYouSure.Translate(), star.displayName), Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.QUESTION, null, () =>
|
||||||
|
{
|
||||||
|
var rocketCount = 0L;
|
||||||
|
var solarSailCount = 0L;
|
||||||
|
foreach (var dysonSphereLayer in dysonSphere.layersIdBased)
|
||||||
|
{
|
||||||
|
if (dysonSphereLayer == null) continue;
|
||||||
|
long totalNodeSp = 0;
|
||||||
|
long totalFrameSp = 0;
|
||||||
|
long totalCp = 0;
|
||||||
|
for (var i = dysonSphereLayer.frameCursor - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var dysonFrame = dysonSphereLayer.framePool[i];
|
||||||
|
if (dysonFrame == null || dysonFrame.id != i) continue;
|
||||||
|
totalFrameSp += dysonFrame.spMax;
|
||||||
|
var spMax = dysonFrame.spMax / 2;
|
||||||
|
if (dysonFrame.spA < spMax)
|
||||||
|
{
|
||||||
|
rocketCount += spMax - dysonFrame.spA;
|
||||||
|
dysonFrame.spA = spMax;
|
||||||
|
dysonSphere.UpdateProgress(dysonFrame);
|
||||||
|
}
|
||||||
|
if (dysonFrame.spB < spMax)
|
||||||
|
{
|
||||||
|
rocketCount += spMax - dysonFrame.spB;
|
||||||
|
dysonFrame.spB = spMax;
|
||||||
|
dysonSphere.UpdateProgress(dysonFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = dysonSphereLayer.nodeCursor - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var dysonNode = dysonSphereLayer.nodePool[i];
|
||||||
|
if (dysonNode == null || dysonNode.id != i) continue;
|
||||||
|
dysonNode.spOrdered = 0;
|
||||||
|
dysonNode._spReq = 0;
|
||||||
|
totalNodeSp += dysonNode.spMax;
|
||||||
|
var diff = dysonNode.spMax - dysonNode.sp;
|
||||||
|
if (diff > 0)
|
||||||
|
{
|
||||||
|
rocketCount += diff;
|
||||||
|
dysonNode.sp = dysonNode.spMax;
|
||||||
|
dysonSphere.UpdateProgress(dysonNode);
|
||||||
|
}
|
||||||
|
dysonNode._cpReq = 0;
|
||||||
|
dysonNode.cpOrdered = 0;
|
||||||
|
foreach (var shell in dysonNode.shells)
|
||||||
|
{
|
||||||
|
var nodeIndex = shell.nodeIndexMap[dysonNode.id];
|
||||||
|
var cpMax = (shell.vertsqOffset[nodeIndex + 1] - shell.vertsqOffset[nodeIndex]) * shell.cpPerVertex;
|
||||||
|
totalCp += cpMax;
|
||||||
|
diff = cpMax - shell.nodecps[nodeIndex];
|
||||||
|
shell.nodecps[nodeIndex] = cpMax;
|
||||||
|
shell.nodecps[shell.nodecps.Length - 1] += diff;
|
||||||
|
solarSailCount += diff;
|
||||||
|
if (DysonSphereReflection.HasTotalCP)
|
||||||
|
{
|
||||||
|
shell.SetMaterialDynamicVars();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DysonSphereReflection.SetTotalNodeSP(dysonSphereLayer, totalNodeSp);
|
||||||
|
DysonSphereReflection.SetTotalFrameSP(dysonSphereLayer, totalFrameSp);
|
||||||
|
DysonSphereReflection.SetTotalCP(dysonSphereLayer, totalCp);
|
||||||
|
}
|
||||||
|
dysonSphere.CheckAutoNodes();
|
||||||
|
|
||||||
|
var productRegister = dysonSphere.productRegister;
|
||||||
|
if (productRegister != null)
|
||||||
|
{
|
||||||
|
lock (productRegister)
|
||||||
|
{
|
||||||
|
var count = rocketCount;
|
||||||
|
while (count > 0x40000000L)
|
||||||
|
{
|
||||||
|
productRegister[ProductionStatistics.DYSON_STRUCTURE_ID] += 0x40000000;
|
||||||
|
count -= 0x40000000;
|
||||||
|
}
|
||||||
|
if (count > 0L) productRegister[ProductionStatistics.DYSON_STRUCTURE_ID] += (int)count;
|
||||||
|
count = solarSailCount;
|
||||||
|
while (count > 0x40000000L)
|
||||||
|
{
|
||||||
|
productRegister[ProductionStatistics.SOLAR_SAIL_ID] += 0x40000000;
|
||||||
|
productRegister[ProductionStatistics.DYSON_CELL_ID] += 0x40000000;
|
||||||
|
count -= 0x40000000;
|
||||||
|
}
|
||||||
|
if (count > 0L)
|
||||||
|
{
|
||||||
|
productRegister[ProductionStatistics.SOLAR_SAIL_ID] += (int)count;
|
||||||
|
productRegister[ProductionStatistics.DYSON_CELL_ID] += (int)count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var consumeRegister = dysonSphere.consumeRegister;
|
||||||
|
if (consumeRegister != null)
|
||||||
|
{
|
||||||
|
lock (consumeRegister)
|
||||||
|
{
|
||||||
|
var count = solarSailCount;
|
||||||
|
while (count > 0x40000000L)
|
||||||
|
{
|
||||||
|
consumeRegister[ProductionStatistics.SOLAR_SAIL_ID] += 0x40000000;
|
||||||
|
count -= 0x40000000;
|
||||||
|
}
|
||||||
|
if (count > 0L) consumeRegister[ProductionStatistics.SOLAR_SAIL_ID] += (int)count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dysonSphere.needRecalculatePower = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,152 +1,29 @@
|
|||||||
using HarmonyLib;
|
using BepInEx.Configuration;
|
||||||
|
using CheatEnabler.Functions.DysonSphere;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler.Functions;
|
namespace CheatEnabler.Functions;
|
||||||
|
|
||||||
|
[ModFeature("CheatDysonSphere", Order = 20)]
|
||||||
public static class DysonSphereFunctions
|
public static class DysonSphereFunctions
|
||||||
{
|
{
|
||||||
|
public const int MinShellsCountForFunctions = 1;
|
||||||
|
public const int MaxShellsCountForFunctions = 99_999;
|
||||||
|
|
||||||
|
public static ConfigEntry<bool> IllegalDysonShellFunctionsEnabled;
|
||||||
|
public static ConfigEntry<int> ShellsCountForFunctions;
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
I18N.Add("You are not in any system.", "You are not in any system.", "你不在任何星系中");
|
}
|
||||||
I18N.Add("There is no Dyson Sphere shell on \"{0}\".", "There is no Dyson Sphere shell 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}”上的所有戴森壳。你确定吗?");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CompleteShellsInstantly()
|
public static void CompleteShellsInstantly() => ShellCompletionFunctions.CompleteShellsInstantly();
|
||||||
{
|
public static void RemoveAllFrames() => FrameRemovalFunctions.RemoveAllFrames();
|
||||||
StarData star = null;
|
public static void DuplicateShellsWithHighestProduction() => IllegalShellFunctions.DuplicateShellsWithHighestProduction();
|
||||||
var dysonEditor = UIRoot.instance?.uiGame?.dysonEditor;
|
public static void KeepMaxProductionShells() => IllegalShellFunctions.KeepMaxProductionShells();
|
||||||
if (dysonEditor != null && dysonEditor.gameObject.activeSelf)
|
public static void CreateIllegalDysonShellQuickly(int triangleCount) => IllegalShellFunctions.CreateIllegalDysonShellQuickly(triangleCount);
|
||||||
{
|
public static void CreateIllegalDysonShellWithMaxOutput() => IllegalShellFunctions.CreateIllegalDysonShellWithMaxOutput();
|
||||||
star = dysonEditor.selection.viewStar;
|
public static void CreateIllegalDysonShellWithMaxOutputForAllLayers() => IllegalShellFunctions.CreateIllegalDysonShellWithMaxOutputForAllLayers();
|
||||||
}
|
public static void CreateIllegalDysonShellsSpecially() => IllegalShellFunctions.CreateIllegalDysonShellsSpecially();
|
||||||
if (star == null)
|
|
||||||
{
|
|
||||||
star = GameMain.data?.localStar;
|
|
||||||
if (star == null)
|
|
||||||
{
|
|
||||||
UIMessageBox.Show("CheatEnabler".Translate(), "You are not in any system.".Translate(), "确定".Translate(), 3, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var dysonSphere = GameMain.data?.dysonSpheres[star.index];
|
|
||||||
if (dysonSphere == null || dysonSphere.layerCount == 0)
|
|
||||||
{
|
|
||||||
UIMessageBox.Show("CheatEnabler".Translate(), string.Format("There is no Dyson Sphere shell on \"{0}\".".Translate(), star.displayName), "确定".Translate(), 3, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UIMessageBox.Show("CheatEnabler".Translate(), string.Format("This will complete all Dyson Sphere shells on \"{0}\" instantly. Are you sure?".Translate(), star.displayName), "取消".Translate(), "确定".Translate(), 2, null, () =>
|
|
||||||
{
|
|
||||||
var totalNodeSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalNodeSP");
|
|
||||||
var totalFrameSpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalFrameSP");
|
|
||||||
var totalCpInfo = AccessTools.Field(typeof(DysonSphereLayer), "totalCP");
|
|
||||||
|
|
||||||
var rocketCount = 0L;
|
|
||||||
var solarSailCount = 0L;
|
|
||||||
foreach (var dysonSphereLayer in dysonSphere.layersIdBased)
|
|
||||||
{
|
|
||||||
if (dysonSphereLayer == null) continue;
|
|
||||||
long totalNodeSp = 0;
|
|
||||||
long totalFrameSp = 0;
|
|
||||||
long totalCp = 0;
|
|
||||||
for (var i = dysonSphereLayer.frameCursor - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
var dysonFrame = dysonSphereLayer.framePool[i];
|
|
||||||
if (dysonFrame == null || dysonFrame.id != i) continue;
|
|
||||||
totalFrameSp += dysonFrame.spMax;
|
|
||||||
var spMax = dysonFrame.spMax / 2;
|
|
||||||
if (dysonFrame.spA < spMax)
|
|
||||||
{
|
|
||||||
rocketCount += spMax - dysonFrame.spA;
|
|
||||||
dysonFrame.spA = spMax;
|
|
||||||
dysonSphere.UpdateProgress(dysonFrame);
|
|
||||||
}
|
|
||||||
if (dysonFrame.spB < spMax)
|
|
||||||
{
|
|
||||||
rocketCount += spMax - dysonFrame.spB;
|
|
||||||
dysonFrame.spB = spMax;
|
|
||||||
dysonSphere.UpdateProgress(dysonFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (var i = dysonSphereLayer.nodeCursor - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
var dysonNode = dysonSphereLayer.nodePool[i];
|
|
||||||
if (dysonNode == null || dysonNode.id != i) continue;
|
|
||||||
dysonNode.spOrdered = 0;
|
|
||||||
dysonNode._spReq = 0;
|
|
||||||
totalNodeSp += dysonNode.spMax;
|
|
||||||
var diff = dysonNode.spMax - dysonNode.sp;
|
|
||||||
if (diff > 0)
|
|
||||||
{
|
|
||||||
rocketCount += diff;
|
|
||||||
dysonNode.sp = dysonNode.spMax;
|
|
||||||
dysonSphere.UpdateProgress(dysonNode);
|
|
||||||
}
|
|
||||||
dysonNode._cpReq = 0;
|
|
||||||
dysonNode.cpOrdered = 0;
|
|
||||||
foreach (var shell in dysonNode.shells)
|
|
||||||
{
|
|
||||||
var nodeIndex = shell.nodeIndexMap[dysonNode.id];
|
|
||||||
var cpMax = (shell.vertsqOffset[nodeIndex + 1] - shell.vertsqOffset[nodeIndex]) * shell.cpPerVertex;
|
|
||||||
totalCp += cpMax;
|
|
||||||
diff = cpMax - shell.nodecps[nodeIndex];
|
|
||||||
shell.nodecps[nodeIndex] = cpMax;
|
|
||||||
shell.nodecps[shell.nodecps.Length - 1] += diff;
|
|
||||||
solarSailCount += diff;
|
|
||||||
if (totalCpInfo != null)
|
|
||||||
{
|
|
||||||
shell.SetMaterialDynamicVars();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalNodeSpInfo?.SetValue(dysonSphereLayer, totalNodeSp);
|
|
||||||
totalFrameSpInfo?.SetValue(dysonSphereLayer, totalFrameSp);
|
|
||||||
totalCpInfo?.SetValue(dysonSphereLayer, totalCp);
|
|
||||||
}
|
|
||||||
dysonSphere.CheckAutoNodes();
|
|
||||||
|
|
||||||
var productRegister = dysonSphere.productRegister;
|
|
||||||
if (productRegister != null)
|
|
||||||
{
|
|
||||||
lock (productRegister)
|
|
||||||
{
|
|
||||||
var count = rocketCount;
|
|
||||||
while (count > 0x40000000L)
|
|
||||||
{
|
|
||||||
productRegister[11902] += 0x40000000;
|
|
||||||
count -= 0x40000000;
|
|
||||||
}
|
|
||||||
if (count > 0L) productRegister[11902] += (int)count;
|
|
||||||
count = solarSailCount;
|
|
||||||
while (count > 0x40000000L)
|
|
||||||
{
|
|
||||||
productRegister[11901] += 0x40000000;
|
|
||||||
productRegister[11903] += 0x40000000;
|
|
||||||
count -= 0x40000000;
|
|
||||||
}
|
|
||||||
if (count > 0L)
|
|
||||||
{
|
|
||||||
productRegister[11901] += (int)count;
|
|
||||||
productRegister[11903] += (int)count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var consumeRegister = dysonSphere.consumeRegister;
|
|
||||||
if (consumeRegister != null)
|
|
||||||
{
|
|
||||||
lock (consumeRegister)
|
|
||||||
{
|
|
||||||
var count = solarSailCount;
|
|
||||||
while (count > 0x40000000L)
|
|
||||||
{
|
|
||||||
consumeRegister[11901] += 0x40000000;
|
|
||||||
count -= 0x40000000;
|
|
||||||
}
|
|
||||||
if (count > 0L) consumeRegister[11901] += (int)count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using Random = UnityEngine.Random;
|
using Random = UnityEngine.Random;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler.Functions;
|
namespace CheatEnabler.Functions;
|
||||||
|
|
||||||
|
[ModFeature("PlanetFunctions")]
|
||||||
public static class PlanetFunctions
|
public static class PlanetFunctions
|
||||||
{
|
{
|
||||||
public static void BuryAllVeins(bool bury)
|
public static void BuryAllVeins(bool bury)
|
||||||
@@ -16,9 +19,15 @@ public static class PlanetFunctions
|
|||||||
{
|
{
|
||||||
var pos = array[m].pos;
|
var pos = array[m].pos;
|
||||||
var colliderId = array[m].colliderId;
|
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 colliderData = physics.GetColliderData(colliderId);
|
||||||
var vector = colliderData.pos.normalized * (height + 0.4f);
|
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;
|
array[m].pos = pos.normalized * height;
|
||||||
var quaternion = Maths.SphericalRotation(array[m].pos, Random.value * 360f);
|
var quaternion = Maths.SphericalRotation(array[m].pos, Random.value * 360f);
|
||||||
physics.SetPlanetPhysicsColliderDirty();
|
physics.SetPlanetPhysicsColliderDirty();
|
||||||
|
|||||||
@@ -1,40 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.GameConstants;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler.Functions;
|
namespace CheatEnabler.Functions;
|
||||||
|
|
||||||
|
[ModFeature("PlayerFunctions")]
|
||||||
public static class PlayerFunctions
|
public static class PlayerFunctions
|
||||||
{
|
{
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
I18N.Add("ClearAllMetadataConsumptionDetails",
|
}
|
||||||
"""
|
|
||||||
Metadata consumption records of all gamesaves are about to be cleared.
|
|
||||||
You will gain following metadata back:
|
|
||||||
""",
|
|
||||||
"""
|
|
||||||
所有存档的元数据消耗记录即将被清除,
|
|
||||||
此操作将返还以下元数据:
|
|
||||||
""");
|
|
||||||
I18N.Add("ClearCurrentMetadataConsumptionDetails",
|
|
||||||
"""
|
|
||||||
Metadata consumption records of current gamesave are about to be cleared.
|
|
||||||
You will gain following metadata back:
|
|
||||||
""",
|
|
||||||
"""
|
|
||||||
当前存档的元数据消耗记录即将被清除,
|
|
||||||
此操作将返还以下元数据:
|
|
||||||
""");
|
|
||||||
I18N.Add("NoMetadataConsumptionRecord",
|
|
||||||
"No metadata consumption records found.",
|
|
||||||
"未找到元数据消耗记录。");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void TeleportToOuterSpace()
|
public static void TeleportToOuterSpace()
|
||||||
{
|
{
|
||||||
var maxSqrDistance = 0.0;
|
var maxSqrDistance = 0.0;
|
||||||
var starPosition = VectorLF3.zero;
|
var starPosition = VectorLF3.zero;
|
||||||
|
if (GameMain.galaxy == null) return;
|
||||||
foreach (var star in GameMain.galaxy.stars)
|
foreach (var star in GameMain.galaxy.stars)
|
||||||
{
|
{
|
||||||
var sqrDistance = star.position.sqrMagnitude;
|
var sqrDistance = star.position.sqrMagnitude;
|
||||||
@@ -98,26 +81,26 @@ public static class PlayerFunctions
|
|||||||
var propertySystem = DSPGame.propertySystem;
|
var propertySystem = DSPGame.propertySystem;
|
||||||
if (propertySystem == null) return;
|
if (propertySystem == null) return;
|
||||||
PurgePropertySystem(propertySystem);
|
PurgePropertySystem(propertySystem);
|
||||||
var itemCnt = new int[6];
|
var itemCnt = new int[ItemIds.Metaverse - ItemIds.HydrogenFuelRod + 1];
|
||||||
foreach (var cons in propertySystem.propertyDatas.SelectMany(data => data.totalConsumption.Where(cons => cons.id is >= 6001 and <= 6006)))
|
foreach (var cons in propertySystem.propertyDatas.SelectMany(data => data.totalConsumption.Where(cons => cons.id is >= ItemIds.HydrogenFuelRod and <= ItemIds.Metaverse)))
|
||||||
{
|
{
|
||||||
itemCnt[cons.id - 6001] += cons.count;
|
itemCnt[cons.id - ItemIds.HydrogenFuelRod] += cons.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemCnt.All(cnt => cnt == 0))
|
if (itemCnt.All(cnt => cnt == 0))
|
||||||
{
|
{
|
||||||
UIMessageBox.Show("Remove all metadata consumption records".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), 0);
|
UIMessageBox.Show(Localization.RemoveAllMetadataConsumptionRecords.Translate(), Localization.NoMetadataConsumptionRecord.Translate(), Localization.OK.Translate(), UIMessageBox.INFO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var msg = "ClearAllMetadataConsumptionDetails".Translate();
|
var msg = Localization.ClearAllMetadataConsumptionDetails.Translate();
|
||||||
for (var i = 0; i < 6; i++)
|
for (var i = 0; i < itemCnt.Length; i++)
|
||||||
{
|
{
|
||||||
if (itemCnt[i] > 0)
|
if (itemCnt[i] > 0)
|
||||||
{
|
{
|
||||||
msg += $"\n {LDB.items.Select(i + 6001).propertyName} x{itemCnt[i]}";
|
msg += $"\n {LDB.items.Select(i + ItemIds.HydrogenFuelRod).propertyName} x{itemCnt[i]}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UIMessageBox.Show("Remove all metadata consumption records".Translate(), msg, "取消".Translate(), "确定".Translate(), 2, null, () =>
|
UIMessageBox.Show(Localization.RemoveAllMetadataConsumptionRecords.Translate(), msg, Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.QUESTION, null, () =>
|
||||||
{
|
{
|
||||||
foreach (var data in propertySystem.propertyDatas)
|
foreach (var data in propertySystem.propertyDatas)
|
||||||
{
|
{
|
||||||
@@ -138,41 +121,41 @@ public static class PlayerFunctions
|
|||||||
var propertySystem = DSPGame.propertySystem;
|
var propertySystem = DSPGame.propertySystem;
|
||||||
if (propertySystem == null) return;
|
if (propertySystem == null) return;
|
||||||
PurgePropertySystem(propertySystem);
|
PurgePropertySystem(propertySystem);
|
||||||
var itemCnt = new int[6];
|
var itemCnt = new int[ItemIds.Metaverse - ItemIds.HydrogenFuelRod + 1];
|
||||||
var seedKey = DSPGame.GameDesc.seedKey64;
|
var seedKey = DSPGame.GameDesc.seedKey64;
|
||||||
var clusterPropertyData = propertySystem.propertyDatas.FirstOrDefault(cpd => cpd.seedKey == seedKey);
|
var clusterPropertyData = propertySystem.propertyDatas.FirstOrDefault(cpd => cpd.seedKey == seedKey);
|
||||||
if (clusterPropertyData == null)
|
if (clusterPropertyData == null)
|
||||||
{
|
{
|
||||||
UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), 0);
|
UIMessageBox.Show(Localization.RemoveMetadataConsumptionRecordInCurrentGame.Translate(), Localization.NoMetadataConsumptionRecord.Translate(), Localization.OK.Translate(), UIMessageBox.INFO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var currentGamePropertyData = GameMain.data.history.propertyData;
|
var currentGamePropertyData = GameMain.data.history.propertyData;
|
||||||
foreach (var cons in currentGamePropertyData.totalConsumption.Where(cons => cons.id is >= 6001 and <= 6006))
|
foreach (var cons in currentGamePropertyData.totalConsumption.Where(cons => cons.id is >= ItemIds.HydrogenFuelRod and <= ItemIds.Metaverse))
|
||||||
{
|
{
|
||||||
itemCnt[cons.id - 6001] += cons.count;
|
itemCnt[cons.id - ItemIds.HydrogenFuelRod] += cons.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemCnt.All(cnt => cnt == 0))
|
if (itemCnt.All(cnt => cnt == 0))
|
||||||
{
|
{
|
||||||
UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), "NoMetadataConsumptionRecord".Translate(), "OK".Translate(), 0);
|
UIMessageBox.Show(Localization.RemoveMetadataConsumptionRecordInCurrentGame.Translate(), Localization.NoMetadataConsumptionRecord.Translate(), Localization.OK.Translate(), UIMessageBox.INFO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var msg = "ClearCurrentMetadataConsumptionDetails".Translate();
|
var msg = Localization.ClearCurrentMetadataConsumptionDetails.Translate();
|
||||||
for (var i = 0; i < 6; i++)
|
for (var i = 0; i < itemCnt.Length; i++)
|
||||||
{
|
{
|
||||||
if (itemCnt[i] > 0)
|
if (itemCnt[i] > 0)
|
||||||
{
|
{
|
||||||
msg += $"\n {LDB.items.Select(i + 6001).propertyName} x{itemCnt[i]}";
|
msg += $"\n {LDB.items.Select(i + ItemIds.HydrogenFuelRod).propertyName} x{itemCnt[i]}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UIMessageBox.Show("Remove metadata consumption record in current game".Translate(), msg, "取消".Translate(), "确定".Translate(), 2, null, () =>
|
UIMessageBox.Show(Localization.RemoveMetadataConsumptionRecordInCurrentGame.Translate(), msg, Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.QUESTION, null, () =>
|
||||||
{
|
{
|
||||||
for (var i = 0; i < clusterPropertyData.totalConsumption.Count; i++)
|
for (var i = 0; i < clusterPropertyData.totalConsumption.Count; i++)
|
||||||
{
|
{
|
||||||
if (clusterPropertyData.totalConsumption[i].count == 0) continue;
|
if (clusterPropertyData.totalConsumption[i].count == 0) continue;
|
||||||
var id = clusterPropertyData.totalConsumption[i].id;
|
var id = clusterPropertyData.totalConsumption[i].id;
|
||||||
if (id < 6001 || id > 6006) continue;
|
if (id < ItemIds.HydrogenFuelRod || id > ItemIds.Metaverse) continue;
|
||||||
var currentGameCount = itemCnt[id - 6001];
|
var currentGameCount = itemCnt[id - ItemIds.HydrogenFuelRod];
|
||||||
if (currentGameCount == 0) continue;
|
if (currentGameCount == 0) continue;
|
||||||
var totalCount = clusterPropertyData.totalConsumption[i].count;
|
var totalCount = clusterPropertyData.totalConsumption[i].count;
|
||||||
clusterPropertyData.totalConsumption[i] = new IDCNT(id, totalCount > currentGameCount ? totalCount - currentGameCount : 0);
|
clusterPropertyData.totalConsumption[i] = new IDCNT(id, totalCount > currentGameCount ? totalCount - currentGameCount : 0);
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace CheatEnabler;
|
||||||
|
|
||||||
|
public static class Localization
|
||||||
|
{
|
||||||
|
public const string CheatEnabler = "CheatEnabler";
|
||||||
|
public const string YouAreNotInAnySystem = "You are not in any system.";
|
||||||
|
public const string ThereIsNoDysonSphereShellOn0 = "There is no Dyson Sphere shell on \"{0}\".";
|
||||||
|
public const string ThereIsNoDysonSphereDataOn0 = "There is no Dyson Sphere data on \"{0}\".";
|
||||||
|
public const string ThisWillCompleteAllDysonSphereShellsOn0InstantlyAreYouSure = "This will complete all Dyson Sphere shells on \"{0}\". Are you sure?";
|
||||||
|
public const string ThisWillRemoveAllFramesOn0AreYouSure = "This will remove all frames on \"{0}\". Are you sure?";
|
||||||
|
public const string NoPrecalculatedShellFoundForRadius0 = "No precalculated shell found for radius {0}.";
|
||||||
|
public const string ClearAllMetadataConsumptionDetails = "ClearAllMetadataConsumptionDetails";
|
||||||
|
public const string ClearCurrentMetadataConsumptionDetails = "ClearCurrentMetadataConsumptionDetails";
|
||||||
|
public const string NoMetadataConsumptionRecord = "NoMetadataConsumptionRecord";
|
||||||
|
public const string KEYToggleNoCondition = "KEYToggleNoCondition";
|
||||||
|
public const string KEYToggleNoCollision = "KEYToggleNoCollision";
|
||||||
|
public const string NoConditionOn = "NoConditionOn";
|
||||||
|
public const string NoConditionOff = "NoConditionOff";
|
||||||
|
public const string NoCollisionOn = "NoCollisionOn";
|
||||||
|
public const string NoCollisionOff = "NoCollisionOff";
|
||||||
|
public const string BuildWithoutConditionIsEnabled = "Build without condition is enabled!";
|
||||||
|
public const string NoCollisionIsEnabled = "No collision is enabled!";
|
||||||
|
public const string Factory = "Factory";
|
||||||
|
public const string Planet = "Planet";
|
||||||
|
public const string MechaCombat = "Mecha/Combat";
|
||||||
|
public const string Cancel = "Cancel";
|
||||||
|
public const string OK = "OK";
|
||||||
|
public const string BuryAllVeins = "Bury all veins";
|
||||||
|
public const string RestoreBuriedVeins = "Restore buried veins";
|
||||||
|
public const string ReformEntirePlanet = "Reform entire planet";
|
||||||
|
public const string RevertPlanetTerrain = "Revert planet terrain";
|
||||||
|
public const string EnableDevShortcuts = "Enable Dev Shortcuts";
|
||||||
|
public const string DisableAbnormalChecks = "Disable Abnormal Checks";
|
||||||
|
public const string Hotkey = "Hotkey";
|
||||||
|
public const string UnlockTechWithKeyModifiers = "Unlock Tech with Key-Modifiers";
|
||||||
|
public const string DevShortcuts = "Dev Shortcuts";
|
||||||
|
public const string DevShortcutsTips = "Dev Shortcuts Tips";
|
||||||
|
public const string UnlockTechWithKeyModifiersTips = "Unlock Tech with Key-Modifiers Tips";
|
||||||
|
public const string RemoveAllMetadataConsumptionRecords = "Remove all metadata consumption records";
|
||||||
|
public const string RemoveMetadataConsumptionRecordInCurrentGame = "Remove metadata consumption record in current game";
|
||||||
|
public const string ClearMetadataFlagWhichBansAchievements = "Clear metadata flag which bans achievements";
|
||||||
|
public const string AssignGamesaveToCurrentAccount = "Assign gamesave to current account";
|
||||||
|
public const string FinishBuildImmediately = "Finish build immediately";
|
||||||
|
public const string ArchitectMode = "Architect mode";
|
||||||
|
public const string BuildWithoutCondition = "Build without condition";
|
||||||
|
public const string NoCollision = "No collision";
|
||||||
|
public const string BeltSignalGenerator = "Belt signal generator";
|
||||||
|
public const string CountProliferatorsUsedForRawsIntermediatesAndFinishedProducts = "Count proliferators used for raws/intermediates and finished products";
|
||||||
|
public const string CountProliferatorsUsedForRawsIntermediatesAndFinishedProductsTips = "Count proliferators used for raws/intermediates and finished products tips";
|
||||||
|
public const string BeltSignalAltFormat = "Belt signal alt format";
|
||||||
|
public const string BeltSignalAltFormatTips = "Belt signal alt format tips";
|
||||||
|
public const string CountGenerationsAsProductionInStatistics = "Count generations as production in statistics";
|
||||||
|
public const string CountRemovalsAsConsumptionInStatistics = "Count removals as consumption in statistics";
|
||||||
|
public const string CountAllRawsAndIntermediatesInStatistics = "Count all raws and intermediates in statistics";
|
||||||
|
public const string RemovePowerSpaceLimit = "Remove power space limit";
|
||||||
|
public const string BoostWindPower = "Boost wind power";
|
||||||
|
public const string BoostSolarPower = "Boost solar power";
|
||||||
|
public const string BoostFuelPower = "Boost fuel power";
|
||||||
|
public const string BoostFuelPower2 = "Boost fuel power 2";
|
||||||
|
public const string WindTurbinesDoGlobalPowerCoverage = "Wind Turbines do global power coverage";
|
||||||
|
public const string BoostGeothermalPower = "Boost geothermal power";
|
||||||
|
public const string RetrievePlaceItemsFromToRemotePlanetsOnLogisticsControlPanel = "Retrieve/Place items from/to remote planets on logistics control panel";
|
||||||
|
public const string InfiniteNaturalResources = "Infinite Natural Resources";
|
||||||
|
public const string FastMining = "Fast Mining";
|
||||||
|
public const string PumpAnywhere = "Pump Anywhere";
|
||||||
|
public const string SkipBulletPeriod = "Skip bullet period";
|
||||||
|
public const string FireAllBulletsAtOnce = "Fire all bullets at once";
|
||||||
|
public const string SkipAbsorptionPeriod = "Skip absorption period";
|
||||||
|
public const string QuickAbsorb = "Quick absorb";
|
||||||
|
public const string EjectAnyway = "Eject anyway";
|
||||||
|
public const string OverclockEjectors = "Overclock Ejectors";
|
||||||
|
public const string OverclockSilos = "Overclock Silos";
|
||||||
|
public const string UnlockDysonSphereMaxOrbitRadius = "Unlock Dyson Sphere max orbit radius";
|
||||||
|
public const string CompleteDysonSphereShellsInstantly = "Complete Dyson Sphere shells instantly";
|
||||||
|
public const string RemoveAllFramesOnDysonSphere = "Remove all frames on Dyson Sphere";
|
||||||
|
public const string GenerateIllegalDysonShell = "Generate illegal dyson shell";
|
||||||
|
public const string GenerateIllegalDysonShell2 = "Generate illegal dyson shell 2";
|
||||||
|
public const string KeepMaxProductionShellsAndRemoveOthers = "Keep max production shells and remove others";
|
||||||
|
public const string DuplicateShellsFromThatWithHighestProduction = "Duplicate shells from that with highest production";
|
||||||
|
public const string GenerateIllegalDysonShellQuickly = "Generate illegal dyson shell quickly";
|
||||||
|
public const string ShellsCount = "Shells count";
|
||||||
|
public const string WARNINGThisOperationCanBeVerySlowContinue = "WARNING: This operation can be very slow, continue?";
|
||||||
|
public const string WARNINGThisOperationIsDANGEROUSContinue = "WARNING: This operation is DANGEROUS, continue?";
|
||||||
|
public const string TerraformWithoutEnoughSoilPiles = "Terraform without enough soil piles";
|
||||||
|
public const string InstantHandCraft = "Instant hand-craft";
|
||||||
|
public const string InstantTeleportLikeThatInSandboxMode = "Instant teleport (like that in Sandbox mode)";
|
||||||
|
public const string MechaAndDronesFleetsInvicible = "Mecha and Drones/Fleets invicible";
|
||||||
|
public const string BuildingsInvicible = "Buildings invicible";
|
||||||
|
public const string EnableWarpWithoutSpaceWarpers = "Enable warp without space warpers";
|
||||||
|
public const string TeleportToOuterSpace = "Teleport to outer space";
|
||||||
|
public const string TeleportToSelectedAstronomical = "Teleport to selected astronomical";
|
||||||
|
|
||||||
|
public static void Register()
|
||||||
|
{
|
||||||
|
I18N.Add(CheatEnabler, "CheatEnabler", "作弊器");
|
||||||
|
I18N.Add(YouAreNotInAnySystem, "You are not in any system.", "你不在任何星系中");
|
||||||
|
I18N.Add(ThereIsNoDysonSphereShellOn0, "There is no Dyson Sphere shell on \"{0}\".", "“{0}”上没有可建造的戴森壳");
|
||||||
|
I18N.Add(ThereIsNoDysonSphereDataOn0, "There is no Dyson Sphere data on \"{0}\".", "“{0}”上没有戴森球数据");
|
||||||
|
I18N.Add(ThisWillCompleteAllDysonSphereShellsOn0InstantlyAreYouSure, "This will complete all Dyson Sphere shells on \"{0}\". Are you sure?", "这将完成“{0}”上的所有戴森壳。你确定吗?");
|
||||||
|
I18N.Add(ThisWillRemoveAllFramesOn0AreYouSure, "This will remove all frames on \"{0}\". Are you sure?", "这将移除“{0}”上的所有框架。你确定吗?");
|
||||||
|
I18N.Add(NoPrecalculatedShellFoundForRadius0, "No precalculated shell found for radius {0}.", "没有找到适合半径 {0} 的预计算壳面");
|
||||||
|
I18N.Add(ClearAllMetadataConsumptionDetails, """
|
||||||
|
|
||||||
|
Metadata consumption records of all gamesaves are about to be cleared.
|
||||||
|
You will gain following metadata back:
|
||||||
|
|
||||||
|
""", """
|
||||||
|
|
||||||
|
所有存档的元数据消耗记录即将被清除,
|
||||||
|
此操作将返还以下元数据:
|
||||||
|
|
||||||
|
""");
|
||||||
|
I18N.Add(ClearCurrentMetadataConsumptionDetails, """
|
||||||
|
|
||||||
|
Metadata consumption records of current gamesave are about to be cleared.
|
||||||
|
You will gain following metadata back:
|
||||||
|
|
||||||
|
""", """
|
||||||
|
|
||||||
|
当前存档的元数据消耗记录即将被清除,
|
||||||
|
此操作将返还以下元数据:
|
||||||
|
|
||||||
|
""");
|
||||||
|
I18N.Add(NoMetadataConsumptionRecord, "No metadata consumption records found.", "未找到元数据消耗记录。");
|
||||||
|
I18N.Add(KEYToggleNoCondition, "[CE] Toggle No Condition Build", "[CE] 切换无条件建造");
|
||||||
|
I18N.Add(KEYToggleNoCollision, "[CE] Toggle No Collision", "[CE] 切换无碰撞");
|
||||||
|
I18N.Add(NoConditionOn, "No condition build is enabled!", "无条件建造已开启");
|
||||||
|
I18N.Add(NoConditionOff, "No condition build is disabled!", "无条件建造已关闭");
|
||||||
|
I18N.Add(NoCollisionOn, "No collision is enabled!", "无碰撞已开启");
|
||||||
|
I18N.Add(NoCollisionOff, "No collision is disabled!", "无碰撞已关闭");
|
||||||
|
I18N.Add(BuildWithoutConditionIsEnabled, "!!Build without condition is enabled!!", "!!无条件建造已开启!!");
|
||||||
|
I18N.Add(NoCollisionIsEnabled, "!!No collision is enabled!!", "!!无碰撞已开启!!");
|
||||||
|
I18N.Add(Factory, "Factory", "工厂");
|
||||||
|
I18N.Add(Planet, "Planet", "行星");
|
||||||
|
I18N.Add(MechaCombat, "Mecha/Combat", "机甲/战斗");
|
||||||
|
I18N.Add(Cancel, "Cancel", "取消");
|
||||||
|
I18N.Add(OK, "OK", "确定");
|
||||||
|
I18N.Add(BuryAllVeins, "Bury all veins", "掩埋所有矿脉");
|
||||||
|
I18N.Add(RestoreBuriedVeins, "Restore buried veins", "还原所有矿脉");
|
||||||
|
I18N.Add(ReformEntirePlanet, "Reform entire planet", "铺满星球地基");
|
||||||
|
I18N.Add(RevertPlanetTerrain, "Revert planet terrain", "还原星球地形");
|
||||||
|
I18N.Add(EnableDevShortcuts, "Enable Dev Shortcuts", "开发模式快捷键");
|
||||||
|
I18N.Add(DisableAbnormalChecks, "Disable Abnormal Checks", "关闭数据异常检查");
|
||||||
|
I18N.Add(Hotkey, "Hotkey", "快捷键");
|
||||||
|
I18N.Add(UnlockTechWithKeyModifiers, "Unlock Tech with Key-Modifiers", "使用组合键点击解锁科技");
|
||||||
|
I18N.Add(DevShortcuts, "Dev Shortcuts", "开发模式快捷键");
|
||||||
|
I18N.Add(DevShortcutsTips, """
|
||||||
|
Caution: Some function may trigger abnormal check!
|
||||||
|
Numpad 1: Gets all items and extends bag.
|
||||||
|
Numpad 2: Boosts walk speed, gathering speed and mecha energy restoration.
|
||||||
|
Numpad 3: Fills planet with foundations and bury all veins.
|
||||||
|
Numpad 4: +1 construction drone.
|
||||||
|
Numpad 5: Upgrades drone engine tech to full.
|
||||||
|
Numpad 6: Unlocks researching tech.
|
||||||
|
Numpad 7: Unlocks Drive Engine 1.
|
||||||
|
Numpad 8: Unlocks Drive Engine 2 and maximize energy.
|
||||||
|
Numpad 9: Unlocks ability to warp.
|
||||||
|
Numpad 0: No costs for Logistic Storages' output.
|
||||||
|
LCtrl + T: Unlocks all techs (not upgrades).
|
||||||
|
LCtrl + Q: Adds 10000 to every metadata.
|
||||||
|
LCtrl + W: Enters Sandbox Mode.
|
||||||
|
LCtrl + Shift + W: Leaves Sandbox Mode.
|
||||||
|
Numpad *: Proliferates items on hand.
|
||||||
|
Numpad /: Removes proliferations from items on hand.
|
||||||
|
PageDown: Remembers Pose of game camera.
|
||||||
|
PageUp: Locks game camera using remembered Pose.
|
||||||
|
""", """
|
||||||
|
警告:某些功能可能触发异常检查!
|
||||||
|
小键盘1:获得所有物品并扩展背包
|
||||||
|
小键盘2:加快行走速度及采集速度,加快能量恢复速度
|
||||||
|
小键盘3:将地基铺设整个星球并掩埋所有矿物
|
||||||
|
小键盘4:建设机器人 +1
|
||||||
|
小键盘5:建设机器人满级
|
||||||
|
小键盘6:解锁当前科技
|
||||||
|
小键盘7:解锁驱动技术I
|
||||||
|
小键盘8:解锁驱动技术II 最大化能量
|
||||||
|
小键盘9:机甲曲速解锁
|
||||||
|
小键盘0:物流站通过传送带出物品无消耗
|
||||||
|
左Ctrl + T:解锁所有非升级科技
|
||||||
|
左Ctrl + Q:增加各项元数据10000点
|
||||||
|
左Ctrl + W:进入沙盒模式
|
||||||
|
左Ctrl + Shift + W:离开沙盒模式
|
||||||
|
小键盘乘号 *:给手上物品喷涂增产剂
|
||||||
|
小键盘除号 /:清除手上物品的增产剂
|
||||||
|
PageDown:记录摄像机当前的Pose
|
||||||
|
PageUp:用记录的Pose锁定摄像机
|
||||||
|
""");
|
||||||
|
I18N.Add(UnlockTechWithKeyModifiersTips, """
|
||||||
|
Click tech on tree while holding:
|
||||||
|
Shift: Tech level + 1
|
||||||
|
Ctrl: Tech level + 10
|
||||||
|
Ctrl + Shift: Tech level + 100
|
||||||
|
Alt: Tech level to MAX
|
||||||
|
|
||||||
|
Note: all direct prerequisites will be unlocked as well.
|
||||||
|
""", """
|
||||||
|
按住以下组合键点击科技树:
|
||||||
|
Shift:科技等级+1
|
||||||
|
Ctrl:科技等级+10
|
||||||
|
Ctrl+Shift:科技等级+100
|
||||||
|
Alt:科技等级升到最大
|
||||||
|
|
||||||
|
注意:所有直接前置科技也会被解锁
|
||||||
|
""");
|
||||||
|
I18N.Add(RemoveAllMetadataConsumptionRecords, "Remove all metadata consumption records", "移除所有元数据消耗记录");
|
||||||
|
I18N.Add(RemoveMetadataConsumptionRecordInCurrentGame, "Remove metadata consumption record in current game", "移除当前存档的元数据消耗记录");
|
||||||
|
I18N.Add(ClearMetadataFlagWhichBansAchievements, "Clear metadata flag which bans achievements in current game", "解除当前存档因使用元数据导致的成就限制");
|
||||||
|
I18N.Add(AssignGamesaveToCurrentAccount, "Assign gamesave to current account", "将游戏存档绑定给当前账号");
|
||||||
|
I18N.Add(FinishBuildImmediately, "Finish build immediately", "建造秒完成");
|
||||||
|
I18N.Add(ArchitectMode, "Architect mode", "建筑师模式");
|
||||||
|
I18N.Add(BuildWithoutCondition, "Build without condition check", "无条件建造");
|
||||||
|
I18N.Add(NoCollision, "No collision", "无碰撞");
|
||||||
|
I18N.Add(BeltSignalGenerator, "Belt signal generator", "传送带信号物品生成");
|
||||||
|
I18N.Add(CountProliferatorsUsedForRawsIntermediatesAndFinishedProducts, "Use proliferators for raws/intermediates and finished products", "原料、中间产物以及成品使用增产剂");
|
||||||
|
I18N.Add(CountProliferatorsUsedForRawsIntermediatesAndFinishedProductsTips, """
|
||||||
|
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.
|
||||||
|
""", """
|
||||||
|
以下物品使用额外产出: 钛合金, 棱镜, 框架材料, 增产剂 Mk.II, 增产剂 Mk.III, 磁线圈, 电动机, 电磁涡轮, 超级磁场环, 电路板, 推进器, 加力推进器, 电浆激发器, 粒子宽带, 引力透镜, 量子芯片, 湮灭约束球, 氘核燃料棒, 空间翘曲器, 戴森球组件, 小型运载火箭, 电磁矩阵, 结构矩阵, 信息矩阵, 引力矩阵, 宇宙矩阵
|
||||||
|
以下物品不使用增产剂: 卡西米尔晶体, 能量矩阵
|
||||||
|
其他物品使用加速生产
|
||||||
|
""");
|
||||||
|
I18N.Add(BeltSignalAltFormat, "Belt signal alt format", "传送带信号替换格式");
|
||||||
|
I18N.Add(BeltSignalAltFormatTips, """
|
||||||
|
Belt signal number format alternative format:
|
||||||
|
AAAABC by default
|
||||||
|
BCAAAA as alternative
|
||||||
|
AAAA=generation speed in minutes, B=proliferate points, C=stack count
|
||||||
|
""", """
|
||||||
|
传送带信号物品生成数量格式:
|
||||||
|
默认为AAAABC
|
||||||
|
勾选替换为BCAAAA
|
||||||
|
AAAA=生成速度,B=增产点数,C=堆叠数量
|
||||||
|
""");
|
||||||
|
I18N.Add(CountGenerationsAsProductionInStatistics, "Count generations as production in statistics", "统计信息里将生成计算为产物");
|
||||||
|
I18N.Add(CountRemovalsAsConsumptionInStatistics, "Count removals as consumption in statistics", "统计信息里将移除计算为消耗");
|
||||||
|
I18N.Add(CountAllRawsAndIntermediatesInStatistics, "Count all raw materials in statistics", "统计信息里计算所有原料和中间产物");
|
||||||
|
I18N.Add(RemovePowerSpaceLimit, "Remove space limit for winds and geothermals", "移除风力发电和地热发电的间距限制");
|
||||||
|
I18N.Add(BoostWindPower, "Boost wind power(x100,000)", "提升风力发电(x100,000)");
|
||||||
|
I18N.Add(BoostSolarPower, "Boost solar power(x100,000)", "提升太阳能发电(x100,000)");
|
||||||
|
I18N.Add(BoostFuelPower, "Boost fuel power(x50,000)", "提升燃料发电(x50,000)");
|
||||||
|
I18N.Add(BoostFuelPower2, "(x20,000 for deuteron, x10,000 for antimatter)", "(氘核燃料棒x20,000,反物质燃料棒x10,000)");
|
||||||
|
I18N.Add(WindTurbinesDoGlobalPowerCoverage, "Wind Turbines do global power coverage", "风力涡轮机供电覆盖全球");
|
||||||
|
I18N.Add(BoostGeothermalPower, "Boost geothermal power(x50,000)", "提升地热发电(x50,000)");
|
||||||
|
I18N.Add(RetrievePlaceItemsFromToRemotePlanetsOnLogisticsControlPanel, "Retrieve/Place items from/to remote planets on logistics control panel", "在物流总控面板上可以从非本地行星取放物品");
|
||||||
|
I18N.Add(InfiniteNaturalResources, "Infinite natural resources", "自然资源采集不消耗");
|
||||||
|
I18N.Add(FastMining, "Fast mining", "高速采集");
|
||||||
|
I18N.Add(PumpAnywhere, "Pump anywhere", "平地抽水");
|
||||||
|
I18N.Add(SkipBulletPeriod, "Skip bullet period", "跳过子弹阶段");
|
||||||
|
I18N.Add(FireAllBulletsAtOnce, "Fire all bullets at once", "一次弹射所有太阳帆");
|
||||||
|
I18N.Add(SkipAbsorptionPeriod, "Skip absorption period", "跳过吸收阶段");
|
||||||
|
I18N.Add(QuickAbsorb, "Quick absorb", "快速吸收");
|
||||||
|
I18N.Add(EjectAnyway, "Eject anyway", "全球弹射");
|
||||||
|
I18N.Add(OverclockEjectors, "Overclock Ejectors (10x)", "高速弹射器(10倍射速)");
|
||||||
|
I18N.Add(OverclockSilos, "Overclock Silos (10x)", "高速发射井(10倍射速)");
|
||||||
|
I18N.Add(UnlockDysonSphereMaxOrbitRadius, "Unlock Dyson Sphere max orbit radius", "解锁戴森球最大轨道半径");
|
||||||
|
I18N.Add(CompleteDysonSphereShellsInstantly, "Complete Dyson Sphere shells instantly", "立即完成戴森壳建造");
|
||||||
|
I18N.Add(RemoveAllFramesOnDysonSphere, "Remove all frames on Dyson Sphere", "移除戴森球上的所有框架");
|
||||||
|
I18N.Add(GenerateIllegalDysonShell, "Generate an illegal dyson shell (!!1st shell layer will be replaced!!)", "生成单层仙术戴森壳(!!会先删除第一层戴森壳!!)");
|
||||||
|
I18N.Add(GenerateIllegalDysonShell2, "Generate illegal dyson shells for all layers without nodes and shells", "为所有没有节点和壳的层级生成仙术戴森壳");
|
||||||
|
I18N.Add(KeepMaxProductionShellsAndRemoveOthers, "Keep max production shells and remove others", "保留发电量最高的戴森壳并移除其他戴森壳");
|
||||||
|
I18N.Add(DuplicateShellsFromThatWithHighestProduction, "Duplicate shells from that with highest production", "从发电量最高的壳复制戴森壳");
|
||||||
|
I18N.Add(GenerateIllegalDysonShellQuickly, "Generate illegal dyson shell quickly", "快速生成仙术戴森壳");
|
||||||
|
I18N.Add(ShellsCount, "Shells count", "壳面数量");
|
||||||
|
I18N.Add(WARNINGThisOperationCanBeVerySlowContinue, "WARNING: This operation can be very slow, continue?", "警告:此操作可能非常慢,继续吗?");
|
||||||
|
I18N.Add(WARNINGThisOperationIsDANGEROUSContinue, "WARNING: This operation is DANGEROUS, continue?", "警告:此操作非常危险,继续吗?");
|
||||||
|
I18N.Add(TerraformWithoutEnoughSoilPiles, "Terraform without enough soil piles", "沙土不够时依然可以整改地形");
|
||||||
|
I18N.Add(InstantHandCraft, "Instant hand-craft", "快速手动制造");
|
||||||
|
I18N.Add(InstantTeleportLikeThatInSandboxMode, "Instant teleport (like that in Sandbox mode)", "快速传送(和沙盒模式一样)");
|
||||||
|
I18N.Add(MechaAndDronesFleetsInvicible, "Mecha and Drones/Fleets invicible", "机甲和战斗无人机无敌");
|
||||||
|
I18N.Add(BuildingsInvicible, "Buildings invincible", "建筑无敌");
|
||||||
|
I18N.Add(EnableWarpWithoutSpaceWarpers, "Enable warp without space warpers", "无需空间翘曲器即可曲速飞行");
|
||||||
|
I18N.Add(TeleportToOuterSpace, "Teleport to outer space", "传送到外太空");
|
||||||
|
I18N.Add(TeleportToSelectedAstronomical, "Teleport to selected astronomical", "传送到选中的天体");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,11 @@ using System.Reflection.Emit;
|
|||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler.Patches;
|
namespace CheatEnabler.Patches;
|
||||||
|
|
||||||
|
[ModFeature("Combat")]
|
||||||
public static class CombatPatch
|
public static class CombatPatch
|
||||||
{
|
{
|
||||||
public static ConfigEntry<bool> MechaInvincibleEnabled;
|
public static ConfigEntry<bool> MechaInvincibleEnabled;
|
||||||
@@ -30,8 +32,11 @@ public static class CombatPatch
|
|||||||
MechaInvincible.Enable(false);
|
MechaInvincible.Enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MechaInvincible: PatchImpl<MechaInvincible>
|
private class MechaInvincible : PatchImpl<MechaInvincible>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: Player_get_invincible_Transpiler
|
||||||
|
// Target: Player.invincible (getter)
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(Player), nameof(Player.invincible), MethodType.Getter)]
|
[HarmonyPatch(typeof(Player), nameof(Player.invincible), MethodType.Getter)]
|
||||||
private static IEnumerable<CodeInstruction> Player_get_invincible_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> Player_get_invincible_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -43,7 +48,9 @@ public static class CombatPatch
|
|||||||
);
|
);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: SkillSystem_DamageObject_Transpiler
|
||||||
|
// Target: SkillSystem.DamageGroundObjectByLocalCaster, SkillSystem.DamageGroundObjectByRemoteCaster, SkillSystem.DamageObject
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByLocalCaster))]
|
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByLocalCaster))]
|
||||||
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByRemoteCaster))]
|
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByRemoteCaster))]
|
||||||
@@ -65,8 +72,11 @@ public static class CombatPatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BuildingsInvincible: PatchImpl<BuildingsInvincible>
|
private class BuildingsInvincible : PatchImpl<BuildingsInvincible>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: SkillSystem_DamageObject_Transpiler
|
||||||
|
// Target: SkillSystem.DamageGroundObjectByLocalCaster, SkillSystem.DamageGroundObjectByRemoteCaster
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByLocalCaster))]
|
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByLocalCaster))]
|
||||||
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByRemoteCaster))]
|
[HarmonyPatch(typeof(SkillSystem), nameof(SkillSystem.DamageGroundObjectByRemoteCaster))]
|
||||||
|
|||||||
@@ -3,14 +3,17 @@ using System.Collections.Generic;
|
|||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using UnityEngine;
|
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||||
|
|
||||||
namespace CheatEnabler.Patches;
|
namespace CheatEnabler.Patches;
|
||||||
|
|
||||||
|
[ModFeature("DysonSphere")]
|
||||||
public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
||||||
{
|
{
|
||||||
public static ConfigEntry<bool> SkipBulletEnabled;
|
public static ConfigEntry<bool> SkipBulletEnabled;
|
||||||
|
public static ConfigEntry<bool> FireAllBulletsEnabled;
|
||||||
public static ConfigEntry<bool> SkipAbsorbEnabled;
|
public static ConfigEntry<bool> SkipAbsorbEnabled;
|
||||||
public static ConfigEntry<bool> QuickAbsorbEnabled;
|
public static ConfigEntry<bool> QuickAbsorbEnabled;
|
||||||
public static ConfigEntry<bool> EjectAnywayEnabled;
|
public static ConfigEntry<bool> EjectAnywayEnabled;
|
||||||
@@ -29,6 +32,8 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
OverclockEjectorEnabled.SettingChanged += (_, _) => OverclockEjector.Enable(OverclockEjectorEnabled.Value);
|
OverclockEjectorEnabled.SettingChanged += (_, _) => OverclockEjector.Enable(OverclockEjectorEnabled.Value);
|
||||||
OverclockSiloEnabled.SettingChanged += (_, _) => OverclockSilo.Enable(OverclockSiloEnabled.Value);
|
OverclockSiloEnabled.SettingChanged += (_, _) => OverclockSilo.Enable(OverclockSiloEnabled.Value);
|
||||||
UnlockMaxOrbitRadiusEnabled.SettingChanged += (_, _) => UnlockMaxOrbitRadius.Enable(UnlockMaxOrbitRadiusEnabled.Value);
|
UnlockMaxOrbitRadiusEnabled.SettingChanged += (_, _) => UnlockMaxOrbitRadius.Enable(UnlockMaxOrbitRadiusEnabled.Value);
|
||||||
|
|
||||||
|
FireAllBulletsEnabled.SettingChanged += (_, _) => SkipBulletPatch.SetFireAllBullets(FireAllBulletsEnabled.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Start()
|
public static void Start()
|
||||||
@@ -41,6 +46,7 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
OverclockSilo.Enable(OverclockSiloEnabled.Value);
|
OverclockSilo.Enable(OverclockSiloEnabled.Value);
|
||||||
UnlockMaxOrbitRadius.Enable(UnlockMaxOrbitRadiusEnabled.Value);
|
UnlockMaxOrbitRadius.Enable(UnlockMaxOrbitRadiusEnabled.Value);
|
||||||
Enable(true);
|
Enable(true);
|
||||||
|
SkipBulletPatch.SetFireAllBullets(FireAllBulletsEnabled.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Uninit()
|
public static void Uninit()
|
||||||
@@ -55,6 +61,15 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
UnlockMaxOrbitRadius.Enable(false);
|
UnlockMaxOrbitRadius.Enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [HarmonyPostfix]
|
||||||
|
// [HarmonyPatch(typeof(DysonShell), nameof(DysonShell.ImportFromBlueprint))]
|
||||||
|
// private static void DysonShell_ImportFromBlueprint_Postfix(DysonShell __instance)
|
||||||
|
// {
|
||||||
|
// CheatEnabler.Logger.LogDebug($"[DysonShell.ImportFromBlueprint] vertCount={__instance.vertexCount}, cpPerVertex={__instance.cpPerVertex}, cpMax={__instance.cellPointMax}");
|
||||||
|
// }
|
||||||
|
// Harmony transpiler: DysonNode_OrderConstructCp_Transpiler
|
||||||
|
// Target: DysonNode.OrderConstructCp
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(DysonNode), nameof(DysonNode.OrderConstructCp))]
|
[HarmonyPatch(typeof(DysonNode), nameof(DysonNode.OrderConstructCp))]
|
||||||
private static IEnumerable<CodeInstruction> DysonNode_OrderConstructCp_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> DysonNode_OrderConstructCp_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -69,7 +84,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
);
|
);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: DysonSwarm_AbsorbSail_Transpiler
|
||||||
|
// Target: DysonSwarm.AbsorbSail
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(DysonSwarm), nameof(DysonSwarm.AbsorbSail))]
|
[HarmonyPatch(typeof(DysonSwarm), nameof(DysonSwarm.AbsorbSail))]
|
||||||
private static IEnumerable<CodeInstruction> DysonSwarm_AbsorbSail_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> DysonSwarm_AbsorbSail_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -94,6 +111,12 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
private static long _sailLifeTime;
|
private static long _sailLifeTime;
|
||||||
private static DysonSailCache[][] _sailsCache;
|
private static DysonSailCache[][] _sailsCache;
|
||||||
private static int[] _sailsCacheLen, _sailsCacheCapacity;
|
private static int[] _sailsCacheLen, _sailsCacheCapacity;
|
||||||
|
private static bool _fireAllBullets;
|
||||||
|
|
||||||
|
public static void SetFireAllBullets(bool value)
|
||||||
|
{
|
||||||
|
_fireAllBullets = value;
|
||||||
|
}
|
||||||
|
|
||||||
private struct DysonSailCache
|
private struct DysonSailCache
|
||||||
{
|
{
|
||||||
@@ -117,12 +140,12 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
{
|
{
|
||||||
UpdateSailLifeTime();
|
UpdateSailLifeTime();
|
||||||
UpdateSailsCacheForThisGame();
|
UpdateSailsCacheForThisGame();
|
||||||
GameLogic.OnGameBegin += GameMain_Begin_Postfix;
|
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisable()
|
protected override void OnDisable()
|
||||||
{
|
{
|
||||||
GameLogic.OnGameBegin -= GameMain_Begin_Postfix;
|
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateSailLifeTime()
|
private static void UpdateSailLifeTime()
|
||||||
@@ -155,7 +178,7 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
_sailsCacheCapacity[index] = capacity;
|
_sailsCacheCapacity[index] = capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GameMain_Begin_Postfix()
|
private static void OnGameBegin()
|
||||||
{
|
{
|
||||||
UpdateSailsCacheForThisGame();
|
UpdateSailsCacheForThisGame();
|
||||||
UpdateSailLifeTime();
|
UpdateSailLifeTime();
|
||||||
@@ -170,7 +193,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
UpdateSailLifeTime();
|
UpdateSailLifeTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: EjectorComponent_InternalUpdate_Transpiler
|
||||||
|
// Target: EjectorComponent.InternalUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(EjectorComponent), nameof(EjectorComponent.InternalUpdate))]
|
[HarmonyPatch(typeof(EjectorComponent), nameof(EjectorComponent.InternalUpdate))]
|
||||||
private static IEnumerable<CodeInstruction> EjectorComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> EjectorComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -181,25 +206,28 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
).Advance(2);
|
).Advance(2);
|
||||||
var start = matcher.Pos;
|
var start = matcher.Pos;
|
||||||
matcher.MatchForward(false,
|
matcher.MatchForward(false,
|
||||||
new CodeMatch(OpCodes.Pop)
|
new CodeMatch(OpCodes.Ldc_I4_M1),
|
||||||
).Advance(1);
|
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(EjectorComponent), nameof(EjectorComponent.direction)))
|
||||||
|
).Advance(2);
|
||||||
var end = matcher.Pos;
|
var end = matcher.Pos;
|
||||||
matcher.Start().Advance(start).RemoveInstructions(end - start).Insert(
|
matcher.Start().Advance(start).RemoveInstructions(end - start).Insert(
|
||||||
new CodeInstruction(OpCodes.Ldarg_3),
|
|
||||||
new CodeInstruction(OpCodes.Ldarg_0),
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(EjectorComponent), nameof(EjectorComponent.orbitId))),
|
new CodeInstruction(OpCodes.Ldarg_3),
|
||||||
new CodeInstruction(OpCodes.Ldloc_S, 9),
|
new CodeInstruction(OpCodes.Ldloc_S, 9),
|
||||||
new CodeInstruction(OpCodes.Ldloc_S, 11),
|
new CodeInstruction(OpCodes.Ldloc_S, 11),
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_S, 6),
|
||||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(SkipBulletPatch), nameof(SkipBulletPatch.AddDysonSail)))
|
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(SkipBulletPatch), nameof(SkipBulletPatch.AddDysonSail)))
|
||||||
);
|
);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddDysonSail(DysonSwarm swarm, int orbitId, VectorLF3 uPos, VectorLF3 endVec)
|
private static void AddDysonSail(ref EjectorComponent ejector, DysonSwarm swarm, VectorLF3 uPos, VectorLF3 endVec, int[] consumeRegister)
|
||||||
{
|
{
|
||||||
var index = swarm.starData.index;
|
var index = swarm.starData.index;
|
||||||
|
var orbitId = ejector.orbitId;
|
||||||
var delta1 = endVec - swarm.starData.uPosition;
|
var delta1 = endVec - swarm.starData.uPosition;
|
||||||
var delta2 = VectorLF3.Cross(endVec - uPos, swarm.orbits[orbitId].up).normalized * Math.Sqrt(swarm.dysonSphere.gravity / swarm.orbits[orbitId].radius);
|
var delta2 = VectorLF3.Cross(endVec - uPos, swarm.orbits[orbitId].up).normalized * Math.Sqrt(swarm.dysonSphere.gravity / swarm.orbits[orbitId].radius);
|
||||||
|
var bulletCount = ejector.bulletCount;
|
||||||
lock (swarm)
|
lock (swarm)
|
||||||
{
|
{
|
||||||
var cache = _sailsCache[index];
|
var cache = _sailsCache[index];
|
||||||
@@ -209,6 +237,24 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
SetSailsCacheCapacity(index, 256);
|
SetSailsCacheCapacity(index, 256);
|
||||||
cache = _sailsCache[index];
|
cache = _sailsCache[index];
|
||||||
}
|
}
|
||||||
|
if (_fireAllBullets)
|
||||||
|
{
|
||||||
|
var capacity = _sailsCacheCapacity[index];
|
||||||
|
var leastCapacity = len + bulletCount;
|
||||||
|
if (leastCapacity > capacity)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
capacity *= 2;
|
||||||
|
} while (leastCapacity > capacity);
|
||||||
|
SetSailsCacheCapacity(index, capacity);
|
||||||
|
cache = _sailsCache[index];
|
||||||
|
}
|
||||||
|
_sailsCacheLen[index] = len + bulletCount;
|
||||||
|
var end = len + bulletCount;
|
||||||
|
for (var i = len; i < end; i++)
|
||||||
|
cache[i].FromData(delta1, delta2 + RandomTable.SphericNormal(ref swarm.randSeed, 0.5), orbitId);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var capacity = _sailsCacheCapacity[index];
|
var capacity = _sailsCacheCapacity[index];
|
||||||
@@ -217,14 +263,48 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
SetSailsCacheCapacity(index, capacity * 2);
|
SetSailsCacheCapacity(index, capacity * 2);
|
||||||
cache = _sailsCache[index];
|
cache = _sailsCache[index];
|
||||||
}
|
}
|
||||||
|
_sailsCacheLen[index] = len + 1;
|
||||||
|
cache[len].FromData(delta1, delta2 + RandomTable.SphericNormal(ref swarm.randSeed, 0.5), orbitId);
|
||||||
}
|
}
|
||||||
_sailsCacheLen[index] = len + 1;
|
|
||||||
cache[len].FromData(delta1, delta2 + RandomTable.SphericNormal(ref swarm.randSeed, 0.5), orbitId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_fireAllBullets)
|
||||||
|
{
|
||||||
|
if (!ejector.incUsed)
|
||||||
|
{
|
||||||
|
ejector.incUsed = ejector.bulletInc >= bulletCount;
|
||||||
|
}
|
||||||
|
ejector.bulletInc = 0;
|
||||||
|
ejector.bulletCount = 0;
|
||||||
|
lock (consumeRegister)
|
||||||
|
{
|
||||||
|
consumeRegister[ejector.bulletId] += bulletCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var inc = ejector.bulletInc / bulletCount;
|
||||||
|
if (!ejector.incUsed)
|
||||||
|
{
|
||||||
|
ejector.incUsed = inc > 0;
|
||||||
|
}
|
||||||
|
ejector.bulletInc -= inc;
|
||||||
|
ejector.bulletCount = bulletCount - 1;
|
||||||
|
if (ejector.bulletCount == 0)
|
||||||
|
{
|
||||||
|
ejector.bulletInc = 0;
|
||||||
|
}
|
||||||
|
lock (consumeRegister)
|
||||||
|
{
|
||||||
|
consumeRegister[ejector.bulletId]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ejector.time = ejector.coldSpend;
|
||||||
|
ejector.direction = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(DysonSwarm), "GameTick")]
|
[HarmonyPatch(typeof(DysonSwarm), nameof(DysonSwarm.GameTick))]
|
||||||
public static void DysonSwarm_GameTick_Prefix(DysonSwarm __instance, long time)
|
public static void DysonSwarm_GameTick_Prefix(DysonSwarm __instance, long time)
|
||||||
{
|
{
|
||||||
var index = __instance.starData.index;
|
var index = __instance.starData.index;
|
||||||
@@ -262,9 +342,10 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
if (node.ConstructCp() == null) break;
|
if (node.ConstructCp() == null) break;
|
||||||
if (idx == 0)
|
if (idx == 0)
|
||||||
{
|
{
|
||||||
sphereProductRegister[11901] += len;
|
sphereProductRegister[ProductionStatistics.SOLAR_SAIL_ID] += len;
|
||||||
sphereConsumeRegister[11901] += len;
|
sphereConsumeRegister[ProductionStatistics.SOLAR_SAIL_ID] += len;
|
||||||
sphereProductRegister[11903] += len;
|
sphereProductRegister[ProductionStatistics.DYSON_CELL_ID] += len;
|
||||||
|
__instance.dysonSphere.needRecalculatePower = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
idx--;
|
idx--;
|
||||||
@@ -275,9 +356,10 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
var absorbCnt = len - 1 - idx;
|
var absorbCnt = len - 1 - idx;
|
||||||
if (absorbCnt > 0)
|
if (absorbCnt > 0)
|
||||||
{
|
{
|
||||||
sphereProductRegister[11901] += absorbCnt;
|
sphereProductRegister[ProductionStatistics.SOLAR_SAIL_ID] += absorbCnt;
|
||||||
sphereConsumeRegister[11901] += absorbCnt;
|
sphereConsumeRegister[ProductionStatistics.SOLAR_SAIL_ID] += absorbCnt;
|
||||||
sphereProductRegister[11903] += absorbCnt;
|
sphereProductRegister[ProductionStatistics.DYSON_CELL_ID] += absorbCnt;
|
||||||
|
__instance.dysonSphere.needRecalculatePower = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (; idx >= 0; idx--)
|
for (; idx >= 0; idx--)
|
||||||
@@ -291,14 +373,16 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
{
|
{
|
||||||
protected override void OnEnable()
|
protected override void OnEnable()
|
||||||
{
|
{
|
||||||
_instantAbsorb = QuickAbsorbEnabled.Value;
|
_instantAbsorb = QuickAbsorbEnabled.Value && QuickAbsorbPatch.GetHarmony() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisable()
|
protected override void OnDisable()
|
||||||
{
|
{
|
||||||
_instantAbsorb = false;
|
_instantAbsorb = QuickAbsorbEnabled.Value && QuickAbsorbPatch.GetHarmony() != null;
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: DysonSwarm_AbsorbSail_Transpiler2
|
||||||
|
// Target: DysonSwarm.AbsorbSail
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(DysonSwarm), nameof(DysonSwarm.AbsorbSail))]
|
[HarmonyPatch(typeof(DysonSwarm), nameof(DysonSwarm.AbsorbSail))]
|
||||||
private static IEnumerable<CodeInstruction> DysonSwarm_AbsorbSail_Transpiler2(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> DysonSwarm_AbsorbSail_Transpiler2(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -308,30 +392,20 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
matcher.MatchForward(false,
|
matcher.MatchForward(false,
|
||||||
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(ExpiryOrder), nameof(ExpiryOrder.index)))
|
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(ExpiryOrder), nameof(ExpiryOrder.index)))
|
||||||
).Advance(1).RemoveInstructions(matcher.Length - matcher.Pos).Insert(
|
).Advance(1).RemoveInstructions(matcher.Length - matcher.Pos).Insert(
|
||||||
// if (node.ConstructCp() != null)
|
|
||||||
// {
|
|
||||||
// this.dysonSphere.productRegister[11903]++;
|
|
||||||
// }
|
|
||||||
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.Ldarg_0),
|
||||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(DysonSwarm), nameof(DysonSwarm.dysonSphere))),
|
new CodeInstruction(OpCodes.Ldarg_1),
|
||||||
new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(DysonSphere), nameof(DysonSphere.productRegister))),
|
|
||||||
new CodeInstruction(OpCodes.Ldc_I4, 11903),
|
|
||||||
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.Ldloc_1),
|
new CodeInstruction(OpCodes.Ldloc_1),
|
||||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DysonSwarm), nameof(DysonSwarm.RemoveSolarSail))),
|
Transpilers.EmitDelegate((DysonSwarm swarm, DysonNode node, int index) =>
|
||||||
|
{
|
||||||
// return false;
|
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.Ldc_I4_1),
|
||||||
new CodeInstruction(OpCodes.Ret)
|
new CodeInstruction(OpCodes.Ret)
|
||||||
);
|
);
|
||||||
@@ -343,14 +417,16 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
{
|
{
|
||||||
protected override void OnEnable()
|
protected override void OnEnable()
|
||||||
{
|
{
|
||||||
_instantAbsorb = SkipAbsorbEnabled.Value;
|
_instantAbsorb = SkipAbsorbEnabled.Value && SkipAbsorbPatch.GetHarmony() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisable()
|
protected override void OnDisable()
|
||||||
{
|
{
|
||||||
_instantAbsorb = false;
|
_instantAbsorb = SkipAbsorbEnabled.Value && SkipAbsorbPatch.GetHarmony() != null;
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: DysonSphereLayer_GameTick_Transpiler
|
||||||
|
// Target: DysonSphereLayer.GameTick
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(DysonSphereLayer), nameof(DysonSphereLayer.GameTick))]
|
[HarmonyPatch(typeof(DysonSphereLayer), nameof(DysonSphereLayer.GameTick))]
|
||||||
private static IEnumerable<CodeInstruction> DysonSphereLayer_GameTick_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> DysonSphereLayer_GameTick_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -392,6 +468,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
|
|
||||||
private class EjectAnywayPatch : PatchImpl<EjectAnywayPatch>
|
private class EjectAnywayPatch : PatchImpl<EjectAnywayPatch>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: EjectorComponent_InternalUpdate_Transpiler
|
||||||
|
// Target: EjectorComponent.InternalUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(EjectorComponent), nameof(EjectorComponent.InternalUpdate))]
|
[HarmonyPatch(typeof(EjectorComponent), nameof(EjectorComponent.InternalUpdate))]
|
||||||
private static IEnumerable<CodeInstruction> EjectorComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> EjectorComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -422,6 +501,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
|
|
||||||
private class OverclockEjector : PatchImpl<OverclockEjector>
|
private class OverclockEjector : PatchImpl<OverclockEjector>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: EjectComponent_InternalUpdate_Transpiler
|
||||||
|
// Target: EjectorComponent.InternalUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(EjectorComponent), nameof(EjectorComponent.InternalUpdate))]
|
[HarmonyPatch(typeof(EjectorComponent), nameof(EjectorComponent.InternalUpdate))]
|
||||||
private static IEnumerable<CodeInstruction> EjectComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> EjectComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -444,7 +526,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
matcher.Start().Advance(pos).RemoveInstructions(end - pos);
|
matcher.Start().Advance(pos).RemoveInstructions(end - pos);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: UIEjectAndSiloWindow__OnUpdate_Transpiler
|
||||||
|
// Target: UIEjectorWindow._OnUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(UIEjectorWindow), nameof(UIEjectorWindow._OnUpdate))]
|
[HarmonyPatch(typeof(UIEjectorWindow), nameof(UIEjectorWindow._OnUpdate))]
|
||||||
private static IEnumerable<CodeInstruction> UIEjectAndSiloWindow__OnUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> UIEjectAndSiloWindow__OnUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -475,6 +559,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
|
|
||||||
private class OverclockSilo : PatchImpl<OverclockSilo>
|
private class OverclockSilo : PatchImpl<OverclockSilo>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: SiloComponent_InternalUpdate_Transpiler
|
||||||
|
// Target: SiloComponent.InternalUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(SiloComponent), nameof(SiloComponent.InternalUpdate))]
|
[HarmonyPatch(typeof(SiloComponent), nameof(SiloComponent.InternalUpdate))]
|
||||||
private static IEnumerable<CodeInstruction> SiloComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> SiloComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -497,7 +584,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
matcher.Start().Advance(pos).RemoveInstructions(end - pos);
|
matcher.Start().Advance(pos).RemoveInstructions(end - pos);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: UIEjectAndSiloWindow__OnUpdate_Transpiler
|
||||||
|
// Target: UISiloWindow._OnUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(UISiloWindow), nameof(UISiloWindow._OnUpdate))]
|
[HarmonyPatch(typeof(UISiloWindow), nameof(UISiloWindow._OnUpdate))]
|
||||||
private static IEnumerable<CodeInstruction> UIEjectAndSiloWindow__OnUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> UIEjectAndSiloWindow__OnUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -546,7 +635,9 @@ public class DysonSpherePatch : PatchImpl<DysonSpherePatch>
|
|||||||
if (dysonEditor == null || !dysonEditor.gameObject.activeSelf) return;
|
if (dysonEditor == null || !dysonEditor.gameObject.activeSelf) return;
|
||||||
dysonEditor.selection?.onViewStarChange?.Invoke();
|
dysonEditor.selection?.onViewStarChange?.Invoke();
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: MaxOrbitRadiusPatch_Transpiler
|
||||||
|
// Target: DysonSphere.CheckLayerRadius, DysonSphere.CheckSwarmRadius, DysonSphere.QueryLayerRadius, DysonSphere.QuerySwarmRadius, UIDEAddLayerDialogue.OnViewStarChange, UIDEAddSwarmDialogue.OnViewStarChange, UIDysonEditor.OnViewStarChange, UIDESwarmOrbitInfo._OnInit, UIDysonOrbitPreview.UpdateAscNodeGizmos
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(DysonSphere), nameof(DysonSphere.CheckLayerRadius))]
|
[HarmonyPatch(typeof(DysonSphere), nameof(DysonSphere.CheckLayerRadius))]
|
||||||
[HarmonyPatch(typeof(DysonSphere), nameof(DysonSphere.CheckSwarmRadius))]
|
[HarmonyPatch(typeof(DysonSphere), nameof(DysonSphere.CheckSwarmRadius))]
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Patches.Factory;
|
||||||
|
|
||||||
|
internal class ArchitectMode : PatchImpl<ArchitectMode>
|
||||||
|
{
|
||||||
|
private static bool[] _canBuildItems;
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
var factory = GameMain.mainPlayer?.factory;
|
||||||
|
if (factory?.planet?.data != null)
|
||||||
|
{
|
||||||
|
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.TakeTailItems), [typeof(int), typeof(int), typeof(int), typeof(bool)],
|
||||||
|
[ArgumentType.Ref, ArgumentType.Ref, ArgumentType.Out, ArgumentType.Normal])]
|
||||||
|
[HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.TakeTailItems), [typeof(int), typeof(int), typeof(int[]), typeof(int), typeof(bool)],
|
||||||
|
[ArgumentType.Ref, ArgumentType.Ref, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal])]
|
||||||
|
public static bool TakeTailItemsPatch(StorageComponent __instance, int itemId)
|
||||||
|
{
|
||||||
|
if (__instance == null || GameMain.mainPlayer == null || __instance.id != GameMain.mainPlayer.package.id) return true;
|
||||||
|
if (itemId <= 0) return true;
|
||||||
|
if (_canBuildItems == null)
|
||||||
|
{
|
||||||
|
DoInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemId >= 12000 || !_canBuildItems[itemId];
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.GetItemCount), typeof(int))]
|
||||||
|
public static void GetItemCountPatch(StorageComponent __instance, int itemId, ref int __result)
|
||||||
|
{
|
||||||
|
if (__result > 99) return;
|
||||||
|
if (__instance == null || GameMain.mainPlayer == null || __instance.id != GameMain.mainPlayer.package.id) return;
|
||||||
|
if (itemId <= 0) return;
|
||||||
|
if (_canBuildItems == null)
|
||||||
|
{
|
||||||
|
DoInit();
|
||||||
|
}
|
||||||
|
if (itemId < 12000 && _canBuildItems[itemId]) __result = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DoInit()
|
||||||
|
{
|
||||||
|
_canBuildItems = new bool[12000];
|
||||||
|
foreach (var ip in LDB.items.dataArray)
|
||||||
|
{
|
||||||
|
if ((ip.Type == EItemType.Logistics || ip.CanBuild) && ip.ID < 12000) _canBuildItems[ip.ID] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,790 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||||
|
using UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Patches.Factory;
|
||||||
|
|
||||||
|
[ModFeature("BeltSignalGenerator")]
|
||||||
|
internal class BeltSignalGenerator : PatchImpl<BeltSignalGenerator>
|
||||||
|
{
|
||||||
|
private static Dictionary<int, BeltSignal>[] _signalBelts;
|
||||||
|
private static Dictionary<long, int> _portalFrom;
|
||||||
|
private static Dictionary<int, HashSet<long>> _portalTo;
|
||||||
|
private static int _signalBeltsCapacity;
|
||||||
|
private static bool _initialized;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameLogicProc.OnGameEnd += ResetState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Uninit()
|
||||||
|
{
|
||||||
|
GameLogicProc.OnGameEnd -= ResetState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ResetState()
|
||||||
|
{
|
||||||
|
_initialized = false;
|
||||||
|
_signalBelts = null;
|
||||||
|
_portalFrom = null;
|
||||||
|
_portalTo = null;
|
||||||
|
_signalBeltsCapacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BeltSignal
|
||||||
|
{
|
||||||
|
public int SignalId;
|
||||||
|
public int SpeedLimit;
|
||||||
|
public byte Stack;
|
||||||
|
public byte Inc;
|
||||||
|
public int Progress;
|
||||||
|
public (int itemId, float itemCount, bool isExtra)[] Sources;
|
||||||
|
public float[] SourceProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
InitSignalBelts();
|
||||||
|
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDisable()
|
||||||
|
{
|
||||||
|
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||||
|
_initialized = false;
|
||||||
|
_signalBelts = null;
|
||||||
|
_signalBeltsCapacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnAltFormatChanged()
|
||||||
|
{
|
||||||
|
if (_signalBelts == null) return;
|
||||||
|
var factories = GameMain.data?.factories;
|
||||||
|
if (factories == null) return;
|
||||||
|
var factoryCount = GameMain.data.factoryCount;
|
||||||
|
var altFormat = FactoryPatch.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;
|
||||||
|
ref var signal = ref entitySignPool[belt.entityId];
|
||||||
|
if (signal.iconId0 < 1000) continue;
|
||||||
|
var signalBelt = pair.Value;
|
||||||
|
var inc = signalBelt.Inc / signalBelt.Stack;
|
||||||
|
if (altFormat)
|
||||||
|
signal.count0 = signalBelt.SpeedLimit + signalBelt.Stack * 10000 + inc * 100000;
|
||||||
|
else
|
||||||
|
signal.count0 = signalBelt.SpeedLimit * 100 + signalBelt.Stack + inc * 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnUseProliferatorChanged()
|
||||||
|
{
|
||||||
|
if (_signalBelts == null) return;
|
||||||
|
var factories = GameMain.data?.factories;
|
||||||
|
if (factories == null) return;
|
||||||
|
var factoryCount = GameMain.data.factoryCount;
|
||||||
|
var altFormat = FactoryPatch.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 (DSPGame.IsMenuDemo) return;
|
||||||
|
InitItemSources();
|
||||||
|
_signalBelts = new Dictionary<int, BeltSignal>[64];
|
||||||
|
_signalBeltsCapacity = 64;
|
||||||
|
_portalFrom = [];
|
||||||
|
_portalTo = [];
|
||||||
|
|
||||||
|
var factories = GameMain.data?.factories;
|
||||||
|
if (factories == null) return;
|
||||||
|
foreach (var factory in factories)
|
||||||
|
{
|
||||||
|
var entitySignPool = factory?.entitySignPool;
|
||||||
|
if (entitySignPool == null) continue;
|
||||||
|
var cargoTraffic = factory.cargoTraffic;
|
||||||
|
var beltPool = cargoTraffic.beltPool;
|
||||||
|
for (var i = cargoTraffic.beltCursor - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (beltPool[i].id != i) continue;
|
||||||
|
ref var signal = ref entitySignPool[beltPool[i].entityId];
|
||||||
|
var signalId = signal.iconId0;
|
||||||
|
if (signalId == 0U) continue;
|
||||||
|
var number = Mathf.RoundToInt(signal.count0);
|
||||||
|
switch (signalId)
|
||||||
|
{
|
||||||
|
case 404:
|
||||||
|
SetSignalBelt(factory.index, i, (int)signalId, 0);
|
||||||
|
continue;
|
||||||
|
case 600:
|
||||||
|
case >= 1000 and < 20000:
|
||||||
|
if (number > 0)
|
||||||
|
SetSignalBelt(factory.index, i, (int)signalId, number);
|
||||||
|
continue;
|
||||||
|
case >= 601 and <= 609:
|
||||||
|
if (number > 0)
|
||||||
|
SetSignalBeltPortalTo(factory.index, i, number);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<int, BeltSignal> GetOrCreateSignalBelts(int index)
|
||||||
|
{
|
||||||
|
Dictionary<int, BeltSignal> obj;
|
||||||
|
if (index < 0) return null;
|
||||||
|
if (index >= _signalBeltsCapacity)
|
||||||
|
{
|
||||||
|
var newCapacity = _signalBeltsCapacity * 2;
|
||||||
|
var newSignalBelts = new Dictionary<int, BeltSignal>[newCapacity];
|
||||||
|
Array.Copy(_signalBelts, newSignalBelts, _signalBeltsCapacity);
|
||||||
|
_signalBelts = newSignalBelts;
|
||||||
|
_signalBeltsCapacity = newCapacity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obj = _signalBelts[index];
|
||||||
|
if (obj != null) return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = [];
|
||||||
|
_signalBelts[index] = obj;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<int, BeltSignal> GetSignalBelts(int index)
|
||||||
|
{
|
||||||
|
return index >= 0 && index < _signalBeltsCapacity ? _signalBelts[index] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetSignalBelt(int factory, int beltId, int signalId, int number)
|
||||||
|
{
|
||||||
|
int stack;
|
||||||
|
int inc;
|
||||||
|
int speedLimit;
|
||||||
|
if (signalId >= 1000)
|
||||||
|
{
|
||||||
|
if (!FactoryPatch.BeltSignalNumberAltFormat.Value)
|
||||||
|
{
|
||||||
|
stack = Mathf.Clamp(number % 10, 1, 4);
|
||||||
|
inc = number / 10 % 10 * stack;
|
||||||
|
speedLimit = number / 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack = Mathf.Clamp(number / 10000 % 10, 1, 4);
|
||||||
|
inc = number / 100000 % 10 * stack;
|
||||||
|
speedLimit = number % 10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack = 0;
|
||||||
|
inc = 0;
|
||||||
|
speedLimit = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedLimit > 3600) speedLimit = 3600;
|
||||||
|
|
||||||
|
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;
|
||||||
|
oldBeltSignal.SignalId = signalId;
|
||||||
|
oldBeltSignal.Sources = null;
|
||||||
|
oldBeltSignal.SourceProgress = null;
|
||||||
|
AddSourcesToBeltSignal(oldBeltSignal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var beltSignal = new BeltSignal
|
||||||
|
{
|
||||||
|
SignalId = signalId,
|
||||||
|
SpeedLimit = speedLimit,
|
||||||
|
Stack = (byte)stack,
|
||||||
|
Inc = (byte)inc
|
||||||
|
};
|
||||||
|
AddSourcesToBeltSignal(beltSignal);
|
||||||
|
signalBelts[beltId] = beltSignal;
|
||||||
|
}
|
||||||
|
|
||||||
|
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>();
|
||||||
|
var sprayedCount = 0f;
|
||||||
|
CalculateAllProductions(result, extra, ref sprayedCount, itemId);
|
||||||
|
|
||||||
|
var proliferatorCount = 0f;
|
||||||
|
if (result.TryGetValue(ItemIds.ProliferatorMkIII, out var pv))
|
||||||
|
{
|
||||||
|
proliferatorCount = pv;
|
||||||
|
result.Remove(ItemIds.ProliferatorMkIII);
|
||||||
|
}
|
||||||
|
if (FactoryPatch.BeltSignalUseProliferatorEnabled.Value)
|
||||||
|
{
|
||||||
|
if (beltSignal.Inc / beltSignal.Stack >= 4)
|
||||||
|
{
|
||||||
|
sprayedCount += 1f;
|
||||||
|
}
|
||||||
|
if (sprayedCount > 0)
|
||||||
|
{
|
||||||
|
proliferatorCount += sprayedCount / ProliferatorSpayCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (proliferatorCount > 0f)
|
||||||
|
{
|
||||||
|
foreach (var p in ItemIds.ProliferatorSources)
|
||||||
|
{
|
||||||
|
result[p.Item1] = (result.TryGetValue(p.Item1, out var v) ? v : 0) + p.Item2 * proliferatorCount / ProliferatorDenom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Remove(itemId);
|
||||||
|
|
||||||
|
var cnt = result.Count + extra.Count;
|
||||||
|
if (cnt == 0)
|
||||||
|
{
|
||||||
|
beltSignal.Sources = null;
|
||||||
|
beltSignal.SourceProgress = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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] = (p.Key, p.Value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
beltSignal.Sources = items;
|
||||||
|
beltSignal.SourceProgress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetSignalBeltPortalTo(int factory, int beltId, int number)
|
||||||
|
{
|
||||||
|
var v = ((long)factory << 32) | (uint)beltId;
|
||||||
|
_portalFrom[v] = number;
|
||||||
|
if (!_portalTo.TryGetValue(number, out var set))
|
||||||
|
{
|
||||||
|
set = [];
|
||||||
|
_portalTo[number] = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
set.Add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveSignalBelt(int factory, int beltId)
|
||||||
|
{
|
||||||
|
GetSignalBelts(factory)?.Remove(beltId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemovePlanetSignalBelts(int factory)
|
||||||
|
{
|
||||||
|
GetSignalBelts(factory)?.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveSignalBeltPortalEnd(int factory, int beltId)
|
||||||
|
{
|
||||||
|
var v = ((long)factory << 32) | (uint)beltId;
|
||||||
|
if (!_portalFrom.TryGetValue(v, out var number)) return;
|
||||||
|
_portalFrom.Remove(v);
|
||||||
|
if (!_portalTo.TryGetValue(number, out var set)) return;
|
||||||
|
set.Remove(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnGameBegin()
|
||||||
|
{
|
||||||
|
if (DSPGame.IsMenuDemo) return;
|
||||||
|
if (FactoryPatch.BeltSignalGeneratorEnabled.Value) InitSignalBelts();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(DigitalSystem), MethodType.Constructor, typeof(PlanetData))]
|
||||||
|
private static void DigitalSystem_Constructor_Postfix(PlanetData _planet)
|
||||||
|
{
|
||||||
|
if (!FactoryPatch.BeltSignalGeneratorEnabled.Value) return;
|
||||||
|
var player = GameMain.mainPlayer;
|
||||||
|
if (player == null) return;
|
||||||
|
var factory = _planet?.factory;
|
||||||
|
if (factory == null) return;
|
||||||
|
RemovePlanetSignalBelts(factory.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RemoveBeltComponent))]
|
||||||
|
public static void CargoTraffic_RemoveBeltComponent_Prefix(int id)
|
||||||
|
{
|
||||||
|
if (!_initialized) return;
|
||||||
|
var planet = GameMain.localPlanet;
|
||||||
|
if (planet == null) return;
|
||||||
|
RemoveSignalBeltPortalEnd(planet.factoryIndex, id);
|
||||||
|
RemoveSignalBelt(planet.factoryIndex, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.SetBeltSignalIcon))]
|
||||||
|
public static void CargoTraffic_SetBeltSignalIcon_Postfix(CargoTraffic __instance, int signalId, int entityId)
|
||||||
|
{
|
||||||
|
if (!_initialized) return;
|
||||||
|
var planet = GameMain.localPlanet;
|
||||||
|
if (planet == null) return;
|
||||||
|
var factory = __instance.factory;
|
||||||
|
int number;
|
||||||
|
var needAdd = false;
|
||||||
|
switch (signalId)
|
||||||
|
{
|
||||||
|
case 404:
|
||||||
|
number = 0;
|
||||||
|
needAdd = true;
|
||||||
|
break;
|
||||||
|
case 600:
|
||||||
|
case >= 1000 and < 20000:
|
||||||
|
number = Mathf.RoundToInt(factory.entitySignPool[entityId].count0);
|
||||||
|
if (number > 0)
|
||||||
|
needAdd = true;
|
||||||
|
break;
|
||||||
|
case >= 601 and <= 609:
|
||||||
|
number = Mathf.RoundToInt(factory.entitySignPool[entityId].count0);
|
||||||
|
var factoryIndex = planet.factoryIndex;
|
||||||
|
var beltId = factory.entityPool[entityId].beltId;
|
||||||
|
if (number > 0)
|
||||||
|
SetSignalBeltPortalTo(factoryIndex, beltId, number);
|
||||||
|
RemoveSignalBelt(factoryIndex, beltId);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
number = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var factoryIndex = planet.factoryIndex;
|
||||||
|
var beltId = factory.entityPool[entityId].beltId;
|
||||||
|
if (needAdd)
|
||||||
|
{
|
||||||
|
SetSignalBelt(factoryIndex, beltId, signalId, number);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemoveSignalBelt(factoryIndex, beltId);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveSignalBeltPortalEnd(factoryIndex, beltId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.SetBeltSignalNumber))]
|
||||||
|
public static void CargoTraffic_SetBeltSignalNumber_Postfix(CargoTraffic __instance, float number, int entityId)
|
||||||
|
{
|
||||||
|
if (!_initialized) return;
|
||||||
|
var planet = GameMain.localPlanet;
|
||||||
|
if (planet == null) return;
|
||||||
|
var factory = __instance.factory;
|
||||||
|
var entitySignPool = factory.entitySignPool;
|
||||||
|
uint signalId;
|
||||||
|
if (entitySignPool[entityId].iconType == 0U || (signalId = entitySignPool[entityId].iconId0) == 0U) return;
|
||||||
|
switch (signalId)
|
||||||
|
{
|
||||||
|
case 404:
|
||||||
|
return;
|
||||||
|
case 600:
|
||||||
|
case >= 1000 and < 20000:
|
||||||
|
break;
|
||||||
|
case >= 601 and <= 609:
|
||||||
|
var factoryIndex = planet.factoryIndex;
|
||||||
|
var beltId = factory.entityPool[entityId].beltId;
|
||||||
|
RemoveSignalBeltPortalEnd(factoryIndex, beltId);
|
||||||
|
SetSignalBeltPortalTo(factoryIndex, beltId, Mathf.RoundToInt(number));
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var factoryIndex = planet.factoryIndex;
|
||||||
|
var beltId = factory.entityPool[entityId].beltId;
|
||||||
|
var n = Mathf.RoundToInt(number);
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
RemoveSignalBelt(factoryIndex, beltId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetSignalBelt(factoryIndex, beltId, (int)signalId, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ProcessBeltSignals()
|
||||||
|
{
|
||||||
|
if (!_initialized) return;
|
||||||
|
var data = GameMain.data;
|
||||||
|
var factories = data?.factories;
|
||||||
|
if (factories == null) return;
|
||||||
|
DeepProfiler.BeginSample(DPEntry.Belt);
|
||||||
|
for (var index = data.factoryCount - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
var factory = factories[index];
|
||||||
|
if (factory == null) continue;
|
||||||
|
var belts = GetSignalBelts(index);
|
||||||
|
if (belts == null || belts.Count == 0) continue;
|
||||||
|
var factoryProductionStat = GameMain.statistics.production.factoryStatPool[index];
|
||||||
|
var productRegister = factoryProductionStat.productRegister;
|
||||||
|
var consumeRegister = factoryProductionStat.consumeRegister;
|
||||||
|
var countRecipe = FactoryPatch.BeltSignalCountRecipeEnabled.Value;
|
||||||
|
var cargoTraffic = factory.cargoTraffic;
|
||||||
|
var beltCount = cargoTraffic.beltCursor;
|
||||||
|
List<int> beltsToRemove = null;
|
||||||
|
foreach (var pair in belts)
|
||||||
|
{
|
||||||
|
if (pair.Key >= beltCount)
|
||||||
|
{
|
||||||
|
if (beltsToRemove == null)
|
||||||
|
beltsToRemove = [pair.Key];
|
||||||
|
else
|
||||||
|
beltsToRemove.Add(pair.Key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var beltSignal = pair.Value;
|
||||||
|
var signalId = beltSignal.SignalId;
|
||||||
|
switch (signalId)
|
||||||
|
{
|
||||||
|
case 404:
|
||||||
|
{
|
||||||
|
var beltId = pair.Key;
|
||||||
|
ref var belt = ref cargoTraffic.beltPool[beltId];
|
||||||
|
var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId);
|
||||||
|
if (cargoPath == null) continue;
|
||||||
|
int itemId;
|
||||||
|
if ((itemId = cargoPath.TryPickItem(belt.segIndex + belt.segPivotOffset - 5, 12, out var stack, out _)) > 0)
|
||||||
|
{
|
||||||
|
if (FactoryPatch.BeltSignalCountRemEnabled.Value) consumeRegister[itemId] += stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case 600:
|
||||||
|
{
|
||||||
|
if (!_portalTo.TryGetValue(beltSignal.SpeedLimit, out var set)) continue;
|
||||||
|
var beltId = pair.Key;
|
||||||
|
ref var belt = ref cargoTraffic.beltPool[beltId];
|
||||||
|
var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId);
|
||||||
|
if (cargoPath == null) continue;
|
||||||
|
var segIndex = belt.segIndex + belt.segPivotOffset;
|
||||||
|
if (!cargoPath.GetCargoAtIndex(segIndex, out var cargo, out var cargoId, out var _)) break;
|
||||||
|
var itemId = cargo.item;
|
||||||
|
var cargoPool = cargoPath.cargoContainer.cargoPool;
|
||||||
|
var inc = cargoPool[cargoId].inc;
|
||||||
|
var stack = cargoPool[cargoId].stack;
|
||||||
|
foreach (var n in set)
|
||||||
|
{
|
||||||
|
var cargoTraffic1 = factories[(int)(n >> 32)].cargoTraffic;
|
||||||
|
ref var belt1 = ref cargoTraffic1.beltPool[(int)(n & 0x7FFFFFFF)];
|
||||||
|
cargoPath = cargoTraffic1.GetCargoPath(belt1.segPathId);
|
||||||
|
if (cargoPath == null) continue;
|
||||||
|
if (!cargoPath.TryInsertItem(belt1.segIndex + belt1.segPivotOffset, itemId, stack, inc)) continue;
|
||||||
|
cargoPath.TryPickItem(segIndex - 5, 12, out var stack1, out var inc1);
|
||||||
|
if (inc1 != inc || stack1 != stack)
|
||||||
|
cargoPath.TryPickItem(segIndex - 5, 12, out _, out _);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case >= 1000 and < 20000:
|
||||||
|
{
|
||||||
|
var hasSpeedLimit = beltSignal.SpeedLimit > 0;
|
||||||
|
if (hasSpeedLimit)
|
||||||
|
{
|
||||||
|
beltSignal.Progress += beltSignal.SpeedLimit;
|
||||||
|
switch (beltSignal.Progress)
|
||||||
|
{
|
||||||
|
case < 3600:
|
||||||
|
continue;
|
||||||
|
case > 18000:
|
||||||
|
beltSignal.Progress = 14400;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var beltId = pair.Key;
|
||||||
|
ref var belt = ref cargoTraffic.beltPool[beltId];
|
||||||
|
var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId);
|
||||||
|
if (cargoPath == null) continue;
|
||||||
|
var stack = beltSignal.Stack;
|
||||||
|
var inc = beltSignal.Inc;
|
||||||
|
if (!cargoPath.TryInsertItem(belt.segIndex + belt.segPivotOffset, signalId, stack, inc)) continue;
|
||||||
|
if (hasSpeedLimit) beltSignal.Progress -= 3600;
|
||||||
|
if (FactoryPatch.BeltSignalCountGenEnabled.Value) productRegister[signalId] += stack;
|
||||||
|
if (!countRecipe) continue;
|
||||||
|
var sources = beltSignal.Sources;
|
||||||
|
if (sources == null) continue;
|
||||||
|
var progress = beltSignal.SourceProgress;
|
||||||
|
var stackf = (float)stack;
|
||||||
|
for (var i = sources.Length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var newCnt = progress[i] + sources[i].itemCount * stackf;
|
||||||
|
if (newCnt > 0)
|
||||||
|
{
|
||||||
|
var itemId = sources[i].itemId;
|
||||||
|
var cnt = Mathf.CeilToInt(newCnt);
|
||||||
|
productRegister[itemId] += cnt;
|
||||||
|
if (!sources[i].isExtra) consumeRegister[itemId] += cnt;
|
||||||
|
progress[i] = newCnt - cnt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progress[i] = newCnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (beltsToRemove == null) continue;
|
||||||
|
foreach (var beltId in beltsToRemove)
|
||||||
|
{
|
||||||
|
belts.Remove(beltId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeepProfiler.EndSample(DPEntry.Belt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.OnFactoryFrameBegin))]
|
||||||
|
public static void GameLogic_OnFactoryFrameBegin_Postfix()
|
||||||
|
{
|
||||||
|
ProcessBeltSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BEGIN: Item sources calculation */
|
||||||
|
// Item ID constants are provided by UXAssist.Common.GameConstants.ItemIds.
|
||||||
|
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;
|
||||||
|
|
||||||
|
private class ItemSource
|
||||||
|
{
|
||||||
|
public float Count;
|
||||||
|
public Dictionary<int, float> From;
|
||||||
|
public Dictionary<int, float> Extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InitItemSources()
|
||||||
|
{
|
||||||
|
if (_itemSourcesInitialized) return;
|
||||||
|
foreach (var vein in LDB.veins.dataArray)
|
||||||
|
{
|
||||||
|
ItemSources[vein.MiningItem] = new ItemSource { Count = 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var ip in LDB.items.dataArray)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(ip.MiningFrom))
|
||||||
|
{
|
||||||
|
ItemSources[ip.ID] = new ItemSource { Count = 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Water, sulfuric acid, hydrogen, deuterium, photons
|
||||||
|
foreach (var itemId in ItemIds.ExtraOreItemIds)
|
||||||
|
{
|
||||||
|
ItemSources[itemId] = new ItemSource { Count = 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
var recipes = LDB.recipes.dataArray;
|
||||||
|
foreach (var recipe in recipes)
|
||||||
|
{
|
||||||
|
if (!recipe.Explicit || recipe.ID == 58 || recipe.ID == 121) continue;
|
||||||
|
var res = recipe.Results;
|
||||||
|
var rescnt = recipe.ResultCounts;
|
||||||
|
var len = res.Length;
|
||||||
|
for (var i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (ItemSources.ContainsKey(res[i])) continue;
|
||||||
|
var rs = new ItemSource { Count = rescnt[i], From = [] };
|
||||||
|
var it = recipe.Items;
|
||||||
|
var itcnt = recipe.ItemCounts;
|
||||||
|
var len2 = it.Length;
|
||||||
|
for (var j = 0; j < len2; j++)
|
||||||
|
{
|
||||||
|
rs.From[it[j]] = itcnt[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 1)
|
||||||
|
{
|
||||||
|
rs.Extra = [];
|
||||||
|
for (var k = 0; k < len; k++)
|
||||||
|
{
|
||||||
|
if (i != k)
|
||||||
|
{
|
||||||
|
rs.Extra[res[k]] = rescnt[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemSources[res[i]] = rs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var recipe in recipes)
|
||||||
|
{
|
||||||
|
if (recipe.Explicit) continue;
|
||||||
|
var res = recipe.Results;
|
||||||
|
var rescnt = recipe.ResultCounts;
|
||||||
|
var len = res.Length;
|
||||||
|
for (var i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (ItemSources.ContainsKey(res[i])) continue;
|
||||||
|
var rs = new ItemSource { Count = rescnt[i], From = [], Extra = null };
|
||||||
|
var it = recipe.Items;
|
||||||
|
var itcnt = recipe.ItemCounts;
|
||||||
|
var len2 = it.Length;
|
||||||
|
for (var j = 0; j < len2; j++)
|
||||||
|
{
|
||||||
|
rs.From[it[j]] = itcnt[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 1)
|
||||||
|
{
|
||||||
|
rs.Extra = [];
|
||||||
|
for (var k = 0; k < len; k++)
|
||||||
|
{
|
||||||
|
if (i != k)
|
||||||
|
{
|
||||||
|
rs.Extra[res[k]] = rescnt[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemSources[res[i]] = rs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_itemSourcesInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var times = 1f;
|
||||||
|
if (Math.Abs(count - itemSource.Count) > 0.000001f)
|
||||||
|
{
|
||||||
|
times = count / itemSource.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[itemId] = (result.TryGetValue(itemId, out var oldCount) ? oldCount : 0) + count;
|
||||||
|
if (itemSource.Extra != null)
|
||||||
|
{
|
||||||
|
foreach (var p in itemSource.Extra)
|
||||||
|
{
|
||||||
|
extra[p.Key] = (extra.TryGetValue(p.Key, out oldCount) ? oldCount : 0) + times * p.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemId == ItemIds.ProliferatorMkIII || itemSource.From == null) return;
|
||||||
|
var useProliferator = FactoryPatch.BeltSignalUseProliferatorEnabled.Value;
|
||||||
|
if (useProliferator && ItemIds.ExtraProliferationItemIds.Contains(itemId))
|
||||||
|
{
|
||||||
|
times *= 0.8f;
|
||||||
|
}
|
||||||
|
foreach (var p in itemSource.From)
|
||||||
|
{
|
||||||
|
var value = p.Value * times;
|
||||||
|
if (useProliferator && !ItemIds.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 */
|
||||||
|
}
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using BepInEx.Configuration;
|
||||||
|
using CommonAPI.Systems;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Patches.Factory;
|
||||||
|
|
||||||
|
[ModFeature("CheatFactory", Order = 10)]
|
||||||
|
public class FactoryPatch : PatchImpl<FactoryPatch>
|
||||||
|
{
|
||||||
|
public static ConfigEntry<bool> ImmediateEnabled;
|
||||||
|
public static ConfigEntry<bool> ArchitectModeEnabled;
|
||||||
|
public static ConfigEntry<bool> NoConditionEnabled;
|
||||||
|
public static ConfigEntry<bool> NoCollisionEnabled;
|
||||||
|
public static ConfigEntry<bool> BeltSignalGeneratorEnabled;
|
||||||
|
public static ConfigEntry<bool> BeltSignalNumberAltFormat;
|
||||||
|
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> ControlPanelRemoteLogisticsEnabled;
|
||||||
|
|
||||||
|
private static PressKeyBind _noConditionKey;
|
||||||
|
private static PressKeyBind _noCollisionKey;
|
||||||
|
internal static HashSet<int> BeltIds;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
_noConditionKey = KeyBindings.RegisterKeyBinding(new BuiltinKey
|
||||||
|
{
|
||||||
|
key = new CombineKey(0, 0, ECombineKeyAction.OnceClick, true),
|
||||||
|
conflictGroup = KeyBindConflict.MOVEMENT | KeyBindConflict.FLYING | KeyBindConflict.SAILING | KeyBindConflict.BUILD_MODE_1 | KeyBindConflict.KEYBOARD_KEYBIND,
|
||||||
|
name = "ToggleNoCondition",
|
||||||
|
canOverride = true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
_noCollisionKey = KeyBindings.RegisterKeyBinding(new BuiltinKey
|
||||||
|
{
|
||||||
|
key = new CombineKey(0, 0, ECombineKeyAction.OnceClick, true),
|
||||||
|
conflictGroup = KeyBindConflict.MOVEMENT | KeyBindConflict.FLYING | KeyBindConflict.SAILING | KeyBindConflict.BUILD_MODE_1 | KeyBindConflict.KEYBOARD_KEYBIND,
|
||||||
|
name = "ToggleNoCollision",
|
||||||
|
canOverride = true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
ImmediateEnabled.SettingChanged += (_, _) => ImmediateBuild.Enable(ImmediateEnabled.Value);
|
||||||
|
ArchitectModeEnabled.SettingChanged += (_, _) => ArchitectMode.Enable(ArchitectModeEnabled.Value);
|
||||||
|
NoConditionEnabled.SettingChanged += (_, _) => NoConditionBuild.Enable(NoConditionEnabled.Value);
|
||||||
|
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);
|
||||||
|
ControlPanelRemoteLogisticsEnabled.SettingChanged += (_, _) => ControlPanelRemoteLogistics.Enable(ControlPanelRemoteLogisticsEnabled.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Start()
|
||||||
|
{
|
||||||
|
ImmediateBuild.Enable(ImmediateEnabled.Value);
|
||||||
|
ArchitectMode.Enable(ArchitectModeEnabled.Value);
|
||||||
|
NoConditionBuild.Enable(NoConditionEnabled.Value);
|
||||||
|
NoCollisionValueChanged();
|
||||||
|
BeltSignalGenerator.Enable(BeltSignalGeneratorEnabled.Value);
|
||||||
|
RemovePowerSpaceLimit.Enable(RemovePowerSpaceLimitEnabled.Value);
|
||||||
|
BoostWindPower.Enable(BoostWindPowerEnabled.Value);
|
||||||
|
BoostSolarPower.Enable(BoostSolarPowerEnabled.Value);
|
||||||
|
BoostFuelPower.Enable(BoostFuelPowerEnabled.Value);
|
||||||
|
BoostGeothermalPower.Enable(BoostGeothermalPowerEnabled.Value);
|
||||||
|
WindTurbinesPowerGlobalCoverage.Enable(WindTurbinesPowerGlobalCoverageEnabled.Value);
|
||||||
|
ControlPanelRemoteLogistics.Enable(ControlPanelRemoteLogisticsEnabled.Value);
|
||||||
|
Enable(true);
|
||||||
|
CargoTrafficPatch.Enable(true);
|
||||||
|
GameLogicProc.OnGameBegin += OnGameBegin_For_ImmBuild;
|
||||||
|
GameLogicProc.OnDataLoaded += OnDataLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Uninit()
|
||||||
|
{
|
||||||
|
GameLogicProc.OnDataLoaded -= OnDataLoaded;
|
||||||
|
GameLogicProc.OnGameBegin -= OnGameBegin_For_ImmBuild;
|
||||||
|
CargoTrafficPatch.Enable(false);
|
||||||
|
Enable(false);
|
||||||
|
ImmediateBuild.Enable(false);
|
||||||
|
ArchitectMode.Enable(false);
|
||||||
|
NoConditionBuild.Enable(false);
|
||||||
|
BeltSignalGenerator.Enable(false);
|
||||||
|
RemovePowerSpaceLimit.Enable(false);
|
||||||
|
BoostWindPower.Enable(false);
|
||||||
|
BoostSolarPower.Enable(false);
|
||||||
|
BoostFuelPower.Enable(false);
|
||||||
|
BoostGeothermalPower.Enable(false);
|
||||||
|
WindTurbinesPowerGlobalCoverage.Enable(false);
|
||||||
|
ControlPanelRemoteLogistics.Enable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnDataLoaded()
|
||||||
|
{
|
||||||
|
WindTurbinesPowerGlobalCoverage.Enable(WindTurbinesPowerGlobalCoverageEnabled.Value);
|
||||||
|
BeltIds ??= [.. LDB.items.dataArray.Where(i => i.prefabDesc.isBelt).Select(i => i.ID)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnInputUpdate()
|
||||||
|
{
|
||||||
|
if (_noConditionKey.keyValue)
|
||||||
|
{
|
||||||
|
NoConditionEnabled.Value = !NoConditionEnabled.Value;
|
||||||
|
if (!DSPGame.IsMenuDemo && GameMain.isRunning)
|
||||||
|
{
|
||||||
|
UIRoot.instance.uiGame.generalTips.InvokeRealtimeTipAhead((NoConditionEnabled.Value ? Localization.NoConditionOn : Localization.NoConditionOff).Translate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_noCollisionKey.keyValue)
|
||||||
|
{
|
||||||
|
NoCollisionEnabled.Value = !NoCollisionEnabled.Value;
|
||||||
|
if (!DSPGame.IsMenuDemo && GameMain.isRunning)
|
||||||
|
{
|
||||||
|
UIRoot.instance.uiGame.generalTips.InvokeRealtimeTipAhead((NoCollisionEnabled.Value ? Localization.NoCollisionOn : Localization.NoCollisionOff).Translate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void NoCollisionValueChanged()
|
||||||
|
{
|
||||||
|
var coll = ColliderPool.instance;
|
||||||
|
if (coll == null) return;
|
||||||
|
var obj = coll.gameObject;
|
||||||
|
if (obj == null) return;
|
||||||
|
obj.gameObject.SetActive(!NoCollisionEnabled.Value);
|
||||||
|
GameMain.data?.warningSystem?.UpdateCriticalWarningText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ArrivePlanet(PlanetFactory factory)
|
||||||
|
{
|
||||||
|
if (factory.prebuildCount <= 0) return;
|
||||||
|
var imm = ImmediateEnabled.Value;
|
||||||
|
var architect = ArchitectModeEnabled.Value;
|
||||||
|
if ((!imm && !architect) || GameMain.gameScenario == null) return;
|
||||||
|
var prebuilds = factory.prebuildPool;
|
||||||
|
if (imm)
|
||||||
|
{
|
||||||
|
var player = GameMain.mainPlayer;
|
||||||
|
for (var i = factory.prebuildCursor - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
ref var pb = ref prebuilds[i];
|
||||||
|
if (pb.id != i || pb.isDestroyed) continue;
|
||||||
|
if (pb.itemRequired > 0)
|
||||||
|
{
|
||||||
|
if (!architect) continue;
|
||||||
|
pb.itemRequired = 0;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(PlanetData), nameof(PlanetData.NotifyFactoryLoaded))]
|
||||||
|
private static void PlanetData_NotifyFactoryLoaded_Postfix(PlanetData __instance)
|
||||||
|
{
|
||||||
|
var main = GameMain.instance;
|
||||||
|
if (main != null && main._running && __instance.factory?.planet?.data != null)
|
||||||
|
{
|
||||||
|
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(__instance.factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnGameBegin_For_ImmBuild()
|
||||||
|
{
|
||||||
|
if (DSPGame.IsMenuDemo) return;
|
||||||
|
var factory = GameMain.mainPlayer?.factory;
|
||||||
|
if (factory?.planet?.data != null)
|
||||||
|
{
|
||||||
|
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||||
|
}
|
||||||
|
GameMain.data?.warningSystem?.UpdateCriticalWarningText();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: WarningSystem_hasCriticalWarning_Transpiler
|
||||||
|
// Target: WarningSystem.hasCriticalWarning (getter)
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(WarningSystem), nameof(WarningSystem.hasCriticalWarning), MethodType.Getter)]
|
||||||
|
private static IEnumerable<CodeInstruction> WarningSystem_hasCriticalWarning_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
var label1 = generator.DefineLabel();
|
||||||
|
var label2 = generator.DefineLabel();
|
||||||
|
matcher.End().MatchBack(false,
|
||||||
|
new CodeMatch(OpCodes.Ret)
|
||||||
|
).RemoveInstructions(1);
|
||||||
|
matcher.InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Brfalse, label1),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I4_1),
|
||||||
|
new CodeInstruction(OpCodes.Ret),
|
||||||
|
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(FactoryPatch), nameof(NoConditionEnabled))).WithLabels(label1),
|
||||||
|
new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(ConfigEntry<bool>), nameof(ConfigEntry<bool>.Value))),
|
||||||
|
new CodeInstruction(OpCodes.Brfalse, label2),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I4_1),
|
||||||
|
new CodeInstruction(OpCodes.Ret),
|
||||||
|
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(FactoryPatch), nameof(NoCollisionEnabled))).WithLabels(label2),
|
||||||
|
new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(ConfigEntry<bool>), nameof(ConfigEntry<bool>.Value))),
|
||||||
|
new CodeInstruction(OpCodes.Ret)
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: WarningSystem_UpdateCriticalWarningText_Transpiler
|
||||||
|
// Target: WarningSystem.UpdateCriticalWarningText
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(WarningSystem), nameof(WarningSystem.UpdateCriticalWarningText))]
|
||||||
|
private static IEnumerable<CodeInstruction> WarningSystem_UpdateCriticalWarningText_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Ldstr, ""),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.PropertySetter(typeof(WarningSystem), nameof(WarningSystem.criticalWarningTexts)))
|
||||||
|
);
|
||||||
|
matcher.Repeat(m =>
|
||||||
|
{
|
||||||
|
var label1 = generator.DefineLabel();
|
||||||
|
m.Advance(3).InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
Transpilers.EmitDelegate((WarningSystem w) =>
|
||||||
|
{
|
||||||
|
if (NoConditionEnabled.Value)
|
||||||
|
{
|
||||||
|
w.criticalWarningTexts = Localization.BuildWithoutConditionIsEnabled.Translate() + "\r\n";
|
||||||
|
}
|
||||||
|
else if (NoCollisionEnabled.Value)
|
||||||
|
{
|
||||||
|
w.criticalWarningTexts = Localization.NoCollisionIsEnabled.Translate() + "\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (m.Opcode == OpCodes.Ret)
|
||||||
|
{
|
||||||
|
m.InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(WarningSystem), nameof(WarningSystem.onCriticalWarningTextChanged))),
|
||||||
|
new CodeInstruction(OpCodes.Brfalse_S, label1),
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(WarningSystem), nameof(WarningSystem.onCriticalWarningTextChanged))),
|
||||||
|
new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(Action), nameof(Action.Invoke)))
|
||||||
|
);
|
||||||
|
m.Labels.Add(label1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Patches.Factory;
|
||||||
|
|
||||||
|
internal 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();
|
||||||
|
_isBatchBuilding = false;
|
||||||
|
var cargoTraffic = factory.cargoTraffic;
|
||||||
|
var entityPool = factory.entityPool;
|
||||||
|
var colChunks = factory.planet.physics?.colChunks;
|
||||||
|
foreach (var beltId in _alterBeltRendererIds)
|
||||||
|
{
|
||||||
|
cargoTraffic.AlterBeltRenderer(beltId, entityPool, colChunks, false);
|
||||||
|
}
|
||||||
|
foreach (var pathId in _alterPathRendererIds)
|
||||||
|
{
|
||||||
|
cargoTraffic.AlterPathRenderer(pathId, false);
|
||||||
|
}
|
||||||
|
foreach (var pathId in _refreshPathUVIds)
|
||||||
|
{
|
||||||
|
cargoTraffic.RefreshPathUV(pathId);
|
||||||
|
}
|
||||||
|
_alterBeltRendererIds.Clear();
|
||||||
|
_alterPathRendererIds.Clear();
|
||||||
|
_refreshPathUVIds.Clear();
|
||||||
|
_disableRefreshBatchesBuffers = false;
|
||||||
|
if (_anyBelt)
|
||||||
|
{
|
||||||
|
factory.cargoTraffic.RefreshBeltBatchesBuffers();
|
||||||
|
factory.cargoTraffic.RefreshPathBatchesBuffers();
|
||||||
|
}
|
||||||
|
_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 || (FactoryPatch.BeltIds?.Contains(factory.prebuildPool[id].protoId) ?? false);
|
||||||
|
factory.BuildFinally(player, id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPriority(Priority.First)]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.AlterBeltRenderer))]
|
||||||
|
private static bool CargoTraffic_AlterBeltRenderer_Prefix(int beltId)
|
||||||
|
{
|
||||||
|
if (!_isBatchBuilding) return true;
|
||||||
|
_alterBeltRendererIds.Add(beltId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPriority(Priority.First)]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.AlterPathRenderer))]
|
||||||
|
private static bool CargoTraffic_AlterPathRenderer_Prefix(int pathId)
|
||||||
|
{
|
||||||
|
if (!_isBatchBuilding) return true;
|
||||||
|
_alterPathRendererIds.Add(pathId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPriority(Priority.First)]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RefreshPathUV))]
|
||||||
|
private static bool CargoTraffic_RefreshPathUV_Prefix(int pathId)
|
||||||
|
{
|
||||||
|
if (!_isBatchBuilding) return true;
|
||||||
|
_refreshPathUVIds.Add(pathId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPriority(Priority.First)]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RefreshBeltBatchesBuffers))]
|
||||||
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RefreshPathBatchesBuffers))]
|
||||||
|
private static bool CargoTraffic_RefreshBeltBatchesBuffers_Prefix()
|
||||||
|
{
|
||||||
|
return !_disableRefreshBatchesBuffers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ImmediateBuild : PatchImpl<ImmediateBuild>
|
||||||
|
{
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
var factory = GameMain.mainPlayer?.factory;
|
||||||
|
if (factory?.planet?.data != null)
|
||||||
|
{
|
||||||
|
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Harmony transpiler: Transpiler
|
||||||
|
// Target: BuildTool_Addon.CreatePrebuilds, BuildTool_BlueprintPaste.CreatePrebuilds, BuildTool_Click.CreatePrebuilds, BuildTool_Inserter.CreatePrebuilds, BuildTool_Path.CreatePrebuilds
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CreatePrebuilds))]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CreatePrebuilds))]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CreatePrebuilds))]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CreatePrebuilds))]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CreatePrebuilds))]
|
||||||
|
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
matcher.End().MatchBack(false,
|
||||||
|
new CodeMatch(OpCodes.Ret)
|
||||||
|
);
|
||||||
|
if (matcher.IsInvalid)
|
||||||
|
{
|
||||||
|
CheatEnabler.Logger.LogWarning($"Failed to patch CreatePrebuilds");
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher.Advance(-1);
|
||||||
|
if (matcher.Opcode != OpCodes.Nop && (matcher.Opcode != OpCodes.Call || !matcher.Instruction.OperandIs(AccessTools.Method(typeof(System.GC), nameof(System.GC.Collect)))))
|
||||||
|
{
|
||||||
|
CheatEnabler.Logger.LogWarning($"Failed to patch CreatePrebuilds: last instruction is not `Nop` or `Call GC.Collect()`: {matcher.Instruction}");
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
|
||||||
|
var labels = matcher.Labels;
|
||||||
|
matcher.Labels = [];
|
||||||
|
matcher.Insert(
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||||
|
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(BuildTool), nameof(BuildTool.factory))),
|
||||||
|
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(global::CheatEnabler.Patches.FactoryPatch), nameof(global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet)))
|
||||||
|
);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(UXAssist.Functions.PlanetFunctions), nameof(UXAssist.Functions.PlanetFunctions.BuildOrbitalCollectors))]
|
||||||
|
private static void UXAssist_PlanetFunctions_BuildOrbitalCollectors_Postfix()
|
||||||
|
{
|
||||||
|
var factory = GameMain.mainPlayer?.factory;
|
||||||
|
if (factory?.planet?.data != null)
|
||||||
|
{
|
||||||
|
global::CheatEnabler.Patches.FactoryPatch.ArrivePlanet(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Patches.Factory;
|
||||||
|
|
||||||
|
internal class ControlPanelRemoteLogistics : PatchImpl<ControlPanelRemoteLogistics>
|
||||||
|
{
|
||||||
|
// Harmony transpiler: UIControlPanelDispenserInspector_OnItemIconMouseDown_Transpiler
|
||||||
|
// Target: UIControlPanelDispenserInspector.OnItemIconMouseDown, UIControlPanelDispenserInspector.OnHoldupItemClick, UIControlPanelDispenserInspector.OnCourierIconClick
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelDispenserInspector), nameof(UIControlPanelDispenserInspector.OnItemIconMouseDown))]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelDispenserInspector), nameof(UIControlPanelDispenserInspector.OnHoldupItemClick))]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelDispenserInspector), nameof(UIControlPanelDispenserInspector.OnCourierIconClick))]
|
||||||
|
private static IEnumerable<CodeInstruction> UIControlPanelDispenserInspector_OnItemIconMouseDown_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions);
|
||||||
|
Label? branch = null;
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(UIControlPanelDispenserInspector), nameof(UIControlPanelDispenserInspector.isLocal))),
|
||||||
|
new CodeMatch(ci => ci.Branches(out branch))
|
||||||
|
).Repeat(
|
||||||
|
m =>
|
||||||
|
{
|
||||||
|
if (branch == null)
|
||||||
|
{
|
||||||
|
m.Advance(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var labels = m.Labels;
|
||||||
|
m.RemoveInstructions(3).InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Br, branch.Value).WithLabels(labels)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: UIControlPanelStationInspector_OnShipIconClick_Transpiler
|
||||||
|
// Target: UIControlPanelStationInspector.OnShipIconClick, UIControlPanelStationInspector.OnWarperIconClick, UIControlPanelStationInspector.OnDroneIconClick
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelStationInspector), nameof(UIControlPanelStationInspector.OnShipIconClick))]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelStationInspector), nameof(UIControlPanelStationInspector.OnWarperIconClick))]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelStationInspector), nameof(UIControlPanelStationInspector.OnDroneIconClick))]
|
||||||
|
private static IEnumerable<CodeInstruction> UIControlPanelStationInspector_OnShipIconClick_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions);
|
||||||
|
Label? branch = null;
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(UIControlPanelStationInspector), nameof(UIControlPanelStationInspector.isLocal))),
|
||||||
|
new CodeMatch(ci => ci.Branches(out branch))
|
||||||
|
).Repeat(
|
||||||
|
m =>
|
||||||
|
{
|
||||||
|
if (branch == null)
|
||||||
|
{
|
||||||
|
m.Advance(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var labels = m.Labels;
|
||||||
|
m.RemoveInstructions(3).InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Br, branch.Value).WithLabels(labels)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: UIControlPanelStationStorage_OnItemIconMouseDown_Transpiler
|
||||||
|
// Target: UIControlPanelStationStorage.OnItemIconMouseDown
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.OnItemIconMouseDown))]
|
||||||
|
private static IEnumerable<CodeInstruction> UIControlPanelStationStorage_OnItemIconMouseDown_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions);
|
||||||
|
Label? branch = null;
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.isLocal))),
|
||||||
|
new CodeMatch(ci => ci.Branches(out branch))
|
||||||
|
).Repeat(
|
||||||
|
m =>
|
||||||
|
{
|
||||||
|
if (branch == null)
|
||||||
|
{
|
||||||
|
m.Advance(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var labels = m.Labels;
|
||||||
|
m.RemoveInstructions(3).InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Br, branch.Value).WithLabels(labels)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: UIControlPanelStationStorage_OnTakeBackButtonClick_Transpiler
|
||||||
|
// Target: UIControlPanelStationStorage.OnTakeBackButtonClick
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.OnTakeBackButtonClick))]
|
||||||
|
private static IEnumerable<CodeInstruction> UIControlPanelStationStorage_OnTakeBackButtonClick_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions);
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.isLocal))),
|
||||||
|
new CodeMatch(ci => ci.Branches(out _))
|
||||||
|
).Repeat(
|
||||||
|
m =>
|
||||||
|
{
|
||||||
|
var labels = m.Labels;
|
||||||
|
m.RemoveInstructions(3).Labels.AddRange(labels);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: UIControlPanelVeinCollectorPanel_OnProductIconClick_Transpiler
|
||||||
|
// Target: UIControlPanelVeinCollectorPanel.OnProductIconClick
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelVeinCollectorPanel), nameof(UIControlPanelVeinCollectorPanel.OnProductIconClick))]
|
||||||
|
private static IEnumerable<CodeInstruction> UIControlPanelVeinCollectorPanel_OnProductIconClick_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions);
|
||||||
|
Label? branch = null;
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(UIControlPanelVeinCollectorPanel), nameof(UIControlPanelVeinCollectorPanel.isLocal))),
|
||||||
|
new CodeMatch(ci => ci.Branches(out branch))
|
||||||
|
).Repeat(
|
||||||
|
m =>
|
||||||
|
{
|
||||||
|
if (branch == null)
|
||||||
|
{
|
||||||
|
m.Advance(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var labels = m.Labels;
|
||||||
|
m.RemoveInstructions(3).InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Br, branch.Value).WithLabels(labels)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Patches.Factory;
|
||||||
|
|
||||||
|
internal class NoConditionBuild : PatchImpl<NoConditionBuild>
|
||||||
|
{
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
GameMain.data?.warningSystem?.UpdateCriticalWarningText();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDisable()
|
||||||
|
{
|
||||||
|
GameMain.data?.warningSystem?.UpdateCriticalWarningText();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: BuildTool_CheckBuildConditions_Transpiler
|
||||||
|
// Target: BuildTool_Addon.CheckBuildConditions, BuildTool_Inserter.CheckBuildConditions
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler, HarmonyPriority(Priority.Last)]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CheckBuildConditions))]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CheckBuildConditions))]
|
||||||
|
private static IEnumerable<CodeInstruction> BuildTool_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldc_I4_1);
|
||||||
|
yield return new CodeInstruction(OpCodes.Ret);
|
||||||
|
}
|
||||||
|
// Harmony transpiler: BuildTool_Path_CheckBuildConditions_Transpiler
|
||||||
|
// Target: BuildTool_Path.CheckBuildConditions
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler, HarmonyPriority(Priority.First)]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CheckBuildConditions))]
|
||||||
|
private static IEnumerable<CodeInstruction> BuildTool_Path_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
var label1 = generator.DefineLabel();
|
||||||
|
var label2 = generator.DefineLabel();
|
||||||
|
matcher.Start().InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Br, label1)
|
||||||
|
);
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(BuildTool), nameof(BuildTool.buildPreviews))),
|
||||||
|
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List<BuildPreview>), nameof(List<BuildPreview>.Count))),
|
||||||
|
new CodeMatch(ci => ci.IsStloc())
|
||||||
|
);
|
||||||
|
matcher.Labels.Add(label1);
|
||||||
|
matcher.Advance(4).InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Br, label2)
|
||||||
|
);
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(ci => ci.IsLdloc()),
|
||||||
|
new CodeMatch(ci => ci.Branches(out _)),
|
||||||
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
|
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BuildTool_Path), nameof(BuildTool_Path.waitForConfirm))),
|
||||||
|
new CodeMatch(ci => ci.Branches(out _))
|
||||||
|
);
|
||||||
|
var operand = matcher.Operand;
|
||||||
|
matcher.InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I4_1).WithLabels(label2),
|
||||||
|
new CodeInstruction(OpCodes.Stloc_S, operand)
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: BuildTool_Click_CheckBuildConditions_Transpiler
|
||||||
|
// Target: BuildTool_BlueprintPaste.CheckBuildConditions, BuildTool_Click.CheckBuildConditions
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler, HarmonyPriority(Priority.Last)]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CheckBuildConditions))]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))]
|
||||||
|
private static IEnumerable<CodeInstruction> BuildTool_Click_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
var label1 = generator.DefineLabel();
|
||||||
|
matcher.Start().InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(NoConditionBuild), nameof(CheckForMiner))),
|
||||||
|
new CodeInstruction(OpCodes.Brfalse_S, label1),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I4_1),
|
||||||
|
new CodeInstruction(OpCodes.Ret)
|
||||||
|
);
|
||||||
|
matcher.Labels.Add(label1);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CheckForMiner(BuildTool tool)
|
||||||
|
{
|
||||||
|
var previews = tool.buildPreviews;
|
||||||
|
foreach (var preview in previews)
|
||||||
|
{
|
||||||
|
var desc = preview?.item?.prefabDesc;
|
||||||
|
if (desc == null) continue;
|
||||||
|
if (desc.veinMiner || desc.oilMiner) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
namespace CheatEnabler.Patches.Factory;
|
||||||
|
|
||||||
|
internal class RemovePowerSpaceLimit : PatchImpl<RemovePowerSpaceLimit>
|
||||||
|
{
|
||||||
|
// Harmony transpiler: BuildTool_CheckBuildConditions_Transpiler
|
||||||
|
// Target: BuildTool_Click.CheckBuildConditions, BuildTool_BlueprintPaste.CheckBuildConditions
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))]
|
||||||
|
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CheckBuildConditions))]
|
||||||
|
private static IEnumerable<CodeInstruction> BuildTool_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions);
|
||||||
|
matcher.Start().MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldc_R4, 110.25f)
|
||||||
|
);
|
||||||
|
if (matcher.IsValid)
|
||||||
|
{
|
||||||
|
matcher.Repeat(codeMatcher => codeMatcher.SetAndAdvance(
|
||||||
|
OpCodes.Ldc_R4, 1f
|
||||||
|
));
|
||||||
|
}
|
||||||
|
matcher.Start().MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldc_R4, 144f)
|
||||||
|
);
|
||||||
|
if (matcher.IsValid)
|
||||||
|
{
|
||||||
|
matcher.Repeat(codeMatcher => codeMatcher.SetAndAdvance(
|
||||||
|
OpCodes.Ldc_R4, 1f
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BoostWindPower : PatchImpl<BoostWindPower>
|
||||||
|
{
|
||||||
|
// Harmony transpiler: PowerGeneratorComponent_EnergyCap_Wind_Transpiler
|
||||||
|
// Target: PowerGeneratorComponent.EnergyCap_Wind
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_Wind))]
|
||||||
|
private static IEnumerable<CodeInstruction> PowerGeneratorComponent_EnergyCap_Wind_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
matcher.Start().RemoveInstructions(matcher.Length);
|
||||||
|
matcher.Insert(
|
||||||
|
// this.currentStrength = windStrength
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_1),
|
||||||
|
new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.currentStrength))),
|
||||||
|
// this.capacityCurrentTick = 500000000L
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 500000000L),
|
||||||
|
new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick))),
|
||||||
|
// return 500000000L
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 500000000L),
|
||||||
|
new CodeInstruction(OpCodes.Ret)
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BoostSolarPower : PatchImpl<BoostSolarPower>
|
||||||
|
{
|
||||||
|
// Harmony transpiler: PowerGeneratorComponent_EnergyCap_PV_Transpiler
|
||||||
|
// Target: PowerGeneratorComponent.EnergyCap_PV
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_PV))]
|
||||||
|
private static IEnumerable<CodeInstruction> PowerGeneratorComponent_EnergyCap_PV_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
matcher.Start().RemoveInstructions(matcher.Length).Insert(
|
||||||
|
// this.currentStrength = lumino
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_S, 4),
|
||||||
|
new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.currentStrength))),
|
||||||
|
// this.capacityCurrentTick = 600000000L
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 600000000L),
|
||||||
|
new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick))),
|
||||||
|
// return 600000000L
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 600000000L),
|
||||||
|
new CodeInstruction(OpCodes.Ret)
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BoostFuelPower : PatchImpl<BoostFuelPower>
|
||||||
|
{
|
||||||
|
// Harmony transpiler: PowerGeneratorComponent_EnergyCap_Fuel_Transpiler
|
||||||
|
// Target: PowerGeneratorComponent.EnergyCap_Fuel
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_Fuel))]
|
||||||
|
private static IEnumerable<CodeInstruction> PowerGeneratorComponent_EnergyCap_Fuel_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
var label1 = generator.DefineLabel();
|
||||||
|
var label2 = generator.DefineLabel();
|
||||||
|
var label3 = generator.DefineLabel();
|
||||||
|
matcher.Start().MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick)))
|
||||||
|
);
|
||||||
|
var labels = matcher.Labels;
|
||||||
|
matcher.Labels = [];
|
||||||
|
matcher.Insert(
|
||||||
|
// if (this.fuelMask == 4)
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||||
|
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.fuelMask))),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I4_4),
|
||||||
|
new CodeInstruction(OpCodes.Bne_Un_S, label1),
|
||||||
|
// multiplier = 10000L
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 10000L),
|
||||||
|
new CodeInstruction(OpCodes.Br_S, label3),
|
||||||
|
// else if (this.fuelMask == 2)
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(label1),
|
||||||
|
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.fuelMask))),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I4_2),
|
||||||
|
new CodeInstruction(OpCodes.Bne_Un_S, label2),
|
||||||
|
// multiplier = 20000L
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 20000L),
|
||||||
|
new CodeInstruction(OpCodes.Br_S, label3),
|
||||||
|
// else multiplier = 50000L
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 50000L).WithLabels(label2),
|
||||||
|
// do multiplier before store to this.capacityCurrentTick
|
||||||
|
new CodeInstruction(OpCodes.Mul).WithLabels(label3)
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BoostGeothermalPower : PatchImpl<BoostGeothermalPower>
|
||||||
|
{
|
||||||
|
// Harmony transpiler: PowerGeneratorComponent_EnergyCap_GTH_Transpiler
|
||||||
|
// Target: PowerGeneratorComponent.EnergyCap_GTH
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_GTH))]
|
||||||
|
private static IEnumerable<CodeInstruction> PowerGeneratorComponent_EnergyCap_GTH_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
matcher.Start().RemoveInstructions(matcher.Length).Insert(
|
||||||
|
// this.currentStrength = this.gthStrength
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.gthStrength))),
|
||||||
|
new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.currentStrength))),
|
||||||
|
// this.capacityCurrentTick = 2000000000L
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_0),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 2000000000L),
|
||||||
|
new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick))),
|
||||||
|
// return 2000000000L
|
||||||
|
new CodeInstruction(OpCodes.Ldc_I8, 2000000000L),
|
||||||
|
new CodeInstruction(OpCodes.Ret)
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class WindTurbinesPowerGlobalCoverage
|
||||||
|
{
|
||||||
|
private static bool _patched;
|
||||||
|
private static PrefabDesc _prefabdesc;
|
||||||
|
private static float _oldCoverRadius;
|
||||||
|
private static float _oldConnectDistance;
|
||||||
|
private const int WindTurbineId = ItemIds.WindTurbine;
|
||||||
|
private const float WindTurbineNewCoverageDistance = 500f;
|
||||||
|
|
||||||
|
public static void Enable(bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
if (_patched) return;
|
||||||
|
_patched = true;
|
||||||
|
var itemProto = LDB.items.Select(WindTurbineId);
|
||||||
|
_oldCoverRadius = itemProto.prefabDesc.powerCoverRadius;
|
||||||
|
_oldConnectDistance = itemProto.prefabDesc.powerConnectDistance;
|
||||||
|
itemProto.prefabDesc.powerCoverRadius = WindTurbineNewCoverageDistance;
|
||||||
|
itemProto.prefabDesc.powerConnectDistance = WindTurbineNewCoverageDistance;
|
||||||
|
_prefabdesc = itemProto.prefabDesc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_patched) return;
|
||||||
|
_patched = false;
|
||||||
|
_prefabdesc.powerCoverRadius = _oldCoverRadius;
|
||||||
|
_prefabdesc.powerConnectDistance = _oldConnectDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
if (powerSystem == null) continue;
|
||||||
|
for (var i = powerSystem.nodeCursor - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
ref var node = ref powerSystem.nodePool[i];
|
||||||
|
if (node.id != i) continue;
|
||||||
|
ref var entity = ref factory.entityPool[node.entityId];
|
||||||
|
if (entity.protoId != WindTurbineId) continue;
|
||||||
|
// Disconnect from power system
|
||||||
|
powerSystem.OnNodeRemoving(i);
|
||||||
|
// Set new properties
|
||||||
|
node.connectDistance = _prefabdesc.powerConnectDistance;
|
||||||
|
node.coverRadius = _prefabdesc.powerCoverRadius;
|
||||||
|
// Connect back to power system
|
||||||
|
powerSystem.OnNodeAdded(i);
|
||||||
|
}
|
||||||
|
// Refresh power nodes rendering if factory is loaded
|
||||||
|
if (factory.planet.factoryLoaded)
|
||||||
|
{
|
||||||
|
factory.planet.factoryModel.RefreshPowerNodes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
|||||||
|
namespace CheatEnabler.Patches;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preserves the pre-refactor type and method identity used by mods that locate FactoryPatch through reflection.
|
||||||
|
/// </summary>
|
||||||
|
public static class FactoryPatch
|
||||||
|
{
|
||||||
|
public static void ArrivePlanet(PlanetFactory factory)
|
||||||
|
{
|
||||||
|
Factory.FactoryPatch.ArrivePlanet(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,12 @@ using BepInEx.Configuration;
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using UnityEngine.Bindings;
|
using UnityEngine.Bindings;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||||
|
|
||||||
namespace CheatEnabler.Patches;
|
namespace CheatEnabler.Patches;
|
||||||
|
|
||||||
|
[ModFeature("Game")]
|
||||||
public static class GamePatch
|
public static class GamePatch
|
||||||
{
|
{
|
||||||
public static ConfigEntry<bool> DevShortcutsEnabled;
|
public static ConfigEntry<bool> DevShortcutsEnabled;
|
||||||
@@ -19,6 +22,7 @@ public static class GamePatch
|
|||||||
DevShortcutsEnabled.SettingChanged += (_, _) => DevShortcuts.Enable(DevShortcutsEnabled.Value);
|
DevShortcutsEnabled.SettingChanged += (_, _) => DevShortcuts.Enable(DevShortcutsEnabled.Value);
|
||||||
AbnormalDisablerEnabled.SettingChanged += (_, _) => AbnormalDisabler.Enable(AbnormalDisablerEnabled.Value);
|
AbnormalDisablerEnabled.SettingChanged += (_, _) => AbnormalDisabler.Enable(AbnormalDisablerEnabled.Value);
|
||||||
UnlockTechEnabled.SettingChanged += (_, _) => UnlockTech.Enable(UnlockTechEnabled.Value);
|
UnlockTechEnabled.SettingChanged += (_, _) => UnlockTech.Enable(UnlockTechEnabled.Value);
|
||||||
|
GameLogicProc.OnGameEnd += ResetState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Start()
|
public static void Start()
|
||||||
@@ -30,11 +34,18 @@ public static class GamePatch
|
|||||||
|
|
||||||
public static void Uninit()
|
public static void Uninit()
|
||||||
{
|
{
|
||||||
|
GameLogicProc.OnGameEnd -= ResetState;
|
||||||
UnlockTech.Enable(false);
|
UnlockTech.Enable(false);
|
||||||
AbnormalDisabler.Enable(false);
|
AbnormalDisabler.Enable(false);
|
||||||
DevShortcuts.Enable(false);
|
DevShortcuts.Enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ResetState()
|
||||||
|
{
|
||||||
|
AbnormalDisabler.ResetState();
|
||||||
|
DevShortcuts.ResetState();
|
||||||
|
}
|
||||||
|
|
||||||
public class AbnormalDisabler : PatchImpl<AbnormalDisabler>
|
public class AbnormalDisabler : PatchImpl<AbnormalDisabler>
|
||||||
{
|
{
|
||||||
private static Dictionary<int, AbnormalityDeterminator> _savedDeterminators;
|
private static Dictionary<int, AbnormalityDeterminator> _savedDeterminators;
|
||||||
@@ -42,19 +53,21 @@ public static class GamePatch
|
|||||||
protected override void OnEnable()
|
protected override void OnEnable()
|
||||||
{
|
{
|
||||||
if (_savedDeterminators == null) return;
|
if (_savedDeterminators == null) return;
|
||||||
var abnormalLogic = GameMain.gameScenario.abnormalityLogic;
|
var abnormalLogic = GameMain.gameScenario?.abnormalityLogic;
|
||||||
|
if (abnormalLogic == null) return;
|
||||||
foreach (var p in _savedDeterminators)
|
foreach (var p in _savedDeterminators)
|
||||||
{
|
{
|
||||||
p.Value.OnUnregEvent();
|
p.Value.OnUnregEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
abnormalLogic.determinators = new Dictionary<int, AbnormalityDeterminator>();
|
abnormalLogic.determinators = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisable()
|
protected override void OnDisable()
|
||||||
{
|
{
|
||||||
if (_savedDeterminators == null) return;
|
if (_savedDeterminators == null) return;
|
||||||
var abnormalLogic = GameMain.gameScenario.abnormalityLogic;
|
var abnormalLogic = GameMain.gameScenario?.abnormalityLogic;
|
||||||
|
if (abnormalLogic?.determinators == null) return;
|
||||||
abnormalLogic.determinators = _savedDeterminators;
|
abnormalLogic.determinators = _savedDeterminators;
|
||||||
foreach (var p in _savedDeterminators)
|
foreach (var p in _savedDeterminators)
|
||||||
{
|
{
|
||||||
@@ -62,25 +75,30 @@ public static class GamePatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void ResetState()
|
||||||
|
{
|
||||||
|
_savedDeterminators = null;
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(AbnormalityLogic), "NotifyBeforeGameSave")]
|
[HarmonyPatch(typeof(AbnormalityLogic), nameof(AbnormalityLogic.NotifyBeforeGameSave))]
|
||||||
[HarmonyPatch(typeof(AbnormalityLogic), "NotifyOnAssemblerRecipePick")]
|
[HarmonyPatch(typeof(AbnormalityLogic), nameof(AbnormalityLogic.NotifyOnAssemblerRecipePick))]
|
||||||
[HarmonyPatch(typeof(AbnormalityLogic), "NotifyOnGameBegin")]
|
[HarmonyPatch(typeof(AbnormalityLogic), nameof(AbnormalityLogic.NotifyOnGameBegin))]
|
||||||
[HarmonyPatch(typeof(AbnormalityLogic), "NotifyOnMechaForgeTaskComplete")]
|
[HarmonyPatch(typeof(AbnormalityLogic), nameof(AbnormalityLogic.NotifyOnMechaForgeTaskComplete))]
|
||||||
[HarmonyPatch(typeof(AbnormalityLogic), "NotifyOnUnlockTech")]
|
[HarmonyPatch(typeof(AbnormalityLogic), nameof(AbnormalityLogic.NotifyOnUnlockTech))]
|
||||||
[HarmonyPatch(typeof(AbnormalityLogic), "NotifyOnUseConsole")]
|
[HarmonyPatch(typeof(AbnormalityLogic), nameof(AbnormalityLogic.NotifyOnUseConsole))]
|
||||||
private static bool DisableAbnormalLogic()
|
private static bool DisableAbnormalLogic()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(AbnormalityLogic), "InitDeterminators")]
|
[HarmonyPatch(typeof(AbnormalityLogic), nameof(AbnormalityLogic.InitDeterminators))]
|
||||||
private static void DisableAbnormalDeterminators(AbnormalityLogic __instance)
|
private static void DisableAbnormalDeterminators(AbnormalityLogic __instance)
|
||||||
{
|
{
|
||||||
_savedDeterminators = __instance.determinators;
|
_savedDeterminators = __instance.determinators;
|
||||||
if (!AbnormalDisablerEnabled.Value) return;
|
if (!AbnormalDisablerEnabled.Value) return;
|
||||||
__instance.determinators = new Dictionary<int, AbnormalityDeterminator>();
|
__instance.determinators = [];
|
||||||
foreach (var p in _savedDeterminators)
|
foreach (var p in _savedDeterminators)
|
||||||
{
|
{
|
||||||
p.Value.OnUnregEvent();
|
p.Value.OnUnregEvent();
|
||||||
@@ -102,6 +120,11 @@ public static class GamePatch
|
|||||||
if (_test != null) _test.active = false;
|
if (_test != null) _test.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void ResetState()
|
||||||
|
{
|
||||||
|
_test = null;
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(PlayerController), nameof(PlayerController.Init))]
|
[HarmonyPatch(typeof(PlayerController), nameof(PlayerController.Init))]
|
||||||
private static void PlayerController_Init_Postfix(PlayerController __instance)
|
private static void PlayerController_Init_Postfix(PlayerController __instance)
|
||||||
@@ -126,7 +149,9 @@ public static class GamePatch
|
|||||||
{
|
{
|
||||||
__instance.Update();
|
__instance.Update();
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: PlayerAction_Test_Update_Transpiler
|
||||||
|
// Target: PlayerAction_Test.Update
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(PlayerAction_Test), nameof(PlayerAction_Test.Update))]
|
[HarmonyPatch(typeof(PlayerAction_Test), nameof(PlayerAction_Test.Update))]
|
||||||
private static IEnumerable<CodeInstruction> PlayerAction_Test_Update_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> PlayerAction_Test_Update_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -139,7 +164,7 @@ public static class GamePatch
|
|||||||
var pos = matcher.Pos;
|
var pos = matcher.Pos;
|
||||||
/* Remove Shift+F4 part of the method */
|
/* Remove Shift+F4 part of the method */
|
||||||
matcher.Start().RemoveInstructions(pos).MatchForward(false,
|
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.Ldc_I4_0),
|
||||||
new CodeMatch(OpCodes.Ceq)
|
new CodeMatch(OpCodes.Ceq)
|
||||||
);
|
);
|
||||||
@@ -159,7 +184,9 @@ public static class GamePatch
|
|||||||
matcher.Labels = labels;
|
matcher.Labels = labels;
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: GameCamera_Logic_Transpiler
|
||||||
|
// Target: GameCamera.FrameLogic
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(GameCamera), nameof(GameCamera.FrameLogic))]
|
[HarmonyPatch(typeof(GameCamera), nameof(GameCamera.FrameLogic))]
|
||||||
private static IEnumerable<CodeInstruction> GameCamera_Logic_Transpiler(IEnumerable<CodeInstruction> instructions)
|
private static IEnumerable<CodeInstruction> GameCamera_Logic_Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
@@ -186,7 +213,7 @@ public static class GamePatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UnlockTech: PatchImpl<UnlockTech>
|
public class UnlockTech : PatchImpl<UnlockTech>
|
||||||
{
|
{
|
||||||
private static void UnlockTechRecursive(GameHistoryData history, [NotNull] TechProto techProto, int maxLevel = 10000)
|
private static void UnlockTechRecursive(GameHistoryData history, [NotNull] TechProto techProto, int maxLevel = 10000)
|
||||||
{
|
{
|
||||||
@@ -281,13 +308,15 @@ public static class GamePatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
history.VarifyTechQueue();
|
history.VerifyTechQueue();
|
||||||
if (history.currentTech != history.techQueue[0])
|
if (history.currentTech != history.techQueue[0])
|
||||||
{
|
{
|
||||||
history.currentTech = history.techQueue[0];
|
history.currentTech = history.techQueue[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Harmony transpiler: UITechNode_OnPointerDown_Transpiler
|
||||||
|
// Target: UITechNode.OnPointerDown
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(UITechNode), nameof(UITechNode.OnPointerDown))]
|
[HarmonyPatch(typeof(UITechNode), nameof(UITechNode.OnPointerDown))]
|
||||||
private static IEnumerable<CodeInstruction> UITechNode_OnPointerDown_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> UITechNode_OnPointerDown_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -296,7 +325,7 @@ public static class GamePatch
|
|||||||
matcher.MatchForward(false,
|
matcher.MatchForward(false,
|
||||||
new CodeMatch(OpCodes.Ldarg_0),
|
new CodeMatch(OpCodes.Ldarg_0),
|
||||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UITechNode), nameof(UITechNode.tree))),
|
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;
|
var labels = matcher.Labels;
|
||||||
matcher.Labels = null;
|
matcher.Labels = null;
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ using System.Reflection.Emit;
|
|||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler.Patches;
|
namespace CheatEnabler.Patches;
|
||||||
|
|
||||||
|
[ModFeature("Planet")]
|
||||||
public static class PlanetPatch
|
public static class PlanetPatch
|
||||||
{
|
{
|
||||||
public static ConfigEntry<bool> WaterPumpAnywhereEnabled;
|
public static ConfigEntry<bool> WaterPumpAnywhereEnabled;
|
||||||
@@ -29,8 +32,11 @@ public static class PlanetPatch
|
|||||||
TerraformAnyway.Enable(false);
|
TerraformAnyway.Enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WaterPumperPatch: PatchImpl<WaterPumperPatch>
|
private class WaterPumperPatch : PatchImpl<WaterPumperPatch>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: BuildTool_CheckBuildConditions_Transpiler
|
||||||
|
// Target: BuildTool_BlueprintPaste.CheckBuildConditions, BuildTool_Click.CheckBuildConditions
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CheckBuildConditions))]
|
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CheckBuildConditions))]
|
||||||
[HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))]
|
[HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))]
|
||||||
@@ -51,8 +57,103 @@ public static class PlanetPatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TerraformAnyway: PatchImpl<TerraformAnyway>
|
private class TerraformAnyway : PatchImpl<TerraformAnyway>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: BuildTool_BlueprintPaste_DetermineReforms_Patch
|
||||||
|
// Target: BuildTool_BlueprintPaste.DetermineReforms
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[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();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: BuildTool_Reform_RemoveBasePit_Patch
|
||||||
|
// Target: BuildTool_Reform.RemoveBasePit
|
||||||
|
// Fallback: Checks CodeMatcher.IsInvalid/IsValid and returns original instructions on mismatch.
|
||||||
|
[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();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: UIRemoveBasePitButton_OnRemoveButtonClick_Patch
|
||||||
|
// Target: UIRemoveBasePitButton.OnRemoveButtonClick, UIRemoveBasePitButton._OnUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[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();
|
||||||
|
}
|
||||||
|
// Harmony transpiler: BuildTool_Reform_ReformAction_Patch
|
||||||
|
// Target: BuildTool_Reform.ReformAction
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(BuildTool_Reform), nameof(BuildTool_Reform.ReformAction))]
|
[HarmonyPatch(typeof(BuildTool_Reform), nameof(BuildTool_Reform.ReformAction))]
|
||||||
private static IEnumerable<CodeInstruction> BuildTool_Reform_ReformAction_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> BuildTool_Reform_ReformAction_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
@@ -65,13 +166,13 @@ public static class PlanetPatch
|
|||||||
).RemoveInstructions(2).InsertAndAdvance(
|
).RemoveInstructions(2).InsertAndAdvance(
|
||||||
new CodeInstruction(OpCodes.Ldc_I4_0)
|
new CodeInstruction(OpCodes.Ldc_I4_0)
|
||||||
).MatchForward(false,
|
).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,
|
).Advance(1).MatchForward(false,
|
||||||
new CodeMatch(OpCodes.Conv_I8),
|
new CodeMatch(OpCodes.Conv_I8),
|
||||||
new CodeMatch(OpCodes.Sub)
|
new CodeMatch(OpCodes.Sub)
|
||||||
).Advance(2).InsertAndAdvance(
|
).Advance(2).InsertAndAdvance(
|
||||||
new CodeInstruction(OpCodes.Ldc_I8, 0L),
|
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();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ using System.Reflection.Emit;
|
|||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler.Patches;
|
namespace CheatEnabler.Patches;
|
||||||
|
|
||||||
|
[ModFeature("Player")]
|
||||||
public static class PlayerPatch
|
public static class PlayerPatch
|
||||||
{
|
{
|
||||||
public static ConfigEntry<bool> InstantHandCraftEnabled;
|
public static ConfigEntry<bool> InstantHandCraftEnabled;
|
||||||
@@ -33,7 +35,7 @@ public static class PlayerPatch
|
|||||||
WarpWithoutSpaceWarpers.Enable(false);
|
WarpWithoutSpaceWarpers.Enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InstantHandCraft: PatchImpl<InstantHandCraft>
|
private class InstantHandCraft : PatchImpl<InstantHandCraft>
|
||||||
{
|
{
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(ForgeTask), MethodType.Constructor, typeof(int), typeof(int))]
|
[HarmonyPatch(typeof(ForgeTask), MethodType.Constructor, typeof(int), typeof(int))]
|
||||||
@@ -43,8 +45,11 @@ public static class PlayerPatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InstantTeleport: PatchImpl<InstantTeleport>
|
private class InstantTeleport : PatchImpl<InstantTeleport>
|
||||||
{
|
{
|
||||||
|
// Harmony transpiler: UIGlobemap__OnUpdate_Transpiler
|
||||||
|
// Target: UIGlobemap._OnUpdate, UIStarmap.DoRightClickFastTravel, UIStarmap.OnFastTravelButtonClick, UIStarmap.OnScreenClick, UIStarmap.SandboxRightClickFastTravelLogic, UIStarmap.StartFastTravelToPlanet, UIStarmap.StartFastTravelToUPosition, UIStarmap.UpdateCursorView, UIStarmap._OnUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(UIGlobemap), nameof(UIGlobemap._OnUpdate))]
|
[HarmonyPatch(typeof(UIGlobemap), nameof(UIGlobemap._OnUpdate))]
|
||||||
[HarmonyPatch(typeof(UIStarmap), nameof(UIStarmap.DoRightClickFastTravel))]
|
[HarmonyPatch(typeof(UIStarmap), nameof(UIStarmap.DoRightClickFastTravel))]
|
||||||
@@ -66,7 +71,7 @@ public static class PlayerPatch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WarpWithoutSpaceWarpers: PatchImpl<WarpWithoutSpaceWarpers>
|
private class WarpWithoutSpaceWarpers : PatchImpl<WarpWithoutSpaceWarpers>
|
||||||
{
|
{
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(Mecha), nameof(Mecha.HasWarper))]
|
[HarmonyPatch(typeof(Mecha), nameof(Mecha.HasWarper))]
|
||||||
@@ -75,7 +80,7 @@ public static class PlayerPatch
|
|||||||
__result = true;
|
__result = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(Mecha), nameof(Mecha.UseWarper))]
|
[HarmonyPatch(typeof(Mecha), nameof(Mecha.UseWarper))]
|
||||||
private static void Mecha_UseWarper_Postfix(ref bool __result)
|
private static void Mecha_UseWarper_Postfix(ref bool __result)
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ using System.Reflection.Emit;
|
|||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
|
using UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
namespace CheatEnabler.Patches;
|
namespace CheatEnabler.Patches;
|
||||||
|
|
||||||
|
[ModFeature("Resource")]
|
||||||
public static class ResourcePatch
|
public static class ResourcePatch
|
||||||
{
|
{
|
||||||
public static ConfigEntry<bool> InfiniteResourceEnabled;
|
public static ConfigEntry<bool> InfiniteResourceEnabled;
|
||||||
@@ -29,12 +31,15 @@ public static class ResourcePatch
|
|||||||
FastMining.Enable(false);
|
FastMining.Enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InfiniteResource: PatchImpl<InfiniteResource>
|
private class InfiniteResource : PatchImpl<InfiniteResource>
|
||||||
{
|
{
|
||||||
|
static private readonly float InfiniteResourceRate = 0f;
|
||||||
|
// Harmony transpiler: Transpiler
|
||||||
|
// Target: FactorySystem.GameTick, GameLogic._miner_parallel, PlanetTransport.GameTick, UIChartAstroResource.CalculateMaxAmount, UIChartVeinGroup.CalculateMaxAmount, UIControlPanelAdvancedMinerEntry._OnUpdate, UIControlPanelVeinCollectorPanel._OnUpdate, UIMinerWindow._OnUpdate, UIMiningUpgradeLabel.Update, UIVeinCollectorPanel._OnUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTick), typeof(long), typeof(bool))]
|
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTick), typeof(long), typeof(bool))]
|
||||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTick), typeof(long), typeof(bool), typeof(int), typeof(int), typeof(int))]
|
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic._miner_parallel))]
|
||||||
[HarmonyPatch(typeof(ItemProto), nameof(ItemProto.GetPropValue))]
|
|
||||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.GameTick))]
|
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.GameTick))]
|
||||||
[HarmonyPatch(typeof(UIChartAstroResource), nameof(UIChartAstroResource.CalculateMaxAmount))]
|
[HarmonyPatch(typeof(UIChartAstroResource), nameof(UIChartAstroResource.CalculateMaxAmount))]
|
||||||
[HarmonyPatch(typeof(UIChartVeinGroup), nameof(UIChartVeinGroup.CalculateMaxAmount))]
|
[HarmonyPatch(typeof(UIChartVeinGroup), nameof(UIChartVeinGroup.CalculateMaxAmount))]
|
||||||
@@ -42,48 +47,83 @@ public static class ResourcePatch
|
|||||||
[HarmonyPatch(typeof(UIControlPanelVeinCollectorPanel), nameof(UIControlPanelVeinCollectorPanel._OnUpdate))]
|
[HarmonyPatch(typeof(UIControlPanelVeinCollectorPanel), nameof(UIControlPanelVeinCollectorPanel._OnUpdate))]
|
||||||
[HarmonyPatch(typeof(UIMinerWindow), nameof(UIMinerWindow._OnUpdate))]
|
[HarmonyPatch(typeof(UIMinerWindow), nameof(UIMinerWindow._OnUpdate))]
|
||||||
[HarmonyPatch(typeof(UIMiningUpgradeLabel), nameof(UIMiningUpgradeLabel.Update))]
|
[HarmonyPatch(typeof(UIMiningUpgradeLabel), nameof(UIMiningUpgradeLabel.Update))]
|
||||||
|
[HarmonyPatch(typeof(UIVeinCollectorPanel), nameof(UIVeinCollectorPanel._OnUpdate))]
|
||||||
|
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
|
{
|
||||||
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
|
matcher.MatchForward(false,
|
||||||
|
new CodeMatch(ci => (ci.opcode == OpCodes.Ldfld || ci.opcode == OpCodes.Ldflda) && ci.OperandIs(AccessTools.Field(typeof(GameHistoryData), nameof(GameHistoryData.miningCostRate))))
|
||||||
|
).Repeat(codeMatcher =>
|
||||||
|
{
|
||||||
|
if (codeMatcher.Instruction.opcode == OpCodes.Ldfld)
|
||||||
|
{
|
||||||
|
codeMatcher.RemoveInstruction().InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Pop),
|
||||||
|
new CodeInstruction(OpCodes.Ldc_R4, InfiniteResourceRate)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
codeMatcher.RemoveInstruction().InsertAndAdvance(
|
||||||
|
new CodeInstruction(OpCodes.Pop),
|
||||||
|
new CodeInstruction(OpCodes.Ldsflda, AccessTools.Field(typeof(InfiniteResource), nameof(InfiniteResourceRate)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return matcher.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FastMining : PatchImpl<FastMining>
|
||||||
|
{
|
||||||
|
static private readonly float FastMiningSpeed = 2400f;
|
||||||
|
// Harmony transpiler: Transpiler
|
||||||
|
// Target: AstroResourceStatPlan.AddPlanetResources, BuildingGizmo.Update, FactorySystem.GameTick, GameLogic._miner_parallel, ItemProto.GetPropValue, PlanetTransport.GameTick, ProductionExtraInfoCalculator.CalculateFactory, UIChartAstroResource.CalculateMaxAmount, UIChartVeinGroup.CalculateMaxAmount, UIControlPanelStationStorage.RefreshValues, UIControlPanelVeinCollectorPanel._OnUpdate, UIMinerWindow._OnUpdate, UIMiningUpgradeLabel.Update, UIPlanetDetail.OnPlanetDataSet, UIPlanetDetail.RefreshDynamicProperties, UIReferenceSpeedTip.AddEntryDataWithFactory, UIStarDetail.OnStarDataSet, UIStarDetail.RefreshDynamicProperties, UIStationStorage.RefreshValues, UIVeinCollectorPanel._OnUpdate
|
||||||
|
// Fallback: None — patch will fail loudly if the target method body changes.
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(typeof(AstroResourceStatPlan), nameof(AstroResourceStatPlan.AddPlanetResources))]
|
||||||
|
[HarmonyPatch(typeof(BuildingGizmo), nameof(BuildingGizmo.Update))]
|
||||||
|
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTick), typeof(long), typeof(bool))]
|
||||||
|
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic._miner_parallel))]
|
||||||
|
[HarmonyPatch(typeof(ItemProto), nameof(ItemProto.GetPropValue))]
|
||||||
|
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.GameTick))]
|
||||||
|
[HarmonyPatch(typeof(ProductionExtraInfoCalculator), nameof(ProductionExtraInfoCalculator.CalculateFactory))]
|
||||||
|
[HarmonyPatch(typeof(UIChartAstroResource), nameof(UIChartAstroResource.CalculateMaxAmount))]
|
||||||
|
[HarmonyPatch(typeof(UIChartVeinGroup), nameof(UIChartVeinGroup.CalculateMaxAmount))]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.RefreshValues))]
|
||||||
|
[HarmonyPatch(typeof(UIControlPanelVeinCollectorPanel), nameof(UIControlPanelVeinCollectorPanel._OnUpdate))]
|
||||||
|
[HarmonyPatch(typeof(UIMinerWindow), nameof(UIMinerWindow._OnUpdate))]
|
||||||
|
[HarmonyPatch(typeof(UIMiningUpgradeLabel), nameof(UIMiningUpgradeLabel.Update))]
|
||||||
|
[HarmonyPatch(typeof(UIPlanetDetail), nameof(UIPlanetDetail.OnPlanetDataSet))]
|
||||||
|
[HarmonyPatch(typeof(UIPlanetDetail), nameof(UIPlanetDetail.RefreshDynamicProperties))]
|
||||||
|
[HarmonyPatch(typeof(UIReferenceSpeedTip), nameof(UIReferenceSpeedTip.AddEntryDataWithFactory))]
|
||||||
|
[HarmonyPatch(typeof(UIStarDetail), nameof(UIStarDetail.OnStarDataSet))]
|
||||||
|
[HarmonyPatch(typeof(UIStarDetail), nameof(UIStarDetail.RefreshDynamicProperties))]
|
||||||
[HarmonyPatch(typeof(UIStationStorage), nameof(UIStationStorage.RefreshValues))]
|
[HarmonyPatch(typeof(UIStationStorage), nameof(UIStationStorage.RefreshValues))]
|
||||||
[HarmonyPatch(typeof(UIVeinCollectorPanel), nameof(UIVeinCollectorPanel._OnUpdate))]
|
[HarmonyPatch(typeof(UIVeinCollectorPanel), nameof(UIVeinCollectorPanel._OnUpdate))]
|
||||||
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
{
|
{
|
||||||
var matcher = new CodeMatcher(instructions, generator);
|
var matcher = new CodeMatcher(instructions, generator);
|
||||||
matcher.MatchForward(false,
|
matcher.MatchForward(false,
|
||||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameHistoryData), nameof(GameHistoryData.miningCostRate)))
|
new CodeMatch(ci => (ci.opcode == OpCodes.Ldfld || ci.opcode == OpCodes.Ldflda) && ci.OperandIs(AccessTools.Field(typeof(GameHistoryData), nameof(GameHistoryData.miningSpeedScale))))
|
||||||
).Repeat(codeMatcher =>
|
).Repeat(codeMatcher =>
|
||||||
codeMatcher.RemoveInstruction().InsertAndAdvance(
|
{
|
||||||
new CodeInstruction(OpCodes.Pop),
|
if (codeMatcher.Instruction.opcode == OpCodes.Ldfld)
|
||||||
new CodeInstruction(OpCodes.Ldc_R4, 0f)
|
{
|
||||||
)
|
codeMatcher.RemoveInstruction().InsertAndAdvance(
|
||||||
);
|
new CodeInstruction(OpCodes.Pop),
|
||||||
return matcher.InstructionEnumeration();
|
new CodeInstruction(OpCodes.Ldc_R4, FastMiningSpeed)
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
private class FastMining: PatchImpl<FastMining>
|
{
|
||||||
{
|
codeMatcher.RemoveInstruction().InsertAndAdvance(
|
||||||
[HarmonyTranspiler]
|
new CodeInstruction(OpCodes.Pop),
|
||||||
[HarmonyPatch(typeof(FactorySystem), "GameTick", typeof(long), typeof(bool))]
|
new CodeInstruction(OpCodes.Ldsflda, AccessTools.Field(typeof(FastMining), nameof(FastMiningSpeed)))
|
||||||
[HarmonyPatch(typeof(FactorySystem), "GameTick", typeof(long), typeof(bool), typeof(int), typeof(int), typeof(int))]
|
);
|
||||||
[HarmonyPatch(typeof(ItemProto), "GetPropValue")]
|
}
|
||||||
[HarmonyPatch(typeof(PlanetTransport), "GameTick")]
|
}
|
||||||
[HarmonyPatch(typeof(UIMinerWindow), "_OnUpdate")]
|
|
||||||
[HarmonyPatch(typeof(UIMiningUpgradeLabel), "Update")]
|
|
||||||
[HarmonyPatch(typeof(UIPlanetDetail), "OnPlanetDataSet")]
|
|
||||||
[HarmonyPatch(typeof(UIPlanetDetail), "RefreshDynamicProperties")]
|
|
||||||
[HarmonyPatch(typeof(UIStarDetail), "OnStarDataSet")]
|
|
||||||
[HarmonyPatch(typeof(UIStarDetail), "RefreshDynamicProperties")]
|
|
||||||
[HarmonyPatch(typeof(UIStationStorage), "RefreshValues")]
|
|
||||||
[HarmonyPatch(typeof(UIVeinCollectorPanel), "_OnUpdate")]
|
|
||||||
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
|
||||||
{
|
|
||||||
var matcher = new CodeMatcher(instructions, generator);
|
|
||||||
matcher.MatchForward(false,
|
|
||||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameHistoryData), nameof(GameHistoryData.miningSpeedScale)))
|
|
||||||
).Repeat(codeMatcher =>
|
|
||||||
codeMatcher.RemoveInstruction().InsertAndAdvance(
|
|
||||||
new CodeInstruction(OpCodes.Pop),
|
|
||||||
new CodeInstruction(OpCodes.Ldc_R4, 2400f)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
|||||||
+110
-94
@@ -3,64 +3,72 @@
|
|||||||
<details>
|
<details>
|
||||||
<summary>Read me in English</summary>
|
<summary>Read me in English</summary>
|
||||||
|
|
||||||
#### Add various cheat functions while disabling abnormal determinants
|
***Add various cheat functions while disabling abnormal determinants***
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
* Config panel is unified with UXAssist.
|
* Config panel is unified with UXAssist.
|
||||||
* There are also buttons on title screen and planet minimap area to call up the config panel.
|
* There are also buttons on title screen and planet minimap area to call up the config panel.
|
||||||
* Features:
|
* Features:
|
||||||
+ General:
|
* General:
|
||||||
+ Enable Dev Shortcuts (check config panel for usage)
|
* Enable Dev Shortcuts (check config panel for usage)
|
||||||
+ Disable Abnormal Checks
|
* Disable Abnormal Checks
|
||||||
+ Unlock techs with key-modifiers (Ctrl/Alt/Shift)
|
* Unlock techs with key-modifiers (Ctrl/Alt/Shift)
|
||||||
+ Remove all metadata consumption records
|
* Remove all metadata consumption records
|
||||||
+ Remove metadata consumption record in current game
|
* Remove metadata consumption record in current game
|
||||||
+ Clear metadata flag which bans achievements
|
* Clear metadata flag which bans achievements
|
||||||
+ Assign gamesave to currrnet account
|
* Assign gamesave to currrnet account
|
||||||
+ Factory:
|
* Factory:
|
||||||
+ Finish build immediately
|
* Finish build immediately
|
||||||
+ Architect mode (Infinite buildings)
|
* Architect mode (Infinite buildings)
|
||||||
+ Build without condition
|
* Build without condition
|
||||||
+ No collision
|
* No collision
|
||||||
+ Belt signal item generation
|
* Belt signal item generation
|
||||||
- Count generations as production in statistics
|
* Count generations as production in statistics
|
||||||
- Count removals as consumption in statistics
|
* Count removals as consumption in statistics
|
||||||
- Count all raws and intermediates in statistics
|
* Count all raws and intermediates in statistics
|
||||||
- Belt signal alt format
|
* Belt signal alt format
|
||||||
+ Increase maximum power usage in Logistic Stations and Advanced Mining Machines
|
* Increase maximum power usage in Logistic Stations and Advanced Mining Machines
|
||||||
- Logistic Stations: Increased max charging power to 3GW(ILS) and 600MW(PLS) (10x of original)
|
* Logistic Stations: Increased max charging power to 3GW(ILS) and 600MW(PLS) (10x of original)
|
||||||
- Advanced Mining Machines: Increased max mining speed to 1000%
|
* Advanced Mining Machines: Increased max mining speed to 1000%
|
||||||
+ Retrieve/Place items from/to remote planets on logistics control panel
|
* Retrieve/Place items from/to remote planets on logistics control panel
|
||||||
+ Remove space limit between wind turbines and solar panels
|
* Remove space limit between wind turbines and solar panels
|
||||||
+ Wind Turbines do global power coverage
|
* Wind Turbines do global power coverage
|
||||||
+ Boost power generations for kinds of power generators
|
* Boost power generations for kinds of power generators
|
||||||
+ Planet:
|
* Planet:
|
||||||
+ Instant hand-craft
|
* Instant hand-craft
|
||||||
+ Infinite Natural Resources
|
* Infinite Natural Resources
|
||||||
+ Fast Mining
|
* Fast Mining
|
||||||
+ Pump Anywhere
|
* Pump Anywhere
|
||||||
+ Terraform without enought soil piles
|
* Terraform without enought soil piles
|
||||||
+ Instant teleport (like that in Sandbox mode)
|
* Instant teleport (like that in Sandbox mode)
|
||||||
+ Dyson Sphere:
|
* Dyson Sphere:
|
||||||
+ Skip bullet period
|
* Skip bullet period
|
||||||
+ Skip absorption period
|
* Skip absorption period
|
||||||
+ Quick absorb
|
* Quick absorb
|
||||||
+ Eject anyway
|
* Eject anyway
|
||||||
+ Complete Dyson Sphere Shells instantly
|
* Unlock Dyson Sphere max orbit radius
|
||||||
+ Mecha/Combat:
|
* Complete Dyson Sphere Shells instantly
|
||||||
+ Mecha and Drones/Fleets invicible
|
* Remove all frames on Dyson Sphere
|
||||||
+ Buildings invicible
|
* Buttons for creating illegal Dyson Sphere Shells, you must enable `IllegalDysonShellFunctionsEnabled` of `DysonSphere` section in config to see the last 2 buttons.
|
||||||
+ Enable warp without space warpers
|
* Generate an illegal dyson shell
|
||||||
+ Teleport to outer space
|
* Keep max production shells and remove others
|
||||||
+ Teleport to selected astronomical
|
* Duplicate shells from that with highest production
|
||||||
|
* Mecha/Combat:
|
||||||
|
* Mecha and Drones/Fleets invicible
|
||||||
|
* Buildings invicible
|
||||||
|
* Enable warp without space warpers
|
||||||
|
* Teleport to outer space
|
||||||
|
* Teleport to selected astronomical
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
* Please upgrade `BepInEx` 5.4.21 or later if using with [BlueprintTweaks](https://dsp.thunderstore.io/package/kremnev8/BlueprintTweaks/) to avoid possible conflicts.
|
* Please upgrade `BepInEx` 5.4.21 or later if using with [BlueprintTweaks](https://dsp.thunderstore.io/package/kremnev8/BlueprintTweaks/) to avoid possible conflicts.
|
||||||
+ You can download `BepInEx` [here](https://github.com/bepinex/bepinex/releases/latest)(choose x64 edition).
|
* You can download [BepInEx here](https://github.com/bepinex/bepinex/releases/latest)(choose x64 edition).
|
||||||
+ If using with r2modman, you can upgrade `BepInEx` by clicking `Settings` -> `Browse profile folder`, then extract downloaded zip to the folder and overwrite existing files.
|
* If using with r2modman, you can upgrade `BepInEx` by clicking `Settings` -> `Browse profile folder`, then extract downloaded zip to the folder and overwrite existing files.
|
||||||
|
|
||||||
## CREDITS
|
## CREDITS
|
||||||
|
|
||||||
* [Dyson Sphere Program](https://store.steampowered.com/app/1366540): The great game
|
* [Dyson Sphere Program](https://store.steampowered.com/app/1366540): The great game
|
||||||
* [BepInEx](https://bepinex.dev/): Base modding framework
|
* [BepInEx](https://bepinex.dev/): Base modding framework
|
||||||
* [Multifunction_mod](https://github.com/blacksnipebiu/Multifunction_mod): Some cheat functions
|
* [Multifunction_mod](https://github.com/blacksnipebiu/Multifunction_mod): Some cheat functions
|
||||||
@@ -70,64 +78,72 @@
|
|||||||
<details>
|
<details>
|
||||||
<summary>中文读我</summary>
|
<summary>中文读我</summary>
|
||||||
|
|
||||||
#### 添加一些作弊功能,同时屏蔽异常检测
|
***添加一些作弊功能,同时屏蔽异常检测***
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
* 配置面板复用UXAssist
|
* 配置面板复用UXAssist
|
||||||
* 标题界面和行星小地图旁也有按钮呼出主面板
|
* 标题界面和行星小地图旁也有按钮呼出主面板
|
||||||
* 功能:
|
* 功能:
|
||||||
+ 常规:
|
* 常规:
|
||||||
+ 启用开发模式快捷键(使用说明见设置面板)
|
* 启用开发模式快捷键(使用说明见设置面板)
|
||||||
+ 屏蔽异常检测
|
* 屏蔽异常检测
|
||||||
+ 使用组合键解锁科技(Ctrl/Alt/Shift)
|
* 使用组合键解锁科技(Ctrl/Alt/Shift)
|
||||||
+ 移除所有元数据消耗记录
|
* 移除所有元数据消耗记录
|
||||||
+ 移除当前存档的元数据消耗记录
|
* 移除当前存档的元数据消耗记录
|
||||||
+ 解除当前存档因使用元数据导致的成就限制
|
* 解除当前存档因使用元数据导致的成就限制
|
||||||
+ 将游戏存档绑定给当前账号
|
* 将游戏存档绑定给当前账号
|
||||||
+ 工厂:
|
* 工厂:
|
||||||
+ 建造秒完成
|
* 建造秒完成
|
||||||
+ 建筑师模式(无限建筑)
|
* 建筑师模式(无限建筑)
|
||||||
+ 无条件建造
|
* 无条件建造
|
||||||
+ 无碰撞
|
* 无碰撞
|
||||||
+ 传送带信号物品生成
|
* 传送带信号物品生成
|
||||||
- 统计信息里将生成计算为产物
|
* 统计信息里将生成计算为产物
|
||||||
- 统计信息里将移除计算为消耗
|
* 统计信息里将移除计算为消耗
|
||||||
- 统计面板中计算所有原材料和中间产物
|
* 统计面板中计算所有原材料和中间产物
|
||||||
- 传送带信号替换格式
|
* 传送带信号替换格式
|
||||||
+ 提升物流塔和大型采矿机的最大功耗
|
* 提升物流塔和大型采矿机的最大功耗
|
||||||
- 物流塔:将最大充电功率提高到3GW(星际物流塔)和600MW(行星物流塔)(原来的10倍)
|
* 物流塔:将最大充电功率提高到3GW(星际物流塔)和600MW(行星物流塔)(原来的10倍)
|
||||||
- 大型采矿机:将最大采矿速度提高到1000%
|
* 大型采矿机:将最大采矿速度提高到1000%
|
||||||
+ 在物流总控面板上可以从非本地行星取放物品
|
* 在物流总控面板上可以从非本地行星取放物品
|
||||||
+ 风力发电机和太阳能板无间距限制
|
* 风力发电机和太阳能板无间距限制
|
||||||
+ 风力涡轮机供电覆盖全球
|
* 风力涡轮机供电覆盖全球
|
||||||
+ 提升各种发电设备发电量
|
* 提升各种发电设备发电量
|
||||||
+ 行星:
|
* 行星:
|
||||||
+ 快速手动制造
|
* 快速手动制造
|
||||||
+ 自然资源采集不消耗
|
* 自然资源采集不消耗
|
||||||
+ 高速采集
|
* 高速采集
|
||||||
+ 平地抽水
|
* 平地抽水
|
||||||
+ 沙土不够时依然可以整改地形
|
* 沙土不够时依然可以整改地形
|
||||||
+ 快速传送(和沙盒模式一样)
|
* 快速传送(和沙盒模式一样)
|
||||||
+ 戴森球:
|
* 戴森球:
|
||||||
+ 跳过子弹阶段
|
* 跳过子弹阶段
|
||||||
+ 跳过吸收阶段
|
* 跳过吸收阶段
|
||||||
+ 快速吸收
|
* 快速吸收
|
||||||
+ 全球弹射
|
* 全球弹射
|
||||||
+ 立即完成戴森壳建造
|
* 解锁戴森球最大轨道半径
|
||||||
+ 机甲/战斗:
|
* 立即完成戴森壳建造
|
||||||
+ 机甲和战斗无人机无敌
|
* 移除戴森球上的所有框架
|
||||||
+ 建筑无敌
|
* 用于制作仙术戴森壳的按钮,你必须在设置文件里开启`DysonSphere`分类的`IllegalDysonShellFunctionsEnabled`才能看到后面两个按钮
|
||||||
+ 无需空间翘曲器即可曲速飞行
|
* 生成单层仙术戴森壳
|
||||||
+ 传送到外太空
|
* 保留发电量最高的戴森壳并移除其他戴森壳
|
||||||
+ 传送到选定的天体
|
* 从发电量最高的壳复制戴森壳
|
||||||
|
* 机甲/战斗:
|
||||||
|
* 机甲和战斗无人机无敌
|
||||||
|
* 建筑无敌
|
||||||
|
* 无需空间翘曲器即可曲速飞行
|
||||||
|
* 传送到外太空
|
||||||
|
* 传送到选定的天体
|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
|
|
||||||
* 如果和[BlueprintTweaks](https://dsp.thunderstore.io/package/kremnev8/BlueprintTweaks/)一起使用,请升级`BepInEx`到5.4.21或更高版本,以避免可能的冲突
|
* 如果和[BlueprintTweaks](https://dsp.thunderstore.io/package/kremnev8/BlueprintTweaks/)一起使用,请升级`BepInEx`到5.4.21或更高版本,以避免可能的冲突
|
||||||
+ 你可以在[这里](https://github.com/bepinex/bepinex/releases/latest)(选择x64版本)下载`BepInEx`
|
* 你可以在[这里](https://github.com/bepinex/bepinex/releases/latest)(选择x64版本)下载`BepInEx`
|
||||||
+ 如果使用r2modman,你可以点击`Settings` -> `Browse profile folder`,然后将下载的zip解压到该文件夹并覆盖现有文件
|
* 如果使用r2modman,你可以点击`Settings` -> `Browse profile folder`,然后将下载的zip解压到该文件夹并覆盖现有文件
|
||||||
|
|
||||||
## 鸣谢
|
## 鸣谢
|
||||||
|
|
||||||
* [戴森球计划](https://store.steampowered.com/app/1366540): 伟大的游戏
|
* [戴森球计划](https://store.steampowered.com/app/1366540): 伟大的游戏
|
||||||
* [BepInEx](https://bepinex.dev/): 基础模组框架
|
* [BepInEx](https://bepinex.dev/): 基础模组框架
|
||||||
* [Multifunction_mod](https://github.com/blacksnipebiu/Multifunction_mod): 一些作弊功能
|
* [Multifunction_mod](https://github.com/blacksnipebiu/Multifunction_mod): 一些作弊功能
|
||||||
|
|||||||
+269
-229
@@ -1,6 +1,9 @@
|
|||||||
using CheatEnabler.Functions;
|
using CheatEnabler.Functions;
|
||||||
using CheatEnabler.Patches;
|
using CheatEnabler.Patches;
|
||||||
|
using CheatEnabler.Patches.Factory;
|
||||||
|
using FactoryPatch = CheatEnabler.Patches.Factory.FactoryPatch;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
using UXAssist.UI;
|
using UXAssist.UI;
|
||||||
using UXAssist.Common;
|
using UXAssist.Common;
|
||||||
using System;
|
using System;
|
||||||
@@ -16,65 +19,6 @@ public static class UIConfigWindow
|
|||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
I18N.Add("Factory", "Factory", "工厂");
|
|
||||||
I18N.Add("Planet", "Planet", "行星");
|
|
||||||
I18N.Add("Mecha/Combat", "Mecha/Combat", "机甲/战斗");
|
|
||||||
I18N.Add("Enable Dev Shortcuts", "Enable Dev Shortcuts", "开发模式快捷键");
|
|
||||||
I18N.Add("Disable Abnormal Checks", "Disable Abnormal Checks", "关闭数据异常检查");
|
|
||||||
I18N.Add("Hotkey", "Hotkey", "快捷键");
|
|
||||||
I18N.Add("Unlock Tech with Key-Modifiers", "Unlock Tech with Key-Modifiers", "使用组合键点击解锁科技");
|
|
||||||
I18N.Add("Dev Shortcuts", "Dev Shortcuts", "开发模式快捷键");
|
|
||||||
I18N.Add("Dev Shortcuts Tips",
|
|
||||||
"Caution: Some function may trigger abnormal check!\nNumpad 1: Gets all items and extends bag.\nNumpad 2: Boosts walk speed, gathering speed and mecha energy restoration.\nNumpad 3: Fills planet with foundations and bury all veins.\nNumpad 4: +1 construction drone.\nNumpad 5: Upgrades drone engine tech to full.\nNumpad 6: Unlocks researching tech.\nNumpad 7: Unlocks Drive Engine 1.\nNumpad 8: Unlocks Drive Engine 2 and maximize energy.\nNumpad 9: Unlocks ability to warp.\nNumpad 0: No costs for Logistic Storages' output.\nLCtrl + T: Unlocks all techs (not upgrades).\nLCtrl + Q: Adds 10000 to every metadata.\nLCtrl + W: Enters Sandbox Mode.\nLCtrl + Shift + W: Leaves Sandbox Mode.\nNumpad *: Proliferates items on hand.\nNumpad /: Removes proliferations from items on hand.\nPageDown: Remembers Pose of game camera.\nPageUp: Locks game camera using remembered Pose.",
|
|
||||||
"警告:某些功能可能触发异常检查!\n小键盘1:获得所有物品并扩展背包\n小键盘2:加快行走速度及采集速度,加快能量恢复速度\n小键盘3:将地基铺设整个星球并掩埋所有矿物\n小键盘4:建设机器人 +1\n小键盘5:建设机器人满级\n小键盘6:解锁当前科技\n小键盘7:解锁驱动技术I\n小键盘8:解锁驱动技术II 最大化能量\n小键盘9:机甲曲速解锁\n小键盘0:物流站通过传送带出物品无消耗\n左Ctrl + T:解锁所有非升级科技\n左Ctrl + Q:增加各项元数据10000点\n左Ctrl + W:进入沙盒模式\n左Ctrl + Shift + W:离开沙盒模式\n小键盘乘号 *:给手上物品喷涂增产剂\n小键盘除号 /:清除手上物品的增产剂\nPageDown:记录摄像机当前的Pose\nPageUp:用记录的Pose锁定摄像机");
|
|
||||||
I18N.Add("Unlock Tech with Key-Modifiers Tips",
|
|
||||||
"Click tech on tree while holding:\n Shift: Tech level + 1\n Ctrl: Tech level + 10\n Ctrl + Shift: Tech level + 100\n Alt: Tech level to MAX\n\nNote: all direct prerequisites will be unlocked as well.",
|
|
||||||
"按住以下组合键点击科技树:\n Shift:科技等级+1\n Ctrl:科技等级+10\n Ctrl+Shift:科技等级+100\n Alt:科技等级升到最大\n\n注意:所有直接前置科技也会被解锁");
|
|
||||||
I18N.Add("Remove all metadata consumption records", "Remove all metadata consumption records", "移除所有元数据消耗记录");
|
|
||||||
I18N.Add("Remove metadata consumption record in current game", "Remove metadata consumption record in current game", "移除当前存档的元数据消耗记录");
|
|
||||||
I18N.Add("Clear metadata flag which bans achievements", "Clear metadata flag which bans achievements in current game", "解除当前存档因使用元数据导致的成就限制");
|
|
||||||
I18N.Add("Assign gamesave to current account", "Assign gamesave to current account", "将游戏存档绑定给当前账号");
|
|
||||||
I18N.Add("Finish build immediately", "Finish build immediately", "建造秒完成");
|
|
||||||
I18N.Add("Architect mode", "Architect mode", "建筑师模式");
|
|
||||||
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("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",
|
|
||||||
"传送带信号物品生成数量格式:\n 默认为AAAABC\n 勾选替换为BCAAAA\nAAAA=生成速度,B=增产点数,C=堆叠数量");
|
|
||||||
I18N.Add("Count generations as production in statistics", "Count generations as production in statistics", "统计信息里将生成计算为产物");
|
|
||||||
I18N.Add("Count removals as consumption in statistics", "Count removals as consumption in statistics", "统计信息里将移除计算为消耗");
|
|
||||||
I18N.Add("Count all raws and intermediates in statistics","Count all raw materials in statistics", "统计信息里计算所有原料和中间产物");
|
|
||||||
I18N.Add("Remove power space limit", "Remove space limit for winds and geothermals", "移除风力发电和地热发电的间距限制");
|
|
||||||
I18N.Add("Boost wind power", "Boost wind power(x100,000)", "提升风力发电(x100,000)");
|
|
||||||
I18N.Add("Boost solar power", "Boost solar power(x100,000)", "提升太阳能发电(x100,000)");
|
|
||||||
I18N.Add("Boost fuel power", "Boost fuel power(x50,000)", "提升燃料发电(x50,000)");
|
|
||||||
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", "高速采集");
|
|
||||||
I18N.Add("Pump Anywhere", "Pump anywhere", "平地抽水");
|
|
||||||
I18N.Add("Skip bullet period", "Skip bullet period", "跳过子弹阶段");
|
|
||||||
I18N.Add("Skip absorption period", "Skip absorption period", "跳过吸收阶段");
|
|
||||||
I18N.Add("Quick absorb", "Quick absorb", "快速吸收");
|
|
||||||
I18N.Add("Eject anyway", "Eject anyway", "全球弹射");
|
|
||||||
I18N.Add("Overclock Ejectors", "Overclock Ejectors (10x)", "高速弹射器(10倍射速)");
|
|
||||||
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("Terraform without enough soil piles", "Terraform without enough soil piles", "沙土不够时依然可以整改地形");
|
|
||||||
I18N.Add("Instant hand-craft", "Instant hand-craft", "快速手动制造");
|
|
||||||
I18N.Add("Instant teleport (like that in Sandbox mode)", "Instant teleport (like that in Sandbox mode)", "快速传送(和沙盒模式一样)");
|
|
||||||
I18N.Add("Mecha and Drones/Fleets invicible", "Mecha and Drones/Fleets invicible", "机甲和战斗无人机无敌");
|
|
||||||
I18N.Add("Buildings invicible", "Buildings invincible", "建筑无敌");
|
|
||||||
I18N.Add("Enable warp without space warpers", "Enable warp without space warpers", "无需空间翘曲器即可曲速飞行");
|
|
||||||
I18N.Add("Teleport to outer space", "Teleport to outer space", "传送到外太空");
|
|
||||||
I18N.Add("Teleport to selected astronomical", "Teleport to selected astronomical", "传送到选中的天体");
|
|
||||||
I18N.Apply();
|
|
||||||
MyConfigWindow.OnUICreated += CreateUI;
|
MyConfigWindow.OnUICreated += CreateUI;
|
||||||
MyConfigWindow.OnUpdateUI += UpdateUI;
|
MyConfigWindow.OnUpdateUI += UpdateUI;
|
||||||
}
|
}
|
||||||
@@ -99,181 +43,275 @@ public static class UIConfigWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateUI(MyConfigWindow wnd, RectTransform trans)
|
private static InputField AddShellsCountInput(MyConfigWindow wnd, float x, float y, RectTransform parent, string objName)
|
||||||
|
{
|
||||||
|
var config = DysonSphereFunctions.ShellsCountForFunctions;
|
||||||
|
var count = Mathf.Clamp(config.Value, DysonSphereFunctions.MinShellsCountForFunctions, DysonSphereFunctions.MaxShellsCountForFunctions);
|
||||||
|
if (config.Value != count) config.Value = count;
|
||||||
|
|
||||||
|
InputField input = null;
|
||||||
|
input = wnd.AddInputField(x, y, parent, count.ToString(), 15, objName, onEditEnd: value =>
|
||||||
{
|
{
|
||||||
_windowTrans = trans;
|
if (!int.TryParse(value, out var parsed)) parsed = config.Value;
|
||||||
// General tab
|
parsed = Mathf.Clamp(parsed, DysonSphereFunctions.MinShellsCountForFunctions, DysonSphereFunctions.MaxShellsCountForFunctions);
|
||||||
var x = 0f;
|
config.Value = parsed;
|
||||||
var y = 10f;
|
input.text = parsed.ToString();
|
||||||
wnd.AddSplitter(trans, 10f);
|
});
|
||||||
wnd.AddTabGroup(trans, "Cheat Enabler", "tab-group-cheatenabler");
|
input.contentType = InputField.ContentType.IntegerNumber;
|
||||||
var tab1 = wnd.AddTab(_windowTrans, "General");
|
input.characterLimit = 5;
|
||||||
var cb = wnd.AddCheckBox(x, y, tab1, GamePatch.DevShortcutsEnabled, "Enable Dev Shortcuts");
|
|
||||||
x += cb.Width + 5f;
|
|
||||||
y += 6f;
|
|
||||||
wnd.AddTipsButton2(x, y, tab1, "Dev Shortcuts", "Dev Shortcuts Tips", "dev-shortcuts-tips");
|
|
||||||
x = 0;
|
|
||||||
y += 30f;
|
|
||||||
wnd.AddCheckBox(x, y, tab1, GamePatch.AbnormalDisablerEnabled, "Disable Abnormal Checks");
|
|
||||||
y += 36f;
|
|
||||||
cb = wnd.AddCheckBox(x, y, tab1, GamePatch.UnlockTechEnabled, "Unlock Tech with Key-Modifiers");
|
|
||||||
x += cb.Width + 5f;
|
|
||||||
y += 6f;
|
|
||||||
wnd.AddTipsButton2(x, y, tab1, "Unlock Tech with Key-Modifiers", "Unlock Tech with Key-Modifiers Tips", "unlock-tech-tips");
|
|
||||||
x = 0f;
|
|
||||||
y += 30f + 36f;
|
|
||||||
wnd.AddButton(x, y, 400f, tab1, "Remove all metadata consumption records", 16, "button-remove-all-metadata-consumption", PlayerFunctions.RemoveAllMetadataConsumptions);
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddButton(x, y, 400f, tab1, "Remove metadata consumption record in current game", 16, "button-remove-current-metadata-consumption", PlayerFunctions.RemoveCurrentMetadataConsumptions);
|
|
||||||
y += 36f;
|
|
||||||
_clearBanBtn = wnd.AddButton(x, y, 400f, tab1, "Clear metadata flag which bans achievements", 16, "button-clear-ban-list", PlayerFunctions.ClearMetadataBanAchievements);
|
|
||||||
x = 300f;
|
|
||||||
y = 10f;
|
|
||||||
_resignGameBtn = wnd.AddButton(x, y, 300f, tab1, "Assign gamesave to current account", 16, "resign-game-btn", () => { GameMain.data.account = AccountData.me; });
|
|
||||||
|
|
||||||
var tab2 = wnd.AddTab(_windowTrans, "Factory");
|
config.SettingChanged += OnShellsCountChanged;
|
||||||
x = 0f;
|
wnd.OnFree += () => config.SettingChanged -= OnShellsCountChanged;
|
||||||
y = 10f;
|
return input;
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.ImmediateEnabled, "Finish build immediately");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.ArchitectModeEnabled, "Architect mode");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.NoConditionEnabled, "Build without condition");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.NoCollisionEnabled, "No collision");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalGeneratorEnabled, "Belt signal generator");
|
|
||||||
x += 26f;
|
|
||||||
y += 26f;
|
|
||||||
var cb1 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalCountGenEnabled, "Count generations as production in statistics", 13);
|
|
||||||
y += 26f;
|
|
||||||
var cb2 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalCountRemEnabled, "Count removals as consumption in statistics", 13);
|
|
||||||
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;
|
|
||||||
y += 6f;
|
|
||||||
var tip1 = wnd.AddTipsButton2(x, 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");
|
|
||||||
{
|
|
||||||
FactoryPatch.BeltSignalGeneratorEnabled.SettingChanged += OnBeltSignalChanged;
|
|
||||||
wnd.OnFree += () => { FactoryPatch.BeltSignalGeneratorEnabled.SettingChanged -= OnBeltSignalChanged; };
|
|
||||||
OnBeltSignalChanged(null, null);
|
|
||||||
void OnBeltSignalChanged(object o, EventArgs e)
|
|
||||||
{
|
|
||||||
var on = FactoryPatch.BeltSignalGeneratorEnabled.Value;
|
|
||||||
cb1.gameObject.SetActive(on);
|
|
||||||
cb2.gameObject.SetActive(on);
|
|
||||||
cb3.gameObject.SetActive(on);
|
|
||||||
cb4.gameObject.SetActive(on);
|
|
||||||
tip1.gameObject.SetActive(on);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x = 350f;
|
|
||||||
y = 10f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.RemovePowerSpaceLimitEnabled, "Remove power space limit");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.WindTurbinesPowerGlobalCoverageEnabled, "Wind Turbines do global power coverage");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostWindPowerEnabled, "Boost wind power");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostSolarPowerEnabled, "Boost solar power");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostGeothermalPowerEnabled, "Boost geothermal power");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostFuelPowerEnabled, "Boost fuel power");
|
|
||||||
y += 26f;
|
|
||||||
wnd.AddText2(x + 32f, y, tab2, "Boost fuel power 2", 13);
|
|
||||||
|
|
||||||
// Planet Tab
|
void OnShellsCountChanged(object o, EventArgs e)
|
||||||
var tab3 = wnd.AddTab(_windowTrans, "Planet");
|
{
|
||||||
x = 0f;
|
var normalized = Mathf.Clamp(config.Value, DysonSphereFunctions.MinShellsCountForFunctions, DysonSphereFunctions.MaxShellsCountForFunctions);
|
||||||
y = 10f;
|
if (config.Value != normalized) config.Value = normalized;
|
||||||
wnd.AddCheckBox(x, y, tab3, ResourcePatch.InfiniteResourceEnabled, "Infinite Natural Resources");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab3, ResourcePatch.FastMiningEnabled, "Fast Mining");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab3, PlanetPatch.WaterPumpAnywhereEnabled, "Pump Anywhere");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab3, PlanetPatch.TerraformAnywayEnabled, "Terraform without enough soil piles");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab3, PlayerPatch.InstantHandCraftEnabled, "Instant hand-craft");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab3, PlayerPatch.InstantTeleportEnabled, "Instant teleport (like that in Sandbox mode)");
|
|
||||||
x = 400f;
|
|
||||||
y = 10f;
|
|
||||||
wnd.AddButton(x, y, 200f, tab3, "矿物掩埋标题", 16, "button-bury-all", () => { PlanetFunctions.BuryAllVeins(true); });
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddButton(x, y, 200f, tab3, "矿物还原标题", 16, "button-bury-restore-all", () => { PlanetFunctions.BuryAllVeins(false); });
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddButton(x, y, 200f, tab3, "铺满地基提示", 16, "button-reform-all", () =>
|
|
||||||
{
|
|
||||||
var player = GameMain.mainPlayer;
|
|
||||||
if (player == null) return;
|
|
||||||
var reformTool = player.controller.actionBuild.reformTool;
|
|
||||||
var factory = GameMain.localPlanet?.factory;
|
|
||||||
if (factory == null) return;
|
|
||||||
GameMain.localPlanet.factory.PlanetReformAll(reformTool.brushType, reformTool.brushColor, reformTool.buryVeins);
|
|
||||||
});
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddButton(x, y, 200f, tab3, "还原地形提示", 16, "button-reform-revert-all", () =>
|
|
||||||
{
|
|
||||||
var factory = GameMain.localPlanet?.factory;
|
|
||||||
if (factory == null) return;
|
|
||||||
GameMain.localPlanet.factory.PlanetReformRevert();
|
|
||||||
});
|
|
||||||
|
|
||||||
var tab4 = wnd.AddTab(_windowTrans, "Dyson Sphere");
|
var value = normalized.ToString();
|
||||||
x = 0f;
|
if (input.text != value) input.text = value;
|
||||||
y = 10f;
|
|
||||||
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.SkipBulletEnabled, "Skip bullet period");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.SkipAbsorbEnabled, "Skip absorption period");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.QuickAbsorbEnabled, "Quick absorb");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.EjectAnywayEnabled, "Eject anyway");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.OverclockEjectorEnabled, "Overclock Ejectors");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.OverclockSiloEnabled, "Overclock Silos");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.UnlockMaxOrbitRadiusEnabled, "Unlock Dyson Sphere max orbit radius");
|
|
||||||
y += 30f;
|
|
||||||
{
|
|
||||||
var slider = wnd.AddSlider(x + 20, y, tab4, DysonSpherePatch.UnlockMaxOrbitRadiusValue, new MaxOrbitRadiusValueMapper(), "##,#m").WithSmallerHandle(-40f);
|
|
||||||
DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.SettingChanged += UnlockMaxOrbitRadiusChanged;
|
|
||||||
wnd.OnFree += () => { DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.SettingChanged -= UnlockMaxOrbitRadiusChanged; };
|
|
||||||
UnlockMaxOrbitRadiusChanged(null, null);
|
|
||||||
void UnlockMaxOrbitRadiusChanged(object o, EventArgs e)
|
|
||||||
{
|
|
||||||
slider.slider.enabled = DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.Value;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
}
|
|
||||||
x = 300f;
|
|
||||||
y = 10f;
|
|
||||||
wnd.AddButton(x, y, 300f, tab4, "Complete Dyson Sphere shells instantly", 16, "button-complete-dyson-sphere-shells-instantly", DysonSphereFunctions.CompleteShellsInstantly);
|
|
||||||
|
|
||||||
var tab5 = wnd.AddTab(_windowTrans, "Mecha/Combat");
|
|
||||||
x = 0f;
|
|
||||||
y = 10f;
|
|
||||||
wnd.AddCheckBox(x, y, tab5, CombatPatch.MechaInvincibleEnabled, "Mecha and Drones/Fleets invicible");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab5, CombatPatch.BuildingsInvincibleEnabled, "Buildings invicible");
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddCheckBox(x, y, tab5, PlayerPatch.WarpWithoutSpaceWarpersEnabled, "Enable warp without space warpers");
|
|
||||||
x = 400f;
|
|
||||||
y = 10f;
|
|
||||||
wnd.AddButton(x, y, 200f, tab5, "Teleport to outer space", 16, "button-teleport-to-outer-space", PlayerFunctions.TeleportToOuterSpace);
|
|
||||||
y += 36f;
|
|
||||||
wnd.AddButton(x, y, 200f, tab5, "Teleport to selected astronomical", 16, "button-teleport-to-selected-astronomical", PlayerFunctions.TeleportToSelectedAstronomical);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CreateUI(MyConfigWindow wnd, RectTransform trans)
|
||||||
|
{
|
||||||
|
_windowTrans = trans;
|
||||||
|
// General tab
|
||||||
|
var x = 0f;
|
||||||
|
var y = 10f;
|
||||||
|
wnd.AddSplitter(trans, 10f);
|
||||||
|
wnd.AddTabGroup(trans, "Cheat Enabler", "tab-group-cheatenabler");
|
||||||
|
var tab1 = wnd.AddTab(_windowTrans, "General");
|
||||||
|
var cb = wnd.AddCheckBox(x, y, tab1, GamePatch.DevShortcutsEnabled, "Enable Dev Shortcuts");
|
||||||
|
x += cb.Width + 5f;
|
||||||
|
y += 6f;
|
||||||
|
wnd.AddTipsButton2(x, y, tab1, "Dev Shortcuts", "Dev Shortcuts Tips", "dev-shortcuts-tips");
|
||||||
|
x = 0;
|
||||||
|
y += 30f;
|
||||||
|
wnd.AddCheckBox(x, y, tab1, GamePatch.AbnormalDisablerEnabled, "Disable Abnormal Checks");
|
||||||
|
y += 36f;
|
||||||
|
cb = wnd.AddCheckBox(x, y, tab1, GamePatch.UnlockTechEnabled, "Unlock Tech with Key-Modifiers");
|
||||||
|
x += cb.Width + 5f;
|
||||||
|
y += 6f;
|
||||||
|
wnd.AddTipsButton2(x, y, tab1, "Unlock Tech with Key-Modifiers", "Unlock Tech with Key-Modifiers Tips", "unlock-tech-tips");
|
||||||
|
x = 0f;
|
||||||
|
y += 30f + 36f;
|
||||||
|
wnd.AddButton(x, y, 400f, tab1, "Remove all metadata consumption records", 16, "button-remove-all-metadata-consumption", PlayerFunctions.RemoveAllMetadataConsumptions);
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddButton(x, y, 400f, tab1, "Remove metadata consumption record in current game", 16, "button-remove-current-metadata-consumption", PlayerFunctions.RemoveCurrentMetadataConsumptions);
|
||||||
|
y += 36f;
|
||||||
|
_clearBanBtn = wnd.AddButton(x, y, 400f, tab1, "Clear metadata flag which bans achievements", 16, "button-clear-ban-list", PlayerFunctions.ClearMetadataBanAchievements);
|
||||||
|
x = 300f;
|
||||||
|
y = 10f;
|
||||||
|
_resignGameBtn = wnd.AddButton(x, y, 300f, tab1, "Assign gamesave to current account", 16, "resign-game-btn", () => { GameMain.data.account = AccountData.me; });
|
||||||
|
|
||||||
|
var tab2 = wnd.AddTab(_windowTrans, "Factory");
|
||||||
|
x = 0f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.ImmediateEnabled, "Finish build immediately");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.ArchitectModeEnabled, "Architect mode");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.NoConditionEnabled, "Build without condition");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.NoCollisionEnabled, "No collision");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalGeneratorEnabled, "Belt signal generator");
|
||||||
|
x += 26f;
|
||||||
|
y += 26f;
|
||||||
|
var cb1 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalCountGenEnabled, "Count generations as production in statistics", 13);
|
||||||
|
y += 26f;
|
||||||
|
var cb2 = wnd.AddCheckBox(x, y, tab2, FactoryPatch.BeltSignalCountRemEnabled, "Count removals as consumption in statistics", 13);
|
||||||
|
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.BeltSignalUseProliferatorEnabled, "Count proliferators used for raws/intermediates and finished products", 13);
|
||||||
|
y += 6f;
|
||||||
|
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 += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.ControlPanelRemoteLogisticsEnabled, "Retrieve/Place items from/to remote planets on logistics control panel");
|
||||||
|
{
|
||||||
|
FactoryPatch.BeltSignalGeneratorEnabled.SettingChanged += OnBeltSignalChanged;
|
||||||
|
wnd.OnFree += () => { FactoryPatch.BeltSignalGeneratorEnabled.SettingChanged -= OnBeltSignalChanged; };
|
||||||
|
OnBeltSignalChanged(null, null);
|
||||||
|
void OnBeltSignalChanged(object o, EventArgs e)
|
||||||
|
{
|
||||||
|
var on = FactoryPatch.BeltSignalGeneratorEnabled.Value;
|
||||||
|
cb1.gameObject.SetActive(on);
|
||||||
|
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;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.RemovePowerSpaceLimitEnabled, "Remove power space limit");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.WindTurbinesPowerGlobalCoverageEnabled, "Wind Turbines do global power coverage");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostWindPowerEnabled, "Boost wind power");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostSolarPowerEnabled, "Boost solar power");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostGeothermalPowerEnabled, "Boost geothermal power");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab2, FactoryPatch.BoostFuelPowerEnabled, "Boost fuel power");
|
||||||
|
y += 26f;
|
||||||
|
wnd.AddText2(x + 32f, y, tab2, "Boost fuel power 2", 13);
|
||||||
|
|
||||||
|
// Planet Tab
|
||||||
|
var tab3 = wnd.AddTab(_windowTrans, "Planet");
|
||||||
|
x = 0f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddCheckBox(x, y, tab3, ResourcePatch.InfiniteResourceEnabled, "Infinite Natural Resources");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab3, ResourcePatch.FastMiningEnabled, "Fast Mining");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab3, PlanetPatch.WaterPumpAnywhereEnabled, "Pump Anywhere");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab3, PlanetPatch.TerraformAnywayEnabled, "Terraform without enough soil piles");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab3, PlayerPatch.InstantHandCraftEnabled, "Instant hand-craft");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab3, PlayerPatch.InstantTeleportEnabled, "Instant teleport (like that in Sandbox mode)");
|
||||||
|
x = 400f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddButton(x, y, 200f, tab3, "Bury all veins", 16, "button-bury-all", () => { PlanetFunctions.BuryAllVeins(true); });
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddButton(x, y, 200f, tab3, "Restore buried veins", 16, "button-bury-restore-all", () => { PlanetFunctions.BuryAllVeins(false); });
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddButton(x, y, 200f, tab3, "Reform entire planet", 16, "button-reform-all", () =>
|
||||||
|
{
|
||||||
|
var player = GameMain.mainPlayer;
|
||||||
|
if (player == null) return;
|
||||||
|
var reformTool = player.controller.actionBuild.reformTool;
|
||||||
|
var factory = GameMain.localPlanet?.factory;
|
||||||
|
if (factory == null) return;
|
||||||
|
GameMain.localPlanet.factory.PlanetReformAll(reformTool.brushType, reformTool.brushColor, reformTool.buryVeins);
|
||||||
|
});
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddButton(x, y, 200f, tab3, "Revert planet terrain", 16, "button-reform-revert-all", () =>
|
||||||
|
{
|
||||||
|
var factory = GameMain.localPlanet?.factory;
|
||||||
|
if (factory == null) return;
|
||||||
|
GameMain.localPlanet.factory.PlanetReformRevert();
|
||||||
|
});
|
||||||
|
|
||||||
|
var tab4 = wnd.AddTab(_windowTrans, "Dyson Sphere");
|
||||||
|
x = 0f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.SkipBulletEnabled, "Skip bullet period");
|
||||||
|
y += 26f;
|
||||||
|
wnd.AddCheckBox(x + 26f, y, tab4, DysonSpherePatch.FireAllBulletsEnabled, "Fire all bullets at once", 13);
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.SkipAbsorbEnabled, "Skip absorption period");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.QuickAbsorbEnabled, "Quick absorb");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.EjectAnywayEnabled, "Eject anyway");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.OverclockEjectorEnabled, "Overclock Ejectors");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.OverclockSiloEnabled, "Overclock Silos");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab4, DysonSpherePatch.UnlockMaxOrbitRadiusEnabled, "Unlock Dyson Sphere max orbit radius");
|
||||||
|
y += 30f;
|
||||||
|
{
|
||||||
|
var slider = wnd.AddSlider(x + 20, y, tab4, DysonSpherePatch.UnlockMaxOrbitRadiusValue, new MaxOrbitRadiusValueMapper(), "##,#m").WithSmallerHandle(-40f);
|
||||||
|
DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.SettingChanged += UnlockMaxOrbitRadiusChanged;
|
||||||
|
wnd.OnFree += () => { DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.SettingChanged -= UnlockMaxOrbitRadiusChanged; };
|
||||||
|
UnlockMaxOrbitRadiusChanged(null, null);
|
||||||
|
|
||||||
|
void UnlockMaxOrbitRadiusChanged(object o, EventArgs e)
|
||||||
|
{
|
||||||
|
slider.slider.enabled = DysonSpherePatch.UnlockMaxOrbitRadiusEnabled.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x = 300f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddButton(x, y, 300f, tab4, "Complete Dyson Sphere shells instantly", 16, "button-complete-dyson-sphere-shells-instantly", DysonSphereFunctions.CompleteShellsInstantly);
|
||||||
|
y += 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 btn0 = wnd.AddButton(x, y, 300f, tab4, "Generate illegal dyson shell", 16, "button-generate-illegal-dyson-shells", () =>
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.GenerateIllegalDysonShell.Translate(), Localization.WARNINGThisOperationCanBeVerySlowContinue.Translate(), Localization.Cancel.Translate(), Localization.OK.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(Localization.GenerateIllegalDysonShell2.Translate(), Localization.WARNINGThisOperationCanBeVerySlowContinue.Translate(), Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.WARNING, null,
|
||||||
|
() => { DysonSphereFunctions.CreateIllegalDysonShellWithMaxOutputForAllLayers(); });
|
||||||
|
});
|
||||||
|
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(Localization.KeepMaxProductionShellsAndRemoveOthers.Translate(), Localization.WARNINGThisOperationIsDANGEROUSContinue.Translate(), Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.WARNING, null,
|
||||||
|
() => { DysonSphereFunctions.KeepMaxProductionShells(); });
|
||||||
|
});
|
||||||
|
y += 36f;
|
||||||
|
var btn3 = wnd.AddButton(x, y, 300f, tab4, "Duplicate shells from that with highest production", 16, "button-duplicate-shells-from-the-highest-production", () =>
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.DuplicateShellsFromThatWithHighestProduction.Translate(), Localization.WARNINGThisOperationCanBeVerySlowContinue.Translate(), Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.WARNING, null,
|
||||||
|
() => { DysonSphereFunctions.DuplicateShellsWithHighestProduction(); });
|
||||||
|
});
|
||||||
|
y += 30f;
|
||||||
|
var input1 = AddShellsCountInput(wnd, x + 20f, y, tab4, "input-shells-count-illegal");
|
||||||
|
|
||||||
|
y = originalY;
|
||||||
|
var btn4 = wnd.AddButton(x, y, 300f, tab4, "Generate illegal dyson shell quickly", 16, "button-generate-illegal-dyson-shells-quickly", () =>
|
||||||
|
{
|
||||||
|
UIMessageBox.Show(Localization.GenerateIllegalDysonShellQuickly.Translate(), Localization.WARNINGThisOperationCanBeVerySlowContinue.Translate(), Localization.Cancel.Translate(), Localization.OK.Translate(), UIMessageBox.WARNING, null,
|
||||||
|
() => { DysonSphereFunctions.CreateIllegalDysonShellQuickly(DysonSphereFunctions.ShellsCountForFunctions.Value); });
|
||||||
|
});
|
||||||
|
y += 30f;
|
||||||
|
var txt2 = wnd.AddText2(x, y, tab4, "Shells count", 15, "text-shells-count");
|
||||||
|
var input2 = AddShellsCountInput(wnd, x + txt2.preferredWidth + 5f, y, tab4, "input-shells-count-quick");
|
||||||
|
|
||||||
|
Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled.SettingChanged += onIllegalDysonShellFunctionsChanged;
|
||||||
|
wnd.OnFree += () => { Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled.SettingChanged -= onIllegalDysonShellFunctionsChanged; };
|
||||||
|
onIllegalDysonShellFunctionsChanged(null, null);
|
||||||
|
void onIllegalDysonShellFunctionsChanged(object o, EventArgs e)
|
||||||
|
{
|
||||||
|
var enabled = Functions.DysonSphereFunctions.IllegalDysonShellFunctionsEnabled.Value;
|
||||||
|
btn0.gameObject.SetActive(enabled);
|
||||||
|
btn1.gameObject.SetActive(enabled);
|
||||||
|
btn2.gameObject.SetActive(enabled);
|
||||||
|
btn3.gameObject.SetActive(enabled);
|
||||||
|
input1.gameObject.SetActive(enabled);
|
||||||
|
|
||||||
|
btn4.gameObject.SetActive(!enabled);
|
||||||
|
txt2.gameObject.SetActive(!enabled);
|
||||||
|
input2.gameObject.SetActive(!enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tab5 = wnd.AddTab(_windowTrans, "Mecha/Combat");
|
||||||
|
x = 0f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddCheckBox(x, y, tab5, CombatPatch.MechaInvincibleEnabled, "Mecha and Drones/Fleets invicible");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab5, CombatPatch.BuildingsInvincibleEnabled, "Buildings invicible");
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddCheckBox(x, y, tab5, PlayerPatch.WarpWithoutSpaceWarpersEnabled, "Enable warp without space warpers");
|
||||||
|
x = 400f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddButton(x, y, 200f, tab5, "Teleport to outer space", 16, "button-teleport-to-outer-space", PlayerFunctions.TeleportToOuterSpace);
|
||||||
|
y += 36f;
|
||||||
|
wnd.AddButton(x, y, 200f, tab5, "Teleport to selected astronomical", 16, "button-teleport-to-selected-astronomical", PlayerFunctions.TeleportToSelectedAstronomical);
|
||||||
|
}
|
||||||
|
|
||||||
private static void UpdateUI()
|
private static void UpdateUI()
|
||||||
{
|
{
|
||||||
@@ -282,6 +320,7 @@ public static class UIConfigWindow
|
|||||||
|
|
||||||
private static void UpdateButtons()
|
private static void UpdateButtons()
|
||||||
{
|
{
|
||||||
|
if (_resignGameBtn == null || _clearBanBtn == null) return;
|
||||||
var data = GameMain.data;
|
var data = GameMain.data;
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
var resignEnabled = data.account != AccountData.me;
|
var resignEnabled = data.account != AccountData.me;
|
||||||
@@ -289,6 +328,7 @@ public static class UIConfigWindow
|
|||||||
{
|
{
|
||||||
_resignGameBtn.gameObject.SetActive(resignEnabled);
|
_resignGameBtn.gameObject.SetActive(resignEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
var history = data.history;
|
var history = data.history;
|
||||||
if (history == null) return;
|
if (history == null) return;
|
||||||
var banEnabled = history.hasUsedPropertyBanAchievement;
|
var banEnabled = history.hasUsedPropertyBanAchievement;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "CheatEnabler",
|
"name": "CheatEnabler",
|
||||||
"version_number": "2.3.31",
|
"version_number": "2.4.4",
|
||||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/CheatEnabler",
|
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/CheatEnabler",
|
||||||
"description": "Add various cheat functions while disabling abnormal determinants / 添加一些作弊功能,同时屏蔽异常检测",
|
"description": "Add various cheat functions while disabling abnormal determinants / 添加一些作弊功能,同时屏蔽异常检测",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"xiaoye97-BepInEx-5.4.17",
|
"xiaoye97-BepInEx-5.4.17",
|
||||||
"soarqin-UXAssist-1.2.0"
|
"soarqin-UXAssist-1.4.0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# CompressSave
|
# CompressSave
|
||||||
|
|
||||||
#### Moved [here](https://github.com/soarqin/DSP_Mods_TO/tree/master/CompressSave)
|
Moved [to another repo](https://github.com/soarqin/DSP_Mods_TO/tree/master/CompressSave)
|
||||||
|
|||||||
+161
-59
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UXAssist", "UXAssist\UXAssist.csproj", "{9C048229-6A50-4642-BC5E-02CD39D3869A}"
|
||||||
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CheatEnabler", "CheatEnabler\CheatEnabler.csproj", "{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CheatEnabler", "CheatEnabler\CheatEnabler.csproj", "{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogisticMiner", "LogisticMiner\LogisticMiner.csproj", "{7149D717-C913-4153-9425-38CB9D087F83}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogisticMiner", "LogisticMiner\LogisticMiner.csproj", "{7149D717-C913-4153-9425-38CB9D087F83}"
|
||||||
@@ -11,90 +13,190 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dustbin", "Dustbin\Dustbin.
|
|||||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC} = {B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}
|
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC} = {B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OCBatchBuild", "OCBatchBuild\OCBatchBuild.csproj", "{E8FB30A0-29BF-4CF0-8E08-9784962A8656}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniverseGenTweaks", "UniverseGenTweaks\UniverseGenTweaks.csproj", "{9534694E-14F0-4498-852D-BBB3FCA986CD}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniverseGenTweaks", "UniverseGenTweaks\UniverseGenTweaks.csproj", "{9534694E-14F0-4498-852D-BBB3FCA986CD}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OverclockEverything", "OverclockEverything\OverclockEverything.csproj", "{0168941C-EEA6-49CF-9A67-E829FE06CF9B}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OverclockEverything", "OverclockEverything\OverclockEverything.csproj", "{0168941C-EEA6-49CF-9A67-E829FE06CF9B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MechaDronesTweaks", "MechaDronesTweaks\MechaDronesTweaks.csproj", "{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MechaDronesTweaks", "MechaDronesTweaks\MechaDronesTweaks.csproj", "{15B8BC2E-93E0-4454-8F8F-BF1FA8DC90F4}"
|
||||||
EndProject
|
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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DustbinPreloader", "DustbinPreloader\DustbinPreloader.csproj", "{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoolOpt", "PoolOpt\PoolOpt.csproj", "{8BE61246-2C9D-4088-AA33-5AFF22C5046E}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PoolOpt", "PoolOpt\PoolOpt.csproj", "{8BE61246-2C9D-4088-AA33-5AFF22C5046E}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UXAssist", "UXAssist\UXAssist.csproj", "{9C048229-6A50-4642-BC5E-02CD39D3869A}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserCloak", "UserCloak\UserCloak.csproj", "{096D2E4B-D1CE-424D-9954-C36A23E9E279}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserCloak", "UserCloak\UserCloak.csproj", "{096D2E4B-D1CE-424D-9954-C36A23E9E279}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}.Release|Any CPU.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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{7149D717-C913-4153-9425-38CB9D087F83}.Release|Any CPU.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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4EABD71D-477F-448B-801B-48F8745A3FA7}.Release|Any CPU.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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{931F0230-5941-4E49-AB19-66921AF14096}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E8FB30A0-29BF-4CF0-8E08-9784962A8656}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{9534694E-14F0-4498-852D-BBB3FCA986CD}.Release|Any CPU.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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{0168941C-EEA6-49CF-9A67-E829FE06CF9B}.Release|Any CPU.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}.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
|
|
||||||
{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B8EB3D8D-5613-42F0-9040-EAA11A38C6AC}.Release|Any CPU.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}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{8BE61246-2C9D-4088-AA33-5AFF22C5046E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{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|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.ActiveCfg = Release|Any CPU
|
||||||
{9C048229-6A50-4642-BC5E-02CD39D3869A}.Release|Any CPU.Build.0 = 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
|
||||||
|
{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.ActiveCfg = Debug|Any CPU
|
||||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{096D2E4B-D1CE-424D-9954-C36A23E9E279}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?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>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
<!-- CS0618: expected from the legacy Util forwarding facade; suppress so new warnings fail the build. -->
|
||||||
|
<NoWarn>0618</NoWarn>
|
||||||
|
<AnalysisLevel>none</AnalysisLevel>
|
||||||
|
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
|
||||||
|
<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>
|
||||||
@@ -52,7 +52,7 @@ public static class BeltSignal
|
|||||||
tex.LoadImage(fileData);
|
tex.LoadImage(fileData);
|
||||||
return tex;
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Sprite LoadEmbeddedSprite(string path, Assembly assembly = null)
|
private static Sprite LoadEmbeddedSprite(string path, Assembly assembly = null)
|
||||||
{
|
{
|
||||||
var tex = LoadEmbeddedTexture(path, assembly);
|
var tex = LoadEmbeddedTexture(path, assembly);
|
||||||
@@ -77,7 +77,7 @@ public static class BeltSignal
|
|||||||
SID = ""
|
SID = ""
|
||||||
};
|
};
|
||||||
p.name = p.Name.Translate();
|
p.name = p.Name.Translate();
|
||||||
signals.dataArray = signals.dataArray.AddItem(p).ToArray();
|
signals.dataArray = [.. signals.dataArray.AddItem(p)];
|
||||||
signals.dataIndices[p.ID] = index;
|
signals.dataIndices[p.ID] = index;
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
@@ -225,11 +225,11 @@ public static class BeltSignal
|
|||||||
int itemId;
|
int itemId;
|
||||||
if ((itemId = cargoPath.TryPickItem(belt.segIndex + belt.segPivotOffset - 5, 12, out var stack, out _)) <= 0) continue;
|
if ((itemId = cargoPath.TryPickItem(belt.segIndex + belt.segPivotOffset - 5, 12, out var stack, out _)) <= 0) continue;
|
||||||
consumeRegister[itemId] += stack;
|
consumeRegister[itemId] += stack;
|
||||||
Dustbin.CalcGetSands(itemId, stack);
|
Dustbin.CalcGetSands(itemId, stack, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-33
@@ -1,67 +1,79 @@
|
|||||||
|
<details>
|
||||||
|
<summary>Read me in English</summary>
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
* 1.4.0
|
* 1.4.0
|
||||||
* Refactorying Tank input logic codes, for better performance, and resolve a bug [#53](https://github.com/soarqin/DSP_Mods/issues/53)
|
* Refactorying Tank input logic codes, for better performance, and resolve a bug [#53](https://github.com/soarqin/DSP_Mods/issues/53)
|
||||||
+ Remove use of AssetBundle, move the belt signal icon into `Assembly Resources`, for better flexibility.
|
* Remove use of AssetBundle, move the belt signal icon into `Assembly Resources`, for better flexibility.
|
||||||
|
|
||||||
* 1.3.3
|
* 1.3.3
|
||||||
+ Support for NebulaMultiplayerModApi 2.0.0
|
* Support for NebulaMultiplayerModApi 2.0.0
|
||||||
|
|
||||||
* 1.3.2
|
* 1.3.2
|
||||||
+ Fix a display issue that the dustbin checkbox is overlapped with the filter button in storage UI.
|
* Fix a display issue that the dustbin checkbox is overlapped with the filter button in storage UI.
|
||||||
|
|
||||||
* 1.3.1
|
* 1.3.1
|
||||||
+ Support for game version 0.10.28.20759
|
* Support for game version 0.10.28.20759
|
||||||
|
|
||||||
* 1.3.0
|
* 1.3.0
|
||||||
+ Add a belt signal(you can find it in first tab of signal selection panel) as dustbin, which is the simplest way to destroy items.
|
* Add a belt signal(you can find it in first tab of signal selection panel) as dustbin, which is the simplest way to destroy items.
|
||||||
+ Reworked dustbin support for Tanks, to improve performance and resolve known bugs.
|
* Reworked dustbin support for Tanks, to improve performance and resolve known bugs.
|
||||||
- Be note that the whole tank logic is optimized which may get a slight better performance even if you don't use them as dustbin.
|
* Be note that the whole tank logic is optimized which may get a slight better performance even if you don't use them as dustbin.
|
||||||
+ Config entry for soil piless gain from destroyed items are changed to a more flexible format.
|
* Config entry for soil piless gain from destroyed items are changed to a more flexible format.
|
||||||
+ [Nebula Mupltiplayer Mod](https://dsp.thunderstore.io/package/nebula/NebulaMultiplayerMod/) and bug fixes from [ModFixerOne](https://dsp.thunderstore.io/package/starfi5h/ModFixerOne/) by [starfi5h](https://github.com/starfi5h/).
|
* [Nebula Mupltiplayer Mod](https://dsp.thunderstore.io/package/nebula/NebulaMultiplayerMod/) and bug fixes from [ModFixerOne](https://dsp.thunderstore.io/package/starfi5h/ModFixerOne/) by [starfi5h](https://github.com/starfi5h/).
|
||||||
|
|
||||||
* 1.2.1
|
* 1.2.1
|
||||||
+ Fix dynamic array bug in codes, which causes various bugs and errors.
|
* Fix dynamic array bug in codes, which causes various bugs and errors.
|
||||||
|
|
||||||
* 1.2.0
|
* 1.2.0
|
||||||
+ Use [DSPModSave](https://dsp.thunderstore.io/package/CommonAPI/DSPModSave/) to save dustbin specified data now, which fixes [#1](https://github.com/soarqin/DSP_Mods/issues/1).
|
* Use [DSPModSave](https://dsp.thunderstore.io/package/CommonAPI/DSPModSave/) to save dustbin specified data now, which fixes [#1](https://github.com/soarqin/DSP_Mods/issues/1).
|
||||||
+ Fix issue for storages on multiple planets.
|
* Fix issue for storages on multiple planets.
|
||||||
+ Fix issue for multi-level tanks.
|
* Fix issue for multi-level tanks.
|
||||||
+ Add a note in README for known bug on tank.
|
* Add a note in README for known bug on tank.
|
||||||
|
|
||||||
* 1.1.0
|
* 1.1.0
|
||||||
+ Rewrite whole plugin, make a checkbox on UI so that you can turn storages into dustbin by just ticking it.
|
* Rewrite whole plugin, make a checkbox on UI so that you can turn storages into dustbin by just ticking it.
|
||||||
+ Can turn tank into dustbin now.
|
* Can turn tank into dustbin now.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>中文读我</summary>
|
||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
* 1.4.0
|
* 1.4.0
|
||||||
+ 重构储液罐的输入逻辑代码,以提高性能并解决bug [#53](https://github.com/soarqin/DSP_Mods/issues/53)
|
* 重构储液罐的输入逻辑代码,以提高性能并解决bug [#53](https://github.com/soarqin/DSP_Mods/issues/53)
|
||||||
+ 移除了AssetBundle的使用,将传送带信号图标移入`Assembly资源`,以获得更好的灵活性
|
* 移除了AssetBundle的使用,将传送带信号图标移入`Assembly资源`,以获得更好的灵活性
|
||||||
|
|
||||||
* 1.3.3
|
* 1.3.3
|
||||||
+ 支持NebulaMultiplayerModApi 2.0.0
|
* 支持NebulaMultiplayerModApi 2.0.0
|
||||||
|
|
||||||
* 1.3.2
|
* 1.3.2
|
||||||
+ 修正了储物仓UI中的垃圾桶勾选框与筛选按钮重叠的显示问题
|
* 修正了储物仓UI中的垃圾桶勾选框与筛选按钮重叠的显示问题
|
||||||
|
|
||||||
* 1.3.1
|
* 1.3.1
|
||||||
+ 支持游戏版本 0.10.28.20759
|
* 支持游戏版本 0.10.28.20759
|
||||||
|
|
||||||
* 1.3.0
|
* 1.3.0
|
||||||
+ 添加了一个传送带信号(可以在信号选择面板的第一个页签中找到)作为垃圾桶,这是目前销毁物品最简单的方法
|
* 添加了一个传送带信号(可以在信号选择面板的第一个页签中找到)作为垃圾桶,这是目前销毁物品最简单的方法
|
||||||
+ 重写了储液罐的垃圾桶实现,以提高性能并解决已知的bug
|
* 重写了储液罐的垃圾桶实现,以提高性能并解决已知的bug
|
||||||
- 注意:整个储液罐逻辑都被优化了,即使你不把他们作为垃圾桶使用,也可能会获得轻微的性能提升
|
* 注意:整个储液罐逻辑都被优化了,即使你不把他们作为垃圾桶使用,也可能会获得轻微的性能提升
|
||||||
+ 从销毁的物品中获得沙子的配置已变为更灵活的设置项格式
|
* 从销毁的物品中获得沙子的配置已变为更灵活的设置项格式
|
||||||
+ [Nebula Mupltiplayer Mod](https://dsp.thunderstore.io/package/nebula/NebulaMultiplayerMod/)支持和Bug修正来自[starfi5h](https://github.com/starfi5h/)的[ModFixerOne](https://dsp.thunderstore.io/package/starfi5h/ModFixerOne/)
|
* [Nebula Mupltiplayer Mod](https://dsp.thunderstore.io/package/nebula/NebulaMultiplayerMod/)支持和Bug修正来自[starfi5h](https://github.com/starfi5h/)的[ModFixerOne](https://dsp.thunderstore.io/package/starfi5h/ModFixerOne/)
|
||||||
|
|
||||||
* 1.2.1
|
* 1.2.1
|
||||||
+ 修正了代码中的动态数组Bug,该Bug可能导致各种问题
|
* 修正了代码中的动态数组Bug,该Bug可能导致各种问题
|
||||||
|
|
||||||
* 1.2.0
|
* 1.2.0
|
||||||
+ 现在使用[DSPModSave](https://dsp.thunderstore.io/package/CommonAPI/DSPModSave/)来保存垃圾桶的数据,修正了[#1](https://github.com/soarqin/DSP_Mods/issues/1)
|
* 现在使用[DSPModSave](https://dsp.thunderstore.io/package/CommonAPI/DSPModSave/)来保存垃圾桶的数据,修正了[#1](https://github.com/soarqin/DSP_Mods/issues/1)
|
||||||
+ 修正了多星球上的储物仓问题
|
* 修正了多星球上的储物仓问题
|
||||||
+ 修正了多层储液罐的问题
|
* 修正了多层储液罐的问题
|
||||||
+ 在README中添加了一个已知储液罐Bug的说明
|
* 在README中添加了一个已知储液罐Bug的说明
|
||||||
|
|
||||||
* 1.1.0
|
* 1.1.0
|
||||||
+ 重写了整个插件,现在可以在仓储类建筑的UI上勾选来将其转变为垃圾桶
|
* 重写了整个插件,现在可以在仓储类建筑的UI上勾选来将其转变为垃圾桶
|
||||||
+ 现在可以将储液罐转变为垃圾桶
|
* 现在可以将储液罐转变为垃圾桶
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|||||||
+3
-3
@@ -48,7 +48,7 @@ public class Dustbin : BaseUnityPlugin, IModCanSave, IMultiplayerMod
|
|||||||
NebulaModAPI.RegisterPackets(Assembly.GetExecutingAssembly());
|
NebulaModAPI.RegisterPackets(Assembly.GetExecutingAssembly());
|
||||||
NebulaModAPI.OnPlanetLoadFinished += RequestPlanetDustbinData;
|
NebulaModAPI.OnPlanetLoadFinished += RequestPlanetDustbinData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
TankPatch.Enable(false);
|
TankPatch.Enable(false);
|
||||||
@@ -58,7 +58,7 @@ public class Dustbin : BaseUnityPlugin, IModCanSave, IMultiplayerMod
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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;
|
var sandsPerItem = itemId <= 12000 ? Dustbin.SandsFactors[itemId] : 0;
|
||||||
if (sandsPerItem <= 0) return count;
|
if (sandsPerItem <= 0) return count;
|
||||||
@@ -68,7 +68,7 @@ public class Dustbin : BaseUnityPlugin, IModCanSave, IMultiplayerMod
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IModCanSave
|
#region IModCanSave
|
||||||
private const ushort ModSaveVersion = 1;
|
private const ushort ModSaveVersion = 1;
|
||||||
|
|
||||||
public void Export(BinaryWriter w)
|
public void Export(BinaryWriter w)
|
||||||
|
|||||||
+3
-23
@@ -1,41 +1,21 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<BepInExPluginGuid>org.soardev.dustbin</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.dustbin</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - Dustbin</Description>
|
<Description>DSP MOD - Dustbin</Description>
|
||||||
<Version>1.4.0</Version>
|
<Version>1.4.0</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<PackageId>Dustbin</PackageId>
|
<PackageId>Dustbin</PackageId>
|
||||||
<RootNamespace>Dustbin</RootNamespace>
|
<RootNamespace>Dustbin</RootNamespace>
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
<PackHasChangelog>true</PackHasChangelog>
|
||||||
|
<PackUsePluginsLayout>true</PackUsePluginsLayout>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-r.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
||||||
<PackageReference Include="DysonSphereProgram.Modding.NebulaMultiplayerModApi" Version="2.0.0" />
|
<PackageReference Include="DysonSphereProgram.Modding.NebulaMultiplayerModApi" Version="2.0.0" />
|
||||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="assets/icon/signal-410.png" />
|
<EmbeddedResource Include="assets/icon/signal-410.png" />
|
||||||
</ItemGroup>
|
</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>
|
</Project>
|
||||||
|
|||||||
@@ -61,19 +61,19 @@ namespace Dustbin.NebulaSupport
|
|||||||
NebulaModAPI.MultiplayerSession.Network.SendPacket(new SyncPlanetData(Dustbin.ExportData(factory)));
|
NebulaModAPI.MultiplayerSession.Network.SendPacket(new SyncPlanetData(Dustbin.ExportData(factory)));
|
||||||
return;
|
return;
|
||||||
case < 0:
|
case < 0:
|
||||||
{
|
{
|
||||||
var tankPool = factory.factoryStorage.tankPool;
|
var tankPool = factory.factoryStorage.tankPool;
|
||||||
tankPool[-storageId].IsDustbin = packet.Enable;
|
tankPool[-storageId].IsDustbin = packet.Enable;
|
||||||
TankPatch.Reset();
|
TankPatch.Reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case > 0:
|
case > 0:
|
||||||
{
|
{
|
||||||
var storagePool = factory.factoryStorage.storagePool;
|
var storagePool = factory.factoryStorage.storagePool;
|
||||||
storagePool[storageId].IsDustbin = packet.Enable;
|
storagePool[storageId].IsDustbin = packet.Enable;
|
||||||
StoragePatch.Reset();
|
StoragePatch.Reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-4
@@ -1,18 +1,29 @@
|
|||||||
# Dustbin
|
# Dustbin
|
||||||
|
|
||||||
#### Can turn Storages and Tanks into Dustbin(Destroy incoming items)
|
<details>
|
||||||
#### 储物仓和储液罐可以转变为垃圾桶(销毁送进的物品)
|
<summary>Read me in English</summary>
|
||||||
|
|
||||||
|
***Can turn Storages and Tanks into Dustbin(Destroy incoming items)***
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
* A checkbox is added to Storages and Tanks UI, which turns them into dustbins.
|
* A checkbox is added to Storages and Tanks UI, which turns them into dustbins.
|
||||||
* Items sent into dustbins are removed immediately.
|
* Items sent into dustbins are removed immediately.
|
||||||
* Can get soil piless from destroyed items, configurable through a json encoded config entry.
|
* Can get soil piless from destroyed items, configurable through a json encoded config entry.
|
||||||
+ You can get item ID list [here](https://dsp-wiki.com/Modding:Items_IDs).
|
* You can get item ID list from [dsp-wiki](https://dsp-wiki.com/Modding:Items_IDs).
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>中文读我</summary>
|
||||||
|
|
||||||
|
***储物仓和储液罐可以转变为垃圾桶(销毁送进的物品)***
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
* 在储物仓和储液罐上增加一个垃圾桶的勾选框。
|
* 在储物仓和储液罐上增加一个垃圾桶的勾选框。
|
||||||
* 送进垃圾桶的物品会立即被移除。
|
* 送进垃圾桶的物品会立即被移除。
|
||||||
* 可以从移除的物品中获得沙子,可以通过json编码的设置项进行配置。
|
* 可以从移除的物品中获得沙子,可以通过json编码的设置项进行配置。
|
||||||
+ 可以在[这里](https://dsp-wiki.com/Modding:Items_IDs)获得物品ID列表。
|
* 可以在[这里](https://dsp-wiki.com/Modding:Items_IDs)获得物品ID列表。
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|||||||
+50
-10
@@ -13,7 +13,7 @@ public static class StoragePatch
|
|||||||
private static UI.MyCheckBox _storageDustbinCheckBox;
|
private static UI.MyCheckBox _storageDustbinCheckBox;
|
||||||
private static int _lastStorageId;
|
private static int _lastStorageId;
|
||||||
private static Harmony _patch;
|
private static Harmony _patch;
|
||||||
|
|
||||||
public static void Enable(bool on)
|
public static void Enable(bool on)
|
||||||
{
|
{
|
||||||
if (on)
|
if (on)
|
||||||
@@ -138,7 +138,7 @@ public static class StoragePatch
|
|||||||
_storageDustbinCheckBox.rectTrans.anchoredPosition3D = new Vector3(190, 57 - rectTrans.sizeDelta.y, 0);
|
_storageDustbinCheckBox.rectTrans.anchoredPosition3D = new Vector3(190, 57 - rectTrans.sizeDelta.y, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adopt fix from starfi5h's NebulaCompatiblilityAssist */
|
/* Adopt fix from starfi5h's NebulaCompatiblilityAssist */
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(UIStorageGrid), nameof(UIStorageGrid.OnStorageSizeChanged))]
|
[HarmonyPatch(typeof(UIStorageGrid), nameof(UIStorageGrid.OnStorageSizeChanged))]
|
||||||
@@ -148,25 +148,65 @@ public static class StoragePatch
|
|||||||
_lastStorageId = 0; // Refresh UI to reposition button on client side
|
_lastStorageId = 0; // Refresh UI to reposition button on client side
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.AddItem), [typeof(int), typeof(int), typeof(int), typeof(int), typeof(bool)],
|
[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])]
|
[ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal])]
|
||||||
private static IEnumerable<CodeInstruction> StorageComponent_AddItem_HarmonyTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
private static IEnumerable<CodeInstruction> StorageComponent_AddItem_HarmonyTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||||
{
|
{
|
||||||
var matcher = new CodeMatcher(instructions, generator);
|
var codes = new List<CodeInstruction>(instructions);
|
||||||
var label1 = generator.DefineLabel();
|
var matcher = new CodeMatcher(codes, generator);
|
||||||
matcher.Start().MatchForward(false,
|
|
||||||
new CodeMatch(OpCodes.Stind_I4)
|
// 找到方法开始处
|
||||||
).Advance(1).InsertAndAdvance(
|
// 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.Ldarg_0),
|
||||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(StorageComponent), nameof(StorageComponent.IsDustbin))),
|
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_1),
|
||||||
new CodeInstruction(OpCodes.Ldarg_2),
|
new CodeInstruction(OpCodes.Ldarg_2),
|
||||||
|
new CodeInstruction(OpCodes.Ldarg_3),
|
||||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Dustbin), nameof(Dustbin.CalcGetSands))),
|
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();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public static class TankPatch
|
|||||||
private static UI.MyCheckBox _tankDustbinCheckBox;
|
private static UI.MyCheckBox _tankDustbinCheckBox;
|
||||||
private static int _lastTankId;
|
private static int _lastTankId;
|
||||||
private static Harmony _patch;
|
private static Harmony _patch;
|
||||||
|
|
||||||
public static void Enable(bool on)
|
public static void Enable(bool on)
|
||||||
{
|
{
|
||||||
if (on)
|
if (on)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace DustbinPreloader;
|
|||||||
|
|
||||||
public static class Preloader
|
public static class Preloader
|
||||||
{
|
{
|
||||||
private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("Dustbin Preloader");
|
private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("Dustbin Preloader");
|
||||||
public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" };
|
public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" };
|
||||||
|
|
||||||
public static void Patch(AssemblyDefinition assembly)
|
public static void Patch(AssemblyDefinition assembly)
|
||||||
|
|||||||
@@ -1,28 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>DustbinPreloader</AssemblyName>
|
<AssemblyName>DustbinPreloader</AssemblyName>
|
||||||
<Description>DSP MOD - Prealoder for Dustbin</Description>
|
<Description>DSP MOD - Preloader for Dustbin</Description>
|
||||||
<Version>1.3.1</Version>
|
<Version>1.3.1</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<PackPreloaderTargetDir>..\Dustbin\package\patchers</PackPreloaderTargetDir>
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<details>
|
||||||
|
<summary>Read me in English</summary>
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
* 1.0.4
|
||||||
|
* Remove `Disable title screen demo scene loading`, as it is buggy in recent updates.
|
||||||
|
* Fix a bug that when tutorials are not added to the guides panel when they are hidden by this MOD.
|
||||||
|
* 1.0.3
|
||||||
|
* Add config entries to disable research completion tips/popup windows
|
||||||
|
* Add a note to README for mod compatibility on `Disable title screen demo scene loading`.
|
||||||
|
* 1.0.2
|
||||||
|
* Add a config entry to disable title screen demo scene loading
|
||||||
|
* 1.0.1
|
||||||
|
* Hide 3 more random tutorial tips popup from bottom-right panel
|
||||||
|
* 1.0.0
|
||||||
|
* Initial release
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>中文读我</summary>
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
* 1.0.4
|
||||||
|
* 移除`关闭标题画面的演示场景加载`设置,因为在最近的更新中有较多bug。
|
||||||
|
* 修复了一个bug,当教程指引被这个MOD隐藏时,它们不会被添加到教程面板。
|
||||||
|
* 1.0.3
|
||||||
|
* 增加设置项以关闭研究完成的提示/弹窗
|
||||||
|
* 在README中增加了一个关于`关闭标题画面的演示场景加载`设置的兼容性说明
|
||||||
|
* 1.0.2
|
||||||
|
* 增加设置项以关闭标题画面的演示场景加载
|
||||||
|
* 1.0.1
|
||||||
|
* 可屏蔽右下面板的3种随机提醒
|
||||||
|
* 1.0.0
|
||||||
|
* 初始版本
|
||||||
|
|
||||||
|
</details>
|
||||||
@@ -152,7 +152,7 @@ public class HideTips : BaseUnityPlugin
|
|||||||
class HideMenuDemo
|
class HideMenuDemo
|
||||||
{
|
{
|
||||||
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(DSPGame), "StartDemoGame", typeof(int))]
|
[HarmonyPatch(typeof(DSPGame), nameof(DSPGame.StartDemoGame), typeof(int))]
|
||||||
private static bool DSPGame_StartDemoGame_Prefix()
|
private static bool DSPGame_StartDemoGame_Prefix()
|
||||||
{
|
{
|
||||||
if (DSPGame.Game != null)
|
if (DSPGame.Game != null)
|
||||||
@@ -188,7 +188,7 @@ class HideMenuDemo
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(VFPreload), "IsMenuDemoLoaded")]
|
[HarmonyPatch(typeof(VFPreload), nameof(VFPreload.IsMenuDemoLoaded))]
|
||||||
private static bool VFPreload_IsMenuDemoLoaded_Prefix(ref bool __result)
|
private static bool VFPreload_IsMenuDemoLoaded_Prefix(ref bool __result)
|
||||||
{
|
{
|
||||||
__result = true;
|
__result = true;
|
||||||
@@ -196,18 +196,18 @@ class HideMenuDemo
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(DSPGame), "LateUpdate")]
|
[HarmonyPatch(typeof(DSPGame), nameof(DSPGame.LateUpdate))]
|
||||||
[HarmonyPatch(typeof(GameMain), "LateUpdate")]
|
[HarmonyPatch(typeof(GameMain), nameof(GameMain.LateUpdate))]
|
||||||
[HarmonyPatch(typeof(GameMain), "FixedUpdate")]
|
[HarmonyPatch(typeof(GameMain), nameof(GameMain.FixedUpdate))]
|
||||||
[HarmonyPatch(typeof(GameMain), "Update")]
|
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Update))]
|
||||||
[HarmonyPatch(typeof(GameCamera), "LateUpdate")]
|
[HarmonyPatch(typeof(GameCamera), nameof(GameCamera.LateUpdate))]
|
||||||
private static bool DSPGame_LateUpdate_Prefix()
|
private static bool DSPGame_LateUpdate_Prefix()
|
||||||
{
|
{
|
||||||
return !DSPGame.IsMenuDemo;
|
return !DSPGame.IsMenuDemo;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
[HarmonyPriority(Priority.First), HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(GameMain), "Begin")]
|
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
|
||||||
private static bool GameMain_Begin_Prefix()
|
private static bool GameMain_Begin_Prefix()
|
||||||
{
|
{
|
||||||
if (!DSPGame.IsMenuDemo) return true;
|
if (!DSPGame.IsMenuDemo) return true;
|
||||||
|
|||||||
@@ -1,29 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>HideTips</AssemblyName>
|
<AssemblyName>HideTips</AssemblyName>
|
||||||
<BepInExPluginGuid>org.soardev.hidetips</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.hidetips</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - HideTips</Description>
|
<Description>DSP MOD - HideTips</Description>
|
||||||
<Version>1.0.4</Version>
|
<Version>1.0.4</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<PackHasChangelog>true</PackHasChangelog>
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
</Project>
|
||||||
|
|||||||
+11
-30
@@ -1,42 +1,23 @@
|
|||||||
# HideTips
|
# HideTips
|
||||||
|
|
||||||
#### Hide/Disable various tutorial tips/messages
|
<details>
|
||||||
#### 隐藏/屏蔽各种引导提示/消息
|
<summary>Read me in English</summary>
|
||||||
|
|
||||||
## Changelog
|
***Hide/Disable various tutorial tips/messages***
|
||||||
* 1.0.4
|
|
||||||
+ Remove `Disable title screen demo scene loading`, as it is buggy in recent updates.
|
|
||||||
+ Fix a bug that when tutorials are not added to the guides panel when they are hidden by this MOD.
|
|
||||||
* 1.0.3
|
|
||||||
+ Add config entries to disable research completion tips/popup windows
|
|
||||||
+ Add a note to README for mod compatibility on `Disable title screen demo scene loading`.
|
|
||||||
* 1.0.2
|
|
||||||
+ Add a config entry to disable title screen demo scene loading
|
|
||||||
* 1.0.1
|
|
||||||
+ Hide 3 more random tutorial tips popup from bottom-right panel
|
|
||||||
* 1.0.0
|
|
||||||
+ Initial release
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
* Tips/messages that can be hidden: random-reminder, tutorial, achievement/milestone card, research completion tips/popup windows.
|
* Tips/messages that can be hidden: random-reminder, tutorial, achievement/milestone card, research completion tips/popup windows.
|
||||||
* Skip prologue for new game.
|
* Skip prologue for new game.
|
||||||
* Each type of tips/messages is configurable individually.
|
* Each type of tips/messages is configurable individually.
|
||||||
|
|
||||||
## 更新日志
|
***隐藏/屏蔽各种引导提示/消息***
|
||||||
* 1.0.4
|
|
||||||
+ 移除`关闭标题画面的演示场景加载`设置,因为在最近的更新中有较多bug。
|
</details>
|
||||||
+ 修复了一个bug,当教程指引被这个MOD隐藏时,它们不会被添加到教程面板。
|
|
||||||
* 1.0.3
|
<details>
|
||||||
+ 增加设置项以关闭研究完成的提示/弹窗
|
<summary>中文读我</summary>
|
||||||
+ 在README中增加了一个关于`关闭标题画面的演示场景加载`设置的兼容性说明
|
|
||||||
* 1.0.2
|
|
||||||
+ 增加设置项以关闭标题画面的演示场景加载
|
|
||||||
* 1.0.1
|
|
||||||
+ 可屏蔽右下面板的3种随机提醒
|
|
||||||
* 1.0.0
|
|
||||||
+ 初始版本
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
* 可以屏蔽的消息:随机提醒,教程,成就/里程碑卡片,研究完成的提示/弹窗。
|
* 可以屏蔽的消息:随机提醒,教程,成就/里程碑卡片,研究完成的提示/弹窗。
|
||||||
* 跳过新游戏引导动画。
|
* 跳过新游戏引导动画。
|
||||||
* 各种屏蔽功能都可以在配置文件里开关。
|
* 各种屏蔽功能都可以在配置文件里开关。
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|||||||
+67
-67
@@ -410,30 +410,30 @@ public static class LabOptPatchFunctions
|
|||||||
public static void SetFunctionInternal(ref LabComponent lab, bool researchMode, int recpId, int techId, SignData[] signPool, LabComponent[] labPool)
|
public static void SetFunctionInternal(ref LabComponent lab, bool researchMode, int recpId, int techId, SignData[] signPool, LabComponent[] labPool)
|
||||||
{
|
{
|
||||||
// LabOptPatch.Logger.LogDebug($"SetFunctionInternal: id={lab.id} root={(int)RootLabIdField.GetValue(lab)} research={researchMode} recp={recpId} tech={techId}");
|
// LabOptPatch.Logger.LogDebug($"SetFunctionInternal: id={lab.id} root={(int)RootLabIdField.GetValue(lab)} research={researchMode} recp={recpId} tech={techId}");
|
||||||
lab.replicating = false;
|
lab.replicating = false;
|
||||||
lab.time = 0;
|
lab.time = 0;
|
||||||
lab.hashBytes = 0;
|
lab.hashBytes = 0;
|
||||||
lab.extraHashBytes = 0;
|
lab.extraHashBytes = 0;
|
||||||
lab.extraTime = 0;
|
lab.extraTime = 0;
|
||||||
lab.extraSpeed = 0;
|
lab.extraSpeed = 0;
|
||||||
lab.extraPowerRatio = 0;
|
lab.extraPowerRatio = 0;
|
||||||
lab.productive = false;
|
lab.productive = false;
|
||||||
if (researchMode)
|
if (researchMode)
|
||||||
{
|
{
|
||||||
lab.forceAccMode = false;
|
lab.forceAccMode = false;
|
||||||
lab.researchMode = true;
|
lab.researchMode = true;
|
||||||
lab.recipeId = 0;
|
lab.recipeId = 0;
|
||||||
lab.techId = 0;
|
lab.techId = 0;
|
||||||
lab.timeSpend = 0;
|
lab.timeSpend = 0;
|
||||||
lab.extraTimeSpend = 0;
|
lab.extraTimeSpend = 0;
|
||||||
lab.requires = null;
|
lab.requires = null;
|
||||||
lab.requireCounts = null;
|
lab.requireCounts = null;
|
||||||
lab.served = null;
|
lab.served = null;
|
||||||
lab.incServed = null;
|
lab.incServed = null;
|
||||||
lab.products = null;
|
lab.products = null;
|
||||||
lab.productCounts = null;
|
lab.productCounts = null;
|
||||||
lab.produced = null;
|
lab.produced = null;
|
||||||
lab.productive = true;
|
lab.productive = true;
|
||||||
var rootLabId = lab.pcId;
|
var rootLabId = lab.pcId;
|
||||||
if (rootLabId > 0)
|
if (rootLabId > 0)
|
||||||
{
|
{
|
||||||
@@ -480,29 +480,29 @@ public static class LabOptPatchFunctions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
signPool[lab.entityId].iconId0 = (uint)lab.techId;
|
signPool[lab.entityId].iconId0 = (uint)lab.techId;
|
||||||
signPool[lab.entityId].iconType = lab.techId == 0 ? 0U : 3U;
|
signPool[lab.entityId].iconType = lab.techId == 0 ? 0U : 3U;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lab.researchMode = false;
|
lab.researchMode = false;
|
||||||
lab.recipeId = 0;
|
lab.recipeId = 0;
|
||||||
lab.techId = 0;
|
lab.techId = 0;
|
||||||
lab.matrixPoints = null;
|
lab.matrixPoints = null;
|
||||||
lab.matrixServed = null;
|
lab.matrixServed = null;
|
||||||
lab.matrixIncServed = null;
|
lab.matrixIncServed = null;
|
||||||
RecipeProto recipeProto = null;
|
RecipeProto recipeProto = null;
|
||||||
if (recpId > 0)
|
if (recpId > 0)
|
||||||
{
|
{
|
||||||
recipeProto = LDB.recipes.Select(recpId);
|
recipeProto = LDB.recipes.Select(recpId);
|
||||||
}
|
}
|
||||||
if (recipeProto != null && recipeProto.Type == ERecipeType.Research)
|
if (recipeProto != null && recipeProto.Type == ERecipeType.Research)
|
||||||
{
|
{
|
||||||
lab.recipeId = recipeProto.ID;
|
lab.recipeId = recipeProto.ID;
|
||||||
lab.speed = 10000;
|
lab.speed = 10000;
|
||||||
lab.speedOverride = lab.speed;
|
lab.speedOverride = lab.speed;
|
||||||
lab.timeSpend = recipeProto.TimeSpend * 10000;
|
lab.timeSpend = recipeProto.TimeSpend * 10000;
|
||||||
lab.extraTimeSpend = recipeProto.TimeSpend * 100000;
|
lab.extraTimeSpend = recipeProto.TimeSpend * 100000;
|
||||||
lab.productive = recipeProto.productive;
|
lab.productive = recipeProto.productive;
|
||||||
lab.forceAccMode &= lab.productive;
|
lab.forceAccMode &= lab.productive;
|
||||||
var rootLabId = lab.pcId;
|
var rootLabId = lab.pcId;
|
||||||
if (rootLabId > 0)
|
if (rootLabId > 0)
|
||||||
{
|
{
|
||||||
@@ -544,26 +544,26 @@ public static class LabOptPatchFunctions
|
|||||||
Array.Clear(lab.produced, 0, lab.produced.Length);
|
Array.Clear(lab.produced, 0, lab.produced.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lab.forceAccMode = false;
|
lab.forceAccMode = false;
|
||||||
lab.recipeId = 0;
|
lab.recipeId = 0;
|
||||||
lab.speed = 0;
|
lab.speed = 0;
|
||||||
lab.speedOverride = 0;
|
lab.speedOverride = 0;
|
||||||
lab.timeSpend = 0;
|
lab.timeSpend = 0;
|
||||||
lab.extraTimeSpend = 0;
|
lab.extraTimeSpend = 0;
|
||||||
lab.requires = null;
|
lab.requires = null;
|
||||||
lab.requireCounts = null;
|
lab.requireCounts = null;
|
||||||
lab.served = null;
|
lab.served = null;
|
||||||
lab.incServed = null;
|
lab.incServed = null;
|
||||||
lab.needs = null;
|
lab.needs = null;
|
||||||
lab.products = null;
|
lab.products = null;
|
||||||
lab.productCounts = null;
|
lab.productCounts = null;
|
||||||
lab.produced = null;
|
lab.produced = null;
|
||||||
}
|
}
|
||||||
signPool[lab.entityId].iconId0 = (uint)lab.recipeId;
|
signPool[lab.entityId].iconId0 = (uint)lab.recipeId;
|
||||||
signPool[lab.entityId].iconType = lab.recipeId == 0 ? 0U : 2U;
|
signPool[lab.entityId].iconType = lab.recipeId == 0 ? 0U : 2U;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int InsertIntoLab(PlanetFactory factory, int labId, int itemId, byte itemCount, byte itemInc, ref byte remainInc, int[] needs)
|
public static int InsertIntoLab(PlanetFactory factory, int labId, int itemId, byte itemCount, byte itemInc, ref byte remainInc, int[] needs)
|
||||||
{
|
{
|
||||||
|
|||||||
+3
-3
@@ -18,7 +18,7 @@ public class LabOptPatch : BaseUnityPlugin
|
|||||||
{
|
{
|
||||||
Harmony.CreateAndPatchAll(typeof(LabOptPatch));
|
Harmony.CreateAndPatchAll(typeof(LabOptPatch));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch LabComponent.Export() to save zero value if rootLabId > 0.
|
// Patch LabComponent.Export() to save zero value if rootLabId > 0.
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(LabComponent), nameof(LabComponent.Export))]
|
[HarmonyPatch(typeof(LabComponent), nameof(LabComponent.Export))]
|
||||||
@@ -274,7 +274,7 @@ public class LabOptPatch : BaseUnityPlugin
|
|||||||
);
|
);
|
||||||
return matcher.InstructionEnumeration();
|
return matcher.InstructionEnumeration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change locks on PlanetFactory.InsertInto(), by calling LabOptPatchFunctions.InsertIntoLab()
|
// Change locks on PlanetFactory.InsertInto(), by calling LabOptPatchFunctions.InsertIntoLab()
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.InsertInto))]
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.InsertInto))]
|
||||||
@@ -332,7 +332,7 @@ public class LabOptPatch : BaseUnityPlugin
|
|||||||
{
|
{
|
||||||
LabOptPatchFunctions.SetRootId(ref __instance, 0);
|
LabOptPatchFunctions.SetRootId(ref __instance, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyTranspiler]
|
[HarmonyTranspiler]
|
||||||
[HarmonyPatch(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetRootId))]
|
[HarmonyPatch(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetRootId))]
|
||||||
[HarmonyPatch(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetRootLabIdForStacking))]
|
[HarmonyPatch(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetRootLabIdForStacking))]
|
||||||
|
|||||||
+1
-20
@@ -1,29 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>LabOpt</AssemblyName>
|
<AssemblyName>LabOpt</AssemblyName>
|
||||||
<BepInExPluginGuid>org.soardev.labopt</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.labopt</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - LabOpt</Description>
|
<Description>DSP MOD - LabOpt</Description>
|
||||||
<Version>0.3.6</Version>
|
<Version>0.3.6</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<PackUsePluginsLayout>true</PackUsePluginsLayout>
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
</Project>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace LabOptPreloader;
|
|||||||
|
|
||||||
public static class Preloader
|
public static class Preloader
|
||||||
{
|
{
|
||||||
private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("LabOpt Preloader");
|
private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("LabOpt Preloader");
|
||||||
public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" };
|
public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" };
|
||||||
|
|
||||||
public static void Patch(AssemblyDefinition assembly)
|
public static void Patch(AssemblyDefinition assembly)
|
||||||
|
|||||||
@@ -1,28 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>LabOptPreloader</AssemblyName>
|
<AssemblyName>LabOptPreloader</AssemblyName>
|
||||||
<Description>DSP MOD - Prealoder for LabOpt</Description>
|
<Description>DSP MOD - Preloader for LabOpt</Description>
|
||||||
<Version>0.2.1</Version>
|
<Version>0.2.1</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<PackPreloaderTargetDir>..\LabOpt\package\patchers</PackPreloaderTargetDir>
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
</Project>
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
|
|
||||||
private static long _oreEnergyConsume = 2000000;
|
private static long _oreEnergyConsume = 2000000;
|
||||||
private static long _oilEnergyConsume = 3600000;
|
private static long _oilEnergyConsume = 3600000;
|
||||||
private static long _waterEnergyConsume = 20000000;
|
private static long _waterEnergyConsume = 2000000;
|
||||||
private static int _waterSpeed = 100;
|
private static int _waterSpeed = 10;
|
||||||
private static int _miningScale;
|
private static int _miningScale;
|
||||||
private static int _fuelIlsSlot = 3;
|
private static int _fuelIlsSlot = 3;
|
||||||
private static int _fuelPlsSlot = 2;
|
private static int _fuelPlsSlot = 3;
|
||||||
|
|
||||||
private static float _frame;
|
private static float _frame;
|
||||||
private static float _miningCostRateByTech;
|
private static float _miningCostRateByTech;
|
||||||
@@ -31,8 +31,8 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
private static uint _miningCostBarrierOil;
|
private static uint _miningCostBarrierOil;
|
||||||
|
|
||||||
private static uint _seed = (uint)Random.Range(int.MinValue, int.MaxValue);
|
private static uint _seed = (uint)Random.Range(int.MinValue, int.MaxValue);
|
||||||
private static readonly Dictionary<int, VeinCacheData> PlanetVeinCacheData = new();
|
private static readonly Dictionary<int, VeinCacheData> PlanetVeinCacheData = [];
|
||||||
private static readonly Dictionary<int, (long, bool)> Fuels = new();
|
private static readonly Dictionary<int, (long, bool)> Fuels = [];
|
||||||
|
|
||||||
private bool _cfgEnabled = true;
|
private bool _cfgEnabled = true;
|
||||||
|
|
||||||
@@ -52,11 +52,11 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
.Value;
|
.Value;
|
||||||
_fuelIlsSlot = Config.Bind("General", "ILSFuelSlot", _fuelIlsSlot + 1,
|
_fuelIlsSlot = Config.Bind("General", "ILSFuelSlot", _fuelIlsSlot + 1,
|
||||||
new ConfigDescription("Fuel slot for ILS, set to 0 to disable",
|
new ConfigDescription("Fuel slot for ILS, set to 0 to disable",
|
||||||
new AcceptableValueRange<int>(0, 5), Array.Empty<object>()))
|
new AcceptableValueRange<int>(0, 5), []))
|
||||||
.Value - 1;
|
.Value - 1;
|
||||||
_fuelPlsSlot = Config.Bind("General", "PLSFuelSlot", _fuelPlsSlot + 1,
|
_fuelPlsSlot = Config.Bind("General", "PLSFuelSlot", _fuelPlsSlot + 1,
|
||||||
new ConfigDescription("Fuel slot for PLS, set to 0 to disable",
|
new ConfigDescription("Fuel slot for PLS, set to 0 to disable",
|
||||||
new AcceptableValueRange<int>(0, 4), Array.Empty<object>()))
|
new AcceptableValueRange<int>(0, 4), []))
|
||||||
.Value - 1;
|
.Value - 1;
|
||||||
if (!_cfgEnabled) return;
|
if (!_cfgEnabled) return;
|
||||||
|
|
||||||
@@ -98,8 +98,8 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(DSPGame), "StartGame", typeof(GameDesc))]
|
[HarmonyPatch(typeof(DSPGame), nameof(DSPGame.StartGame), typeof(GameDesc))]
|
||||||
[HarmonyPatch(typeof(DSPGame), "StartGame", typeof(string))]
|
[HarmonyPatch(typeof(DSPGame), nameof(DSPGame.StartGame), typeof(string))]
|
||||||
private static void OnGameStart()
|
private static void OnGameStart()
|
||||||
{
|
{
|
||||||
Logger.LogInfo("Game Start");
|
Logger.LogInfo("Game Start");
|
||||||
@@ -119,7 +119,7 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(GameMain), "Start")]
|
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Start))]
|
||||||
private static void OnGameLoaded()
|
private static void OnGameLoaded()
|
||||||
{
|
{
|
||||||
_frame = 0f;
|
_frame = 0f;
|
||||||
@@ -130,7 +130,7 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(GameHistoryData), "UnlockTechFunction")]
|
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockTechFunction))]
|
||||||
private static void OnUnlockTech(int func)
|
private static void OnUnlockTech(int func)
|
||||||
{
|
{
|
||||||
switch (func)
|
switch (func)
|
||||||
@@ -145,7 +145,7 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(GameData), "GameTick")]
|
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.OnFactoryFrameBegin))]
|
||||||
private static void FrameTick()
|
private static void FrameTick()
|
||||||
{
|
{
|
||||||
var main = GameMain.instance;
|
var main = GameMain.instance;
|
||||||
@@ -165,7 +165,7 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(GameHistoryData), "UnlockRecipe")]
|
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockRecipe))]
|
||||||
private static void OnUnlockRecipe(int recipeId)
|
private static void OnUnlockRecipe(int recipeId)
|
||||||
{
|
{
|
||||||
if (recipeId == 119)
|
if (recipeId == 119)
|
||||||
@@ -175,9 +175,9 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(PlanetFactory), "Init")]
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.Init))]
|
||||||
[HarmonyPatch(typeof(PlanetFactory), "RecalculateVeinGroup")]
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateVeinGroup))]
|
||||||
[HarmonyPatch(typeof(PlanetFactory), "RecalculateAllVeinGroups")]
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateAllVeinGroups))]
|
||||||
private static void NeedRecalcVeins(PlanetFactory __instance)
|
private static void NeedRecalcVeins(PlanetFactory __instance)
|
||||||
{
|
{
|
||||||
RecalcVeins(__instance);
|
RecalcVeins(__instance);
|
||||||
@@ -204,13 +204,12 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(FactorySystem), "CheckBeforeGameTick")]
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.BeforeGameTick))]
|
||||||
private static void FactorySystemLogisticMiner(FactorySystem __instance)
|
private static void FactorySystemLogisticMiner(PlanetFactory __instance)
|
||||||
{
|
{
|
||||||
if (_miningSpeedScaleLong <= 0)
|
if (_miningSpeedScaleLong <= 0)
|
||||||
return;
|
return;
|
||||||
var factory = __instance.factory;
|
var planetId = __instance.planetId;
|
||||||
var planetId = factory.planetId;
|
|
||||||
lock (PlanetVeinCacheData)
|
lock (PlanetVeinCacheData)
|
||||||
{
|
{
|
||||||
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
||||||
@@ -227,11 +226,11 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var planetTransport = __instance.planet.factory.transport;
|
var planetTransport = __instance.transport;
|
||||||
var factoryProductionStat =
|
var factoryProductionStat =
|
||||||
GameMain.statistics.production.factoryStatPool[__instance.factory.index];
|
GameMain.statistics.production.factoryStatPool[__instance.index];
|
||||||
var productRegister = factoryProductionStat?.productRegister;
|
var productRegister = factoryProductionStat?.productRegister;
|
||||||
PerformanceMonitor.BeginSample(ECpuWorkEntry.Miner);
|
DeepProfiler.BeginSample(DPEntry.Miner);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
for (var j = 1; j < planetTransport.stationCursor; j++)
|
for (var j = 1; j < planetTransport.stationCursor; j++)
|
||||||
@@ -271,7 +270,7 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
|
|
||||||
if (isVein)
|
if (isVein)
|
||||||
{
|
{
|
||||||
(amount, energyConsume) = vcd.Mine(factory, stationStore.itemId, miningScale,
|
(amount, energyConsume) = vcd.Mine(__instance, stationStore.itemId, miningScale,
|
||||||
_miningSpeedScaleLong,
|
_miningSpeedScaleLong,
|
||||||
stationComponent.energy);
|
stationComponent.energy);
|
||||||
if (amount < 0)
|
if (amount < 0)
|
||||||
@@ -334,7 +333,7 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
vcd.FrameNext += _miningFrames;
|
vcd.FrameNext += _miningFrames;
|
||||||
} while (vcd.FrameNext <= _frame);
|
} while (vcd.FrameNext <= _frame);
|
||||||
|
|
||||||
PerformanceMonitor.EndSample(ECpuWorkEntry.Miner);
|
DeepProfiler.EndSample(DPEntry.Miner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +342,7 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
public float FrameNext;
|
public float FrameNext;
|
||||||
|
|
||||||
/* stores list of indices to veinData, with an extra INT which indicates cout of veinGroups at last */
|
/* stores list of indices to veinData, with an extra INT which indicates cout of veinGroups at last */
|
||||||
private Dictionary<int, List<int>> _veins = new();
|
private Dictionary<int, List<int>> _veins = [];
|
||||||
private int _mineIndex = -1;
|
private int _mineIndex = -1;
|
||||||
|
|
||||||
public bool HasVein(int productId)
|
public bool HasVein(int productId)
|
||||||
@@ -353,9 +352,9 @@ public class LogisticMiner : BaseUnityPlugin
|
|||||||
|
|
||||||
public void GenVeins(PlanetFactory factory)
|
public void GenVeins(PlanetFactory factory)
|
||||||
{
|
{
|
||||||
_veins = new Dictionary<int, List<int>>();
|
_veins = [];
|
||||||
var veinPool = factory.veinPool;
|
var veinPool = factory.veinPool;
|
||||||
var vg = new Dictionary<int, HashSet<int>>();
|
Dictionary<int, HashSet<int>> vg = [];
|
||||||
for (var i = 0; i < veinPool.Length; i++)
|
for (var i = 0; i < veinPool.Length; i++)
|
||||||
{
|
{
|
||||||
if (veinPool[i].amount <= 0 || veinPool[i].type == EVeinType.None) continue;
|
if (veinPool[i].amount <= 0 || veinPool[i].type == EVeinType.None) continue;
|
||||||
|
|||||||
@@ -1,25 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>LogisticMiner</AssemblyName>
|
<AssemblyName>LogisticMiner</AssemblyName>
|
||||||
<BepInExPluginGuid>org.soardev.logisticminer</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.logisticminer</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - LogisticMiner</Description>
|
<Description>DSP MOD - LogisticMiner</Description>
|
||||||
<Version>0.1.0</Version>
|
<Version>0.2.0</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
reaches Advanced Mining Machine, otherwise 100.
|
reaches Advanced Mining Machine, otherwise 100.
|
||||||
* 100/s for water by default.
|
* 100/s for water by default.
|
||||||
* Energy costs: 1MW/vein-group & 10MW/water-slot & 1.8MW/oil-seep(configurable)
|
* Energy costs: 1MW/vein-group & 10MW/water-slot & 1.8MW/oil-seep(configurable)
|
||||||
* Fuels burning slot. Default: 4th for ILS, 3rd for PLS. Set to 0 to disable it.
|
* Fuels burning slot. Default: 4th for ILS, 4th for PLS. Set to 0 to disable it.
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
@@ -47,4 +47,4 @@
|
|||||||
倍率可以设置为0(默认),此时倍率会随科技解锁而变化,默认是100%,解锁高级采矿机后变为300%。
|
倍率可以设置为0(默认),此时倍率会随科技解锁而变化,默认是100%,解锁高级采矿机后变为300%。
|
||||||
* 水的采集速度默认为100/s。
|
* 水的采集速度默认为100/s。
|
||||||
* 能耗:每矿物组 1MW,单格水 10MW,每油井 1.8MW。
|
* 能耗:每矿物组 1MW,单格水 10MW,每油井 1.8MW。
|
||||||
* 燃料格位置。默认:星际物流塔第4格,行星内物流塔第3格。设为0则关闭燃料补充能量功能。
|
* 燃料格位置。默认:星际物流塔第4格,行星内物流塔第4格。设为0则关闭燃料补充能量功能。
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "LogisticMiner",
|
"name": "LogisticMiner",
|
||||||
"version_number": "0.1.0",
|
"version_number": "0.2.0",
|
||||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LogisticMiner",
|
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LogisticMiner",
|
||||||
"description": "Logistic Storages can mine all ores/water on current planet / 物流塔可以采集当前星球的全部矿产(以及水)",
|
"description": "Logistic Storages can mine all ores/water on current planet / 物流塔可以采集当前星球的全部矿产(以及水)",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
|||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<details>
|
||||||
|
<summary>Read me in English</summary>
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
* 1.1.4
|
||||||
|
* Fixed support for game version 0.10.29
|
||||||
|
|
||||||
|
* 1.1.3
|
||||||
|
* Support for game version 0.10.28.20759+
|
||||||
|
* Fixed a minor bug that `RemoveSpeedLimitForStage1` not working while `UseFixedSpeed` set to false and `SpeedMultiplier` set to 1
|
||||||
|
|
||||||
|
* 1.1.2
|
||||||
|
* `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` and `LargerAreaForTerraform` are moved to [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
|
||||||
|
|
||||||
|
* 1.1.1
|
||||||
|
* Fixed crash in `LargeAreaForTerraform` functions.
|
||||||
|
|
||||||
|
* 1.1.0
|
||||||
|
* Added `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` and `LargerAreaForTerraform` options (Check Usage for details).
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>中文读我</summary>
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
* 1.1.4
|
||||||
|
* 修复了对游戏版本0.10.29的支持
|
||||||
|
|
||||||
|
* 1.1.3
|
||||||
|
* 支持游戏版本0.10.28.20759+
|
||||||
|
* 修复了当`UseFixedSpeed`设置为false且`SpeedMultiplier`设置为1时`RemoveSpeedLimitForStage1`无效的问题
|
||||||
|
|
||||||
|
* 1.1.2
|
||||||
|
* `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` 和 `LargerAreaForTerraform` 移动到了 MOD [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) 中
|
||||||
|
|
||||||
|
* 1.1.1
|
||||||
|
* 修复了 `LargeAreaForTerraform` 功能可能导致崩溃的问题。
|
||||||
|
|
||||||
|
* 1.1.0
|
||||||
|
* 添加了 `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` 和 `LargerAreaForTerraform` 选项 (详情见使用说明)。
|
||||||
|
|
||||||
|
</details>
|
||||||
@@ -1,29 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>MechaDronesTweaks</AssemblyName>
|
<AssemblyName>MechaDronesTweaks</AssemblyName>
|
||||||
<BepInExPluginGuid>org.soardev.mechadronestweaks</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.mechadronestweaks</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - MechaDronesTweaks</Description>
|
<Description>DSP MOD - MechaDronesTweaks</Description>
|
||||||
<Version>1.1.4</Version>
|
<Version>1.1.4</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<PackHasChangelog>true</PackHasChangelog>
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
</Project>
|
||||||
|
|||||||
+19
-22
@@ -1,26 +1,30 @@
|
|||||||
# MechaDronesTweaks
|
# MechaDronesTweaks
|
||||||
|
|
||||||
#### Some tweaks for mecha drones(Successor to FastDrones MOD)
|
<details>
|
||||||
#### 机甲建设机调整(FastDrones MOD的后继者)
|
<summary>Read me in English</summary>
|
||||||
|
|
||||||
|
***Some tweaks for mecha drones(Successor to FastDrones MOD)***
|
||||||
|
|
||||||
## Updates
|
## Updates
|
||||||
|
|
||||||
* 1.1.4
|
* 1.1.4
|
||||||
+ Fixed support for game version 0.10.29
|
* Fixed support for game version 0.10.29
|
||||||
|
|
||||||
* 1.1.3
|
* 1.1.3
|
||||||
+ Support for game version 0.10.28.20759+
|
* Support for game version 0.10.28.20759+
|
||||||
+ Fixed a minor bug that `RemoveSpeedLimitForStage1` not working while `UseFixedSpeed` set to false and `SpeedMultiplier` set to 1
|
* Fixed a minor bug that `RemoveSpeedLimitForStage1` not working while `UseFixedSpeed` set to false and `SpeedMultiplier` set to 1
|
||||||
|
|
||||||
* 1.1.2
|
* 1.1.2
|
||||||
+ `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` and `LargerAreaForTerraform` are moved to [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
|
* `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` and `LargerAreaForTerraform` are moved to [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
|
||||||
|
|
||||||
* 1.1.1
|
* 1.1.1
|
||||||
+ Fixed crash in `LargeAreaForTerraform` functions.
|
* Fixed crash in `LargeAreaForTerraform` functions.
|
||||||
|
|
||||||
* 1.1.0
|
* 1.1.0
|
||||||
+ Added `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` and `LargerAreaForTerraform` options (Check Usage for details).
|
* Added `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` and `LargerAreaForTerraform` options (Check Usage for details).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
* Inspired by [FastDrones](https://dsp.thunderstore.io/package/dkoppstein/FastDrones/), but patching IL codes, consuming less CPU to reduce lags on massive builds especially blueprints' put.
|
* Inspired by [FastDrones](https://dsp.thunderstore.io/package/dkoppstein/FastDrones/), but patching IL codes, consuming less CPU to reduce lags on massive builds especially blueprints' put.
|
||||||
* Does not affect current game-saves, which means:
|
* Does not affect current game-saves, which means:
|
||||||
* All values are patched in memory but written to game-saves so that you can play with normal mecha drone parameters while disabling this MOD.
|
* All values are patched in memory but written to game-saves so that you can play with normal mecha drone parameters while disabling this MOD.
|
||||||
@@ -37,24 +41,15 @@
|
|||||||
* `EnergyMultiplier` [Default Value: 0.1]: Energy consumption multiplier for mecha drones.
|
* `EnergyMultiplier` [Default Value: 0.1]: Energy consumption multiplier for mecha drones.
|
||||||
* Note: This MOD will disable `FastDrones` if the MOD is installed, to avoid conflict in functions.
|
* Note: This MOD will disable `FastDrones` if the MOD is installed, to avoid conflict in functions.
|
||||||
|
|
||||||
## 更新日志
|
</details>
|
||||||
* 1.1.4
|
|
||||||
+ 修复了对游戏版本0.10.29的支持
|
|
||||||
|
|
||||||
* 1.1.3
|
<details>
|
||||||
+ 支持游戏版本0.10.28.20759+
|
<summary>中文读我</summary>
|
||||||
+ 修复了当`UseFixedSpeed`设置为false且`SpeedMultiplier`设置为1时`RemoveSpeedLimitForStage1`无效的问题
|
|
||||||
|
|
||||||
* 1.1.2
|
***机甲建设机调整(FastDrones MOD的后继者)***
|
||||||
+ `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` 和 `LargerAreaForTerraform` 移动到了 MOD [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) 中
|
|
||||||
|
|
||||||
* 1.1.1
|
|
||||||
+ 修复了 `LargeAreaForTerraform` 功能可能导致崩溃的问题。
|
|
||||||
|
|
||||||
* 1.1.0
|
|
||||||
+ 添加了 `RemoveBuildRangeLimit`, `LargerAreaForUpgradeAndDismantle` 和 `LargerAreaForTerraform` 选项 (详情见使用说明)。
|
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
* 功能参考 [FastDrones](https://dsp.thunderstore.io/package/dkoppstein/FastDrones/),但主要对IL代码进行Patch因此消耗更少的CPU,尤其在大规模建造比如放置蓝图的时候可以大大减少卡顿。
|
* 功能参考 [FastDrones](https://dsp.thunderstore.io/package/dkoppstein/FastDrones/),但主要对IL代码进行Patch因此消耗更少的CPU,尤其在大规模建造比如放置蓝图的时候可以大大减少卡顿。
|
||||||
* 不影响当前游戏存档:
|
* 不影响当前游戏存档:
|
||||||
* 所有修改参数都在内存中Patch不会写入存档,禁用此MOD后可恢复正常建设机参数。
|
* 所有修改参数都在内存中Patch不会写入存档,禁用此MOD后可恢复正常建设机参数。
|
||||||
@@ -70,3 +65,5 @@
|
|||||||
* `SpeedMultiplier` [默认值: 4]: 速度倍数。
|
* `SpeedMultiplier` [默认值: 4]: 速度倍数。
|
||||||
* `EnergyMultiplier` [默认值: 0.1]: 能量消耗倍数。
|
* `EnergyMultiplier` [默认值: 0.1]: 能量消耗倍数。
|
||||||
* 说明: 如果安装了`FastDrones`本MOD会将其禁用避免功能冲突。
|
* 说明: 如果安装了`FastDrones`本MOD会将其禁用避免功能冲突。
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>OCBatchBuild</AssemblyName>
|
|
||||||
<BepInExPluginGuid>org.soardev.ocbatchbuild</BepInExPluginGuid>
|
|
||||||
<Description>DSP MOD - OCBatchBuild</Description>
|
|
||||||
<Version>1.2.0</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="*-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,129 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using BepInEx;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
namespace OCBatchBuild;
|
|
||||||
|
|
||||||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
|
||||||
public class OrbitalCollectorBatchBuild : BaseUnityPlugin
|
|
||||||
{
|
|
||||||
private new static readonly BepInEx.Logging.ManualLogSource Logger =
|
|
||||||
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
|
||||||
|
|
||||||
private bool _cfgEnabled = true;
|
|
||||||
private static int _maxBuildCount;
|
|
||||||
private static bool _instantBuild;
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
_cfgEnabled = Config.Bind("General", "Enabled", _cfgEnabled, "enable/disable this plugin").Value;
|
|
||||||
_maxBuildCount = Config.Bind("General", "MaxBuildCount", _maxBuildCount, "Maximum Orbital Collectors to build once, set to 0 to build as many as possible").Value;
|
|
||||||
_instantBuild = Config.Bind("General", "InstantBuild", _instantBuild, "Enable to make Orbital Collectors built instantly. This is thought to be game logic breaking.").Value;
|
|
||||||
Harmony.CreateAndPatchAll(typeof(OrbitalCollectorBatchBuild));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(BuildTool_Click), "CreatePrebuilds")]
|
|
||||||
private static void CreatePrebuilds(BuildTool_Click __instance)
|
|
||||||
{
|
|
||||||
/* Check Gas Planet */
|
|
||||||
if (__instance.planet.type != EPlanetType.Gas) return;
|
|
||||||
if (__instance.buildPreviews.Count == 0) return;
|
|
||||||
|
|
||||||
var buildPreview = __instance.buildPreviews[0];
|
|
||||||
/* Check if is collector station */
|
|
||||||
if (!buildPreview.desc.isCollectStation) return;
|
|
||||||
|
|
||||||
var factory = __instance.factory;
|
|
||||||
var stationPool = factory.transport.stationPool;
|
|
||||||
var entityPool = factory.entityPool;
|
|
||||||
var stationCursor = factory.transport.stationCursor;
|
|
||||||
var pos = buildPreview.lpos;
|
|
||||||
var pos2 = buildPreview.lpos2;
|
|
||||||
var itemId = buildPreview.item.ID;
|
|
||||||
var countToBuild = _maxBuildCount - 1;
|
|
||||||
if (countToBuild == 0) return;
|
|
||||||
var prebuilds = new List<int> {-buildPreview.objId};
|
|
||||||
var player = __instance.player;
|
|
||||||
var firstPos = pos;
|
|
||||||
var cellCount = PlanetGrid.DetermineLongitudeSegmentCount(0, factory.planet.aux.mainGrid.segment) * 5;
|
|
||||||
var cellRad = Math.PI / cellCount;
|
|
||||||
var distRadCount = 0;
|
|
||||||
for (var i = 1; i <= cellCount; i++)
|
|
||||||
{
|
|
||||||
pos = Maths.RotateLF(0.0, 1.0, 0.0, cellRad, pos);
|
|
||||||
if ((firstPos - pos).sqrMagnitude < 14297f) continue;
|
|
||||||
distRadCount = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (distRadCount == 0) return;
|
|
||||||
pos = firstPos;
|
|
||||||
/* rotate for a minimal distance for next OC on sphere */
|
|
||||||
pos = Maths.RotateLF(0.0, 1.0, 0.0, cellRad * distRadCount, pos);
|
|
||||||
pos2 = Maths.RotateLF(0.0, 1.0, 0.0, cellRad * distRadCount, pos2);
|
|
||||||
for (var i = distRadCount; i < cellCount && countToBuild != 0;)
|
|
||||||
{
|
|
||||||
/* Check for collision */
|
|
||||||
var collide = false;
|
|
||||||
for (var j = 1; j < stationCursor; j++)
|
|
||||||
{
|
|
||||||
if (stationPool[j] == null || stationPool[j].id != j) continue;
|
|
||||||
if ((entityPool[stationPool[j].entityId].pos - pos).sqrMagnitude >= 14297f) continue;
|
|
||||||
collide = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (collide)
|
|
||||||
{
|
|
||||||
/* rotate for a small cell on sphere */
|
|
||||||
pos = Maths.RotateLF(0.0, 1.0, 0.0, cellRad, pos);
|
|
||||||
pos2 = Maths.RotateLF(0.0, 1.0, 0.0, cellRad, pos2);
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player.inhandItemId == itemId && player.inhandItemCount > 0)
|
|
||||||
{
|
|
||||||
player.UseHandItems(1, out var _);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var count = 1;
|
|
||||||
player.package.TakeTailItems(ref itemId, ref count, out var _);
|
|
||||||
if (count == 0) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rot = Maths.SphericalRotation(pos, 0f);
|
|
||||||
var rot2 = Maths.SphericalRotation(pos2, 0f);
|
|
||||||
var prebuild = default(PrebuildData);
|
|
||||||
prebuild.protoId = (short)buildPreview.item.ID;
|
|
||||||
prebuild.modelIndex = (short)buildPreview.desc.modelIndex;
|
|
||||||
prebuild.pos = pos;
|
|
||||||
prebuild.pos2 = pos2;
|
|
||||||
prebuild.rot = rot;
|
|
||||||
prebuild.rot2 = rot2;
|
|
||||||
prebuild.pickOffset = (short)buildPreview.inputOffset;
|
|
||||||
prebuild.insertOffset = (short)buildPreview.outputOffset;
|
|
||||||
prebuild.recipeId = buildPreview.recipeId;
|
|
||||||
prebuild.filterId = buildPreview.filterId;
|
|
||||||
prebuild.InitParametersArray(buildPreview.paramCount);
|
|
||||||
for (var j = 0; j < buildPreview.paramCount; j++)
|
|
||||||
{
|
|
||||||
prebuild.parameters[j] = buildPreview.parameters[j];
|
|
||||||
}
|
|
||||||
prebuilds.Add(factory.AddPrebuildDataWithComponents(prebuild));
|
|
||||||
countToBuild--;
|
|
||||||
/* rotate for minimal distance for next OC on sphere */
|
|
||||||
pos = Maths.RotateLF(0.0, 1.0, 0.0, cellRad * distRadCount, pos);
|
|
||||||
pos2 = Maths.RotateLF(0.0, 1.0, 0.0, cellRad * distRadCount, pos2);
|
|
||||||
i += distRadCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_instantBuild) return;
|
|
||||||
foreach (var id in prebuilds)
|
|
||||||
{
|
|
||||||
factory.BuildFinally(player, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# OrbitalCollectorBatchBuild
|
|
||||||
|
|
||||||
#### Batch build Orbital Collectors
|
|
||||||
#### 轨道采集器快速批量建造
|
|
||||||
|
|
||||||
## Updates
|
|
||||||
### 1.2.0
|
|
||||||
* Support for mods that change default radius of Gas Planets, e.g. `GalacticScale`.
|
|
||||||
* Remove maximum build count limit in config.
|
|
||||||
|
|
||||||
### 1.1.0
|
|
||||||
* Add `InstantBuild` to config
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
* Build any orbital collector on a Gas Giant to trigger building all placable orbital collectors.
|
|
||||||
* Can set maximum orbital collectors to build once in config.
|
|
||||||
* Note: Collectors are placed as prebuilt status, you still need to fly around the Gas Giant to complete building. This is designed not to break much game logic.
|
|
||||||
You can set `InstantBuild` to `true` in config to make them built instantly.
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
* 在气态星球上建造任何一个轨道采集器触发所有可建造采集器的放置。
|
|
||||||
* 可以在设置文件中配置一次批量建造的最大轨道采集器数量。
|
|
||||||
* 提示:轨道采集器会处于待建造状态,你仍然需要绕行气态行星一圈以完成建造。这个机制是为了尽可能减少对原有游戏逻辑的破坏。
|
|
||||||
在配置文件里设置`InstantBuild`为`true`可以使采集器的建造立即完成。
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB |
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "OrbitalCollectorBatchBuild",
|
|
||||||
"version_number": "1.2.0",
|
|
||||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/OCBatchBuild",
|
|
||||||
"description": "Batch build Orbital Collectors / 轨道采集器快速批量建造",
|
|
||||||
"dependencies": [
|
|
||||||
"xiaoye97-BepInEx-5.4.17"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -186,7 +186,7 @@ public class Patch : BaseUnityPlugin, IModCanSave
|
|||||||
sorter.stt = sorter.stt * om / nm;
|
sorter.stt = sorter.stt * om / nm;
|
||||||
if (sorter.time > sorter.stt)
|
if (sorter.time > sorter.stt)
|
||||||
{
|
{
|
||||||
sorter.time = sorter.stt - sorter.speed;
|
sorter.time = sorter.stt - InserterComponent.speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (powerSystem == null) continue;
|
if (powerSystem == null) continue;
|
||||||
|
|||||||
@@ -1,31 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<BepInExPluginGuid>org.soardev.overclockeverything</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.overclockeverything</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - OverclockEverything</Description>
|
<Description>DSP MOD - OverclockEverything</Description>
|
||||||
<Version>1.0.0</Version>
|
<Version>1.0.0</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<PackageId>OverclockEverything</PackageId>
|
<PackageId>OverclockEverything</PackageId>
|
||||||
<RootNamespace>OverclockEverything</RootNamespace>
|
<RootNamespace>OverclockEverything</RootNamespace>
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-r.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
<PackageReference Include="DysonSphereProgram.Modding.DSPModSave" Version="1.*" />
|
||||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
|
||||||
</ItemGroup>
|
</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>
|
</Project>
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
# OverclockEverything
|
# OverclockEverything
|
||||||
|
|
||||||
#### Boost nearly all structures
|
***Boost nearly all structures***
|
||||||
#### 加速几乎所有建筑功能
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
* Boost power generation, assembling speed, belt and sorter speed.
|
* Boost power generation, assembling speed, belt and sorter speed.
|
||||||
|
|
||||||
## 使用说明
|
***加速几乎所有建筑功能***
|
||||||
|
|
||||||
* 加快发电,制造,传送带和分拣器速度。
|
* 加快发电,制造,传送带和分拣器速度。
|
||||||
|
|||||||
@@ -1,29 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>PoolOpt</AssemblyName>
|
<AssemblyName>PoolOpt</AssemblyName>
|
||||||
<BepInExPluginGuid>org.soardev.poolopt</BepInExPluginGuid>
|
<BepInExPluginGuid>org.soardev.poolopt</BepInExPluginGuid>
|
||||||
<Description>DSP MOD - PoolOpt</Description>
|
<Description>DSP MOD - PoolOpt</Description>
|
||||||
<Version>0.9.3</Version>
|
<Version>0.9.3</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="*-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>
|
</Project>
|
||||||
|
|||||||
@@ -1,67 +1,66 @@
|
|||||||
## DSP Mods by Soar Qin
|
# DSP Mods by Soar Qin
|
||||||
|
|
||||||
# [CheatEnabler](CheatEnabler)
|
## [CheatEnabler](CheatEnabler)
|
||||||
|
|
||||||
Add various cheat functions while disabling abnormal determinants
|
Add various cheat functions while disabling abnormal determinants
|
||||||
添加一些作弊功能,同时屏蔽异常检测
|
添加一些作弊功能,同时屏蔽异常检测
|
||||||
|
|
||||||
# [CompressSave](CompressSave)
|
## [CompressSave](CompressSave)
|
||||||
|
|
||||||
Moved [here](https://github.com/soarqin/DSP_Mods_TO/tree/master/CompressSave)
|
Moved [to another repo](https://github.com/soarqin/DSP_Mods_TO/tree/master/CompressSave)
|
||||||
|
|
||||||
# [LogisticMiner](LogisticMiner)
|
## [Dustbin](Dustbin)
|
||||||
|
|
||||||
Logistic Storages can mine all ores/water on current planet
|
Can turn Storages and Tanks into Dustbin(Destroy incoming items)
|
||||||
物流塔可以采集当前星球的全部矿产(以及水)
|
|
||||||
|
|
||||||
# [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
|
Hide/Disable various tutorial tips/messages
|
||||||
加速几乎所有建筑功能
|
隐藏/屏蔽各种引导提示/消息
|
||||||
|
|
||||||
# [OrbitalCollectorBatchBuild](OCBatchBuild)
|
## [LabOpt](LabOpt)
|
||||||
|
|
||||||
Batch build Orbital Collectors
|
Performance optimizations for Matrix Labs
|
||||||
轨道采集器快速批量建造
|
|
||||||
|
|
||||||
# [UniverseGenTweaks](UniverseGenTweaks)
|
|
||||||
|
|
||||||
Universe Generator Tweak
|
|
||||||
宇宙生成参数调节
|
|
||||||
|
|
||||||
# [MechaDronesTweaks](MechaDronesTweaks)
|
|
||||||
|
|
||||||
Some tweaks for mecha drones and build functions(Successor to FastDrones MOD)
|
|
||||||
机甲建设机和建设功能调整(FastDrones MOD的后继者)
|
|
||||||
|
|
||||||
# [LabOpt](LabOpt)
|
|
||||||
|
|
||||||
Performance optimizations for Matrix Labs
|
|
||||||
Marked as obsoleted temporarily, needs more investigation about LabComponent's mechanism
|
Marked as obsoleted temporarily, needs more investigation about LabComponent's mechanism
|
||||||
优化研究站性能
|
优化研究站性能
|
||||||
暂时标识为过期,需要更多关于LabComponent机制的研究
|
暂时标识为过期,需要更多关于LabComponent机制的研究
|
||||||
|
|
||||||
# [PoolOpt](PoolOpt)
|
## [LogisticMiner](LogisticMiner)
|
||||||
|
|
||||||
Optimize memory pools on loading gamesaves
|
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
|
||||||
加载游戏存档时优化内存池的使用
|
加载游戏存档时优化内存池的使用
|
||||||
|
|
||||||
# [UserCloak](UserCloak)
|
## [UniverseGenTweaks](UniverseGenTweaks)
|
||||||
|
|
||||||
Cloak(Fake) user account info
|
Universe Generator Tweak
|
||||||
|
宇宙生成参数调节
|
||||||
|
|
||||||
|
## [UserCloak](UserCloak)
|
||||||
|
|
||||||
|
Cloak(Fake) user account info
|
||||||
隐匿(伪装)用户账号信息
|
隐匿(伪装)用户账号信息
|
||||||
|
|
||||||
# [UXAssist](UXAssist)
|
## [UXAssist](UXAssist)
|
||||||
|
|
||||||
Some functions and patches for better user experience
|
Some functions and patches for better user experience
|
||||||
一些提升用户体验的功能和补丁
|
一些提升用户体验的功能和补丁
|
||||||
|
|||||||
+662
-482
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
|||||||
|
using BepInEx.Configuration;
|
||||||
|
using UXAssist.Patches.Factory;
|
||||||
|
|
||||||
|
namespace UXAssist.Common.Config;
|
||||||
|
|
||||||
|
public static class FactoryConfigProvider
|
||||||
|
{
|
||||||
|
public static ConfigEntry<bool> UnlimitInteractiveEnabled => FactoryPatch.UnlimitInteractiveEnabled;
|
||||||
|
public static ConfigEntry<bool> RemoveSomeConditionEnabled => FactoryPatch.RemoveSomeConditionEnabled;
|
||||||
|
public static ConfigEntry<bool> NightLightEnabled => FactoryPatch.NightLightEnabled;
|
||||||
|
public static ConfigEntry<float> NightLightAngleX => FactoryPatch.NightLightAngleX;
|
||||||
|
public static ConfigEntry<float> NightLightAngleY => FactoryPatch.NightLightAngleY;
|
||||||
|
public static ConfigEntry<bool> RemoveBuildRangeLimitEnabled => FactoryPatch.RemoveBuildRangeLimitEnabled;
|
||||||
|
public static ConfigEntry<bool> LargerAreaForUpgradeAndDismantleEnabled => FactoryPatch.LargerAreaForUpgradeAndDismantleEnabled;
|
||||||
|
public static ConfigEntry<bool> LargerAreaForTerraformEnabled => FactoryPatch.LargerAreaForTerraformEnabled;
|
||||||
|
public static ConfigEntry<bool> OffGridBuildingEnabled => FactoryPatch.OffGridBuildingEnabled;
|
||||||
|
public static ConfigEntry<bool> TreatStackingAsSingleEnabled => FactoryPatch.TreatStackingAsSingleEnabled;
|
||||||
|
public static ConfigEntry<bool> QuickBuildAndDismantleLabsEnabled => FactoryPatch.QuickBuildAndDismantleLabsEnabled;
|
||||||
|
public static ConfigEntry<bool> ProtectVeinsFromExhaustionEnabled => FactoryPatch.ProtectVeinsFromExhaustionEnabled;
|
||||||
|
public static ConfigEntry<bool> DoNotRenderEntitiesEnabled => FactoryPatch.DoNotRenderEntitiesEnabled;
|
||||||
|
public static ConfigEntry<bool> DoNotRenderEntitiesHideSortersEnabled => FactoryPatch.DoNotRenderEntitiesHideSortersEnabled;
|
||||||
|
public static ConfigEntry<bool> DragBuildPowerPolesEnabled => FactoryPatch.DragBuildPowerPolesEnabled;
|
||||||
|
public static ConfigEntry<bool> DragBuildPowerPolesAlternatelyEnabled => FactoryPatch.DragBuildPowerPolesAlternatelyEnabled;
|
||||||
|
public static ConfigEntry<bool> AutoConstructButtonEnabled => FactoryPatch.AutoConstructButtonEnabled;
|
||||||
|
public static ConfigEntry<bool> BeltSignalsForBuyOutEnabled => FactoryPatch.BeltSignalsForBuyOutEnabled;
|
||||||
|
public static ConfigEntry<bool> TankFastFillInAndTakeOutEnabled => FactoryPatch.TankFastFillInAndTakeOutEnabled;
|
||||||
|
public static ConfigEntry<int> TankFastFillInAndTakeOutMultiplier => FactoryPatch.TankFastFillInAndTakeOutMultiplier;
|
||||||
|
public static ConfigEntry<bool> CutConveyorBeltEnabled => FactoryPatch.CutConveyorBeltEnabled;
|
||||||
|
public static ConfigEntry<bool> TweakBuildingBufferEnabled => FactoryPatch.TweakBuildingBufferEnabled;
|
||||||
|
public static ConfigEntry<int> AssemblerBufferTimeMultiplier => FactoryPatch.AssemblerBufferTimeMultiplier;
|
||||||
|
public static ConfigEntry<int> AssemblerBufferMininumMultiplier => FactoryPatch.AssemblerBufferMininumMultiplier;
|
||||||
|
public static ConfigEntry<int> LabBufferMaxCountForAssemble => FactoryPatch.LabBufferMaxCountForAssemble;
|
||||||
|
public static ConfigEntry<int> LabBufferExtraCountForAdvancedAssemble => FactoryPatch.LabBufferExtraCountForAdvancedAssemble;
|
||||||
|
public static ConfigEntry<int> LabBufferMaxCountForResearch => FactoryPatch.LabBufferMaxCountForResearch;
|
||||||
|
public static ConfigEntry<int> ReceiverBufferCount => FactoryPatch.ReceiverBufferCount;
|
||||||
|
public static ConfigEntry<int> EjectorBufferCount => FactoryPatch.EjectorBufferCount;
|
||||||
|
public static ConfigEntry<int> SiloBufferCount => FactoryPatch.SiloBufferCount;
|
||||||
|
public static ConfigEntry<bool> ShortcutKeysForBlueprintCopyEnabled => FactoryPatch.ShortcutKeysForBlueprintCopyEnabled;
|
||||||
|
public static ConfigEntry<bool> PressShiftToTakeWholeBeltItemsEnabled => FactoryPatch.PressShiftToTakeWholeBeltItemsEnabled;
|
||||||
|
public static ConfigEntry<bool> PressShiftToTakeWholeBeltItemsIncludeBranches => FactoryPatch.PressShiftToTakeWholeBeltItemsIncludeBranches;
|
||||||
|
public static ConfigEntry<bool> PressShiftToTakeWholeBeltItemsIncludeInserters => FactoryPatch.PressShiftToTakeWholeBeltItemsIncludeInserters;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using BepInEx.Configuration;
|
||||||
|
using UXAssist.Patches.Logistics;
|
||||||
|
|
||||||
|
namespace UXAssist.Common.Config;
|
||||||
|
|
||||||
|
public static class LogisticsConfigProvider
|
||||||
|
{
|
||||||
|
public static ConfigEntry<bool> AutoConfigLogisticsEnabled => LogisticsPatch.AutoConfigLogisticsEnabled;
|
||||||
|
public static ConfigEntry<bool> AutoConfigLimitAutoReplenishCount => LogisticsPatch.AutoConfigLimitAutoReplenishCount;
|
||||||
|
public static ConfigEntry<int> AutoConfigDispenserChargePower => LogisticsPatch.AutoConfigDispenserChargePower;
|
||||||
|
public static ConfigEntry<int> AutoConfigDispenserCourierCount => LogisticsPatch.AutoConfigDispenserCourierCount;
|
||||||
|
public static ConfigEntry<int> AutoConfigBattleBaseChargePower => LogisticsPatch.AutoConfigBattleBaseChargePower;
|
||||||
|
public static ConfigEntry<int> AutoConfigPLSChargePower => LogisticsPatch.AutoConfigPLSChargePower;
|
||||||
|
public static ConfigEntry<int> AutoConfigPLSMaxTripDrone => LogisticsPatch.AutoConfigPLSMaxTripDrone;
|
||||||
|
public static ConfigEntry<int> AutoConfigPLSDroneMinDeliver => LogisticsPatch.AutoConfigPLSDroneMinDeliver;
|
||||||
|
public static ConfigEntry<int> AutoConfigPLSMinPilerValue => LogisticsPatch.AutoConfigPLSMinPilerValue;
|
||||||
|
public static ConfigEntry<int> AutoConfigPLSDroneCount => LogisticsPatch.AutoConfigPLSDroneCount;
|
||||||
|
public static ConfigEntry<bool> SetDefaultRemoteLogicToStorage => LogisticsPatch.SetDefaultRemoteLogicToStorage;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSChargePower => LogisticsPatch.AutoConfigILSChargePower;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSMaxTripDrone => LogisticsPatch.AutoConfigILSMaxTripDrone;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSMaxTripShip => LogisticsPatch.AutoConfigILSMaxTripShip;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSWarperDistance => LogisticsPatch.AutoConfigILSWarperDistance;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSDroneMinDeliver => LogisticsPatch.AutoConfigILSDroneMinDeliver;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSShipMinDeliver => LogisticsPatch.AutoConfigILSShipMinDeliver;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSMinPilerValue => LogisticsPatch.AutoConfigILSMinPilerValue;
|
||||||
|
public static ConfigEntry<bool> AutoConfigILSIncludeOrbitCollector => LogisticsPatch.AutoConfigILSIncludeOrbitCollector;
|
||||||
|
public static ConfigEntry<bool> AutoConfigILSWarperNecessary => LogisticsPatch.AutoConfigILSWarperNecessary;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSDroneCount => LogisticsPatch.AutoConfigILSDroneCount;
|
||||||
|
public static ConfigEntry<int> AutoConfigILSShipCount => LogisticsPatch.AutoConfigILSShipCount;
|
||||||
|
public static ConfigEntry<int> AutoConfigVeinCollectorHarvestSpeed => LogisticsPatch.AutoConfigVeinCollectorHarvestSpeed;
|
||||||
|
public static ConfigEntry<int> AutoConfigVeinCollectorMinPilerValue => LogisticsPatch.AutoConfigVeinCollectorMinPilerValue;
|
||||||
|
public static ConfigEntry<int> OrbitalCollectorProductLimit => LogisticsPatch.OrbitalCollectorProductLimit;
|
||||||
|
public static ConfigEntry<bool> LogisticsCapacityTweaksEnabled => LogisticsPatch.LogisticsCapacityTweaksEnabled;
|
||||||
|
public static ConfigEntry<bool> AllowOverflowInLogisticsEnabled => LogisticsPatch.AllowOverflowInLogisticsEnabled;
|
||||||
|
public static ConfigEntry<bool> GreaterPowerUsageInLogisticsEnabled => LogisticsPatch.GreaterPowerUsageInLogisticsEnabled;
|
||||||
|
public static ConfigEntry<bool> LogisticsConstrolPanelImprovementEnabled => LogisticsPatch.LogisticsConstrolPanelImprovementEnabled;
|
||||||
|
public static ConfigEntry<bool> RealtimeLogisticsInfoPanelEnabled => LogisticsPatch.RealtimeLogisticsInfoPanelEnabled;
|
||||||
|
public static ConfigEntry<bool> RealtimeLogisticsInfoPanelBarsEnabled => LogisticsPatch.RealtimeLogisticsInfoPanelBarsEnabled;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
namespace UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Geometric and pool constants used by Dyson Sphere helper functions.
|
||||||
|
/// </summary>
|
||||||
|
public static class DysonSphereConstants
|
||||||
|
{
|
||||||
|
/* Angle conversion. */
|
||||||
|
public const float RadiansToDegrees = 57.2957802f;
|
||||||
|
|
||||||
|
/* Default capacity for newly reset Dyson sphere layer pools. */
|
||||||
|
public const int DefaultLayerPoolCapacity = 64;
|
||||||
|
|
||||||
|
/* Maximum allowed vertices for a custom Dyson shell. */
|
||||||
|
public const int MaxShellVertices = 32767;
|
||||||
|
|
||||||
|
/* Minimum vertex count used as a quality guard in quick shell creation. */
|
||||||
|
public const int MinShellVertexThreshold = 32000;
|
||||||
|
|
||||||
|
/* Maximum orbit radius supported by precalculated shell triangles (m). */
|
||||||
|
public const int MaxOrbitRadius = 250000;
|
||||||
|
|
||||||
|
/* Minimum radius considered when searching for a free layer radius. */
|
||||||
|
public const int MinOrbitRadiusSearch = 4000;
|
||||||
|
|
||||||
|
/* Layer radius decrement step when looking for a free slot. */
|
||||||
|
public const int OrbitRadiusSearchStep = 10;
|
||||||
|
|
||||||
|
/* Base grid size used for shell vertex tessellation. */
|
||||||
|
public const float GridSizeBase = 80f;
|
||||||
|
|
||||||
|
/* Base radius used to derive shell grid scale (gridScale ~ (radius / base)^0.75). */
|
||||||
|
public const double GridScaleBaseRadius = 4000.0;
|
||||||
|
|
||||||
|
/* Cell point cost per vertex (cpPerVertex = gridScale^2 * 2). */
|
||||||
|
public const int CpPerVertexFactor = 2;
|
||||||
|
|
||||||
|
/* Number of candidate node positions around the orbit for max-output shell search. */
|
||||||
|
public const int MaxShellSearchNodeCount = 60;
|
||||||
|
|
||||||
|
/* Maximum triangle combinations evaluated in brute-force shell search. */
|
||||||
|
public const int MaxShellSearchCombinations = 60 * 59 * 58;
|
||||||
|
|
||||||
|
/* Seed multiplier for shell randomization. */
|
||||||
|
public const int ShellRandSeedMultiplier = 10000;
|
||||||
|
|
||||||
|
/* int.MaxValue, used as a total-cp ceiling before forcing new nodes. */
|
||||||
|
public const int TotalCpMaxCeiling = int.MaxValue;
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hard-coded item IDs used across factory and logistics patches.
|
||||||
|
/// </summary>
|
||||||
|
public static class ItemIds
|
||||||
|
{
|
||||||
|
/* Ores and basic resources */
|
||||||
|
public const int Water = 1000;
|
||||||
|
public const int Coal = 1006;
|
||||||
|
public const int SulfuricAcid = 1116;
|
||||||
|
public const int Hydrogen = 1120;
|
||||||
|
public const int Deuterium = 1121;
|
||||||
|
public const int Photon = 1208;
|
||||||
|
|
||||||
|
/* Materials used by recipes */
|
||||||
|
public const int OrganicCrystal = 1015;
|
||||||
|
public const int FireIce = 1012;
|
||||||
|
public const int CriticalPhoton = 1124;
|
||||||
|
public const int CircuitBoard = 1112; // used in proliferator mk.III recipe
|
||||||
|
public const int Steel = 1107;
|
||||||
|
public const int TitaniumGlass = 1111;
|
||||||
|
public const int GravitonLens = 1125;
|
||||||
|
|
||||||
|
/* Proliferators */
|
||||||
|
public const int ProliferatorMkI = 1141;
|
||||||
|
public const int ProliferatorMkII = 1142;
|
||||||
|
public const int ProliferatorMkIII = 1143;
|
||||||
|
|
||||||
|
/* Logistics carriers */
|
||||||
|
public const int SpaceWarper = 1126;
|
||||||
|
|
||||||
|
/* Matrices */
|
||||||
|
public const int ElectromagneticMatrix = 1202;
|
||||||
|
public const int EnergyMatrix = 1203;
|
||||||
|
public const int StructureMatrix = 1204;
|
||||||
|
public const int InformationMatrix = 1205;
|
||||||
|
public const int UniverseMatrix = 1209;
|
||||||
|
public const int Antimatter = 1210;
|
||||||
|
|
||||||
|
/* Components */
|
||||||
|
public const int PlasmaExciter = 1301;
|
||||||
|
public const int ParticleBroadband = 1305;
|
||||||
|
public const int Processor = 1401;
|
||||||
|
public const int QuantumChip = 1402;
|
||||||
|
public const int MicrocrystallineComponent = 1403;
|
||||||
|
public const int PlaneFilter = 1405;
|
||||||
|
public const int ParticleContainer = 1406;
|
||||||
|
|
||||||
|
/* Dyson sphere materials */
|
||||||
|
public const int SolarSail = 1502;
|
||||||
|
public const int FrameMaterial = 1503;
|
||||||
|
public const int DysonSphereComponent = 1802;
|
||||||
|
|
||||||
|
/* Power generators */
|
||||||
|
public const int WindTurbine = 2203;
|
||||||
|
|
||||||
|
/* Dark Fog items (combat expansion) */
|
||||||
|
public const int DarkFogMemoryUnit = 5201;
|
||||||
|
public const int DarkFogEnergyFragment = 5202;
|
||||||
|
public const int DarkFogSiliconNeuron = 5203;
|
||||||
|
public const int DarkFogNegentropySingularity = 5204;
|
||||||
|
public const int DarkFogMatterReassembler = 5205;
|
||||||
|
public const int DarkFogVirtualParticle = 5206;
|
||||||
|
|
||||||
|
/* Fuel and advanced items */
|
||||||
|
public const int HydrogenFuelRod = 6001;
|
||||||
|
public const int DeuteronFuelRod = 6002;
|
||||||
|
public const int AntimatterFuelRod = 6003;
|
||||||
|
public const int StrangeMatter = 6004;
|
||||||
|
public const int Foundation = 6005;
|
||||||
|
public const int Metaverse = 6006; // also called property/meta-data item
|
||||||
|
|
||||||
|
/* Item groups used by belt signal recipe calculations. */
|
||||||
|
public static readonly int[] ExtraOreItemIds =
|
||||||
|
[
|
||||||
|
Water, SulfuricAcid, Hydrogen, Deuterium, Photon,
|
||||||
|
DarkFogMemoryUnit, DarkFogEnergyFragment, DarkFogSiliconNeuron,
|
||||||
|
DarkFogNegentropySingularity, DarkFogMatterReassembler, DarkFogVirtualParticle
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly HashSet<int> ExtraProliferationItemIds =
|
||||||
|
[
|
||||||
|
Steel, TitaniumGlass, GravitonLens, ProliferatorMkII, ProliferatorMkIII,
|
||||||
|
ElectromagneticMatrix, EnergyMatrix, StructureMatrix, InformationMatrix,
|
||||||
|
UniverseMatrix, Antimatter, PlasmaExciter, ParticleBroadband,
|
||||||
|
Processor, QuantumChip, MicrocrystallineComponent, PlaneFilter, ParticleContainer,
|
||||||
|
SolarSail, FrameMaterial, DysonSphereComponent,
|
||||||
|
HydrogenFuelRod, AntimatterFuelRod, StrangeMatter, Foundation, Metaverse
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly HashSet<int> NoProliferationItemIds =
|
||||||
|
[
|
||||||
|
SpaceWarper, DeuteronFuelRod
|
||||||
|
];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All source items used to create 25 proliferators mk.III (not self-sprayed).
|
||||||
|
/// </summary>
|
||||||
|
public static readonly List<(int ItemId, float Count)> ProliferatorSources =
|
||||||
|
[
|
||||||
|
(OrganicCrystal, 60f),
|
||||||
|
(CriticalPhoton, 20f),
|
||||||
|
(Coal, 64f),
|
||||||
|
(FireIce, 16f),
|
||||||
|
(CircuitBoard, 32f),
|
||||||
|
(ProliferatorMkI, 64f),
|
||||||
|
(ProliferatorMkII, 40f),
|
||||||
|
(ProliferatorMkIII, 25f)
|
||||||
|
];
|
||||||
|
|
||||||
|
/* Aliases used by UXAssist belt signal buy-out logic. */
|
||||||
|
public static readonly int[] DarkFogItemIds =
|
||||||
|
[
|
||||||
|
DarkFogMemoryUnit, DarkFogVirtualParticle, DarkFogEnergyFragment,
|
||||||
|
DarkFogNegentropySingularity, DarkFogSiliconNeuron, DarkFogMatterReassembler
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
namespace UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constants used by logistics capacity and station UI patches.
|
||||||
|
/// </summary>
|
||||||
|
public static class LogisticsConstants
|
||||||
|
{
|
||||||
|
/* Default base storage capacity used by the real-time logistics panel. */
|
||||||
|
public const int DefaultLocalStorageMax = 5000;
|
||||||
|
public const int DefaultRemoteStorageMax = 10000;
|
||||||
|
|
||||||
|
/* Maximum storage when overflow-in-logistics is enabled. */
|
||||||
|
public const int OverflowStorageMax = 90000000;
|
||||||
|
|
||||||
|
/* Station storage slot limits. */
|
||||||
|
public const int DefaultStorageSlotCount = 5;
|
||||||
|
|
||||||
|
/* Key-repeat timing for keyboard-based max adjustment (in game ticks). */
|
||||||
|
public const long KeyRepeatInitialDelay = 30;
|
||||||
|
public const long KeyRepeatInterval = 4;
|
||||||
|
|
||||||
|
/* Keyboard adjustment deltas for storage max values. */
|
||||||
|
public const int SmallAdjustment = 10;
|
||||||
|
public const int MediumAdjustment = 100;
|
||||||
|
public const int LargeAdjustment = 1000;
|
||||||
|
public const int HugeAdjustment = 10000;
|
||||||
|
public const int MassiveAdjustment = 100000;
|
||||||
|
public const int GargantuanAdjustment = 1000000;
|
||||||
|
|
||||||
|
/* Rounding divisors used when scaling storage on tech unlock. */
|
||||||
|
public const int LocalStorageRounding = 50;
|
||||||
|
public const int RemoteStorageRounding = 100;
|
||||||
|
|
||||||
|
/* Charge power slider scaling factors. */
|
||||||
|
public const long ChargePowerSliderScale = 50000L;
|
||||||
|
public const long ChargePowerSliderMinScale = 500000L;
|
||||||
|
|
||||||
|
/* Mining speed slider ranges. */
|
||||||
|
public const int MinMiningSpeedBase = 10000;
|
||||||
|
public const int MaxMiningSpeedBase = 30000;
|
||||||
|
public const int MiningSpeedFineStep = 1000;
|
||||||
|
public const int MiningSpeedCoarseStep = 10000;
|
||||||
|
public const float MiningSpeedSliderMaxDefault = 20f;
|
||||||
|
public const float MiningSpeedSliderMaxExtended = 27f;
|
||||||
|
|
||||||
|
/* Dispenser / battle base charge power multiplier. */
|
||||||
|
public const double DispenserChargePowerMultiplier = 5000.0;
|
||||||
|
|
||||||
|
/* Real-time logistics panel UI dimensions. */
|
||||||
|
public const float StorageSliderWidth = 70f;
|
||||||
|
public const float StorageSliderHeight = 5f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hard-coded technology IDs used across tech patches.
|
||||||
|
/// </summary>
|
||||||
|
public static class TechIds
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base game tech for "Sorter Cargo Stacking" upgrades.
|
||||||
|
/// </summary>
|
||||||
|
public const int SorterCargoStacking = 3608;
|
||||||
|
|
||||||
|
/* Custom sorter cargo stacking techs used by UXAssist (repositioned clones). */
|
||||||
|
public const int SorterCargoStackingCustomStart = 3301;
|
||||||
|
public const int SorterCargoStackingCustomEnd = 3306;
|
||||||
|
|
||||||
|
/* Combat-related tech ranges disabled in peace mode. */
|
||||||
|
public static readonly HashSet<int> CombatTechs = CreateCombatTechs();
|
||||||
|
|
||||||
|
private static HashSet<int> CreateCombatTechs()
|
||||||
|
{
|
||||||
|
(int Start, int End)[] ranges =
|
||||||
|
[
|
||||||
|
// Explosive Unit, Crystal Explosive Unit
|
||||||
|
(1803, 1804),
|
||||||
|
// Implosion Cannon
|
||||||
|
(1807, 1807),
|
||||||
|
// Signal Tower, Planetary Defense System, Jammer Tower, Plasma Turret,
|
||||||
|
// ammo boxes, shell/missile sets, capsules, drones, corvettes, destroyers, suppressing/EM capsules
|
||||||
|
(1809, 1825),
|
||||||
|
// Auto Reconstruction Marking
|
||||||
|
(2951, 2956),
|
||||||
|
// Energy Shield
|
||||||
|
(2801, 2807),
|
||||||
|
// Kinetic Weapon Damage
|
||||||
|
(5001, 5006),
|
||||||
|
// Energy Weapon Damage
|
||||||
|
(5101, 5106),
|
||||||
|
// Explosive Weapon Damage
|
||||||
|
(5201, 5206),
|
||||||
|
// Combat Drone Damage
|
||||||
|
(5301, 5305),
|
||||||
|
// Combat Drone Attack Speed
|
||||||
|
(5401, 5405),
|
||||||
|
// Combat Drone Engine
|
||||||
|
(5601, 5605),
|
||||||
|
// Combat Drone Durability
|
||||||
|
(5701, 5705),
|
||||||
|
// Ground Squadron Expansion
|
||||||
|
(5801, 5807),
|
||||||
|
// Space Fleet Expansion
|
||||||
|
(5901, 5907),
|
||||||
|
// Enhanced Structure
|
||||||
|
(6001, 6006),
|
||||||
|
// Planetary Shield
|
||||||
|
(6101, 6106)
|
||||||
|
];
|
||||||
|
|
||||||
|
var set = new HashSet<int>();
|
||||||
|
foreach (var (start, end) in ranges)
|
||||||
|
{
|
||||||
|
for (var id = start; id <= end; id++)
|
||||||
|
{
|
||||||
|
set.Add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
namespace UXAssist.Common.GameConstants;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Galaxy generation defaults, slider limits and UI constants.
|
||||||
|
/// </summary>
|
||||||
|
public static class UniverseGenConstants
|
||||||
|
{
|
||||||
|
/* Default algorithm parameters for galaxy generation. */
|
||||||
|
public const double DefaultMinDist = 2.0;
|
||||||
|
public const double DefaultMinStep = 2.0;
|
||||||
|
public const double DefaultMaxStep = 3.2;
|
||||||
|
public const double DefaultFlatten = 0.18;
|
||||||
|
|
||||||
|
/* Vanilla game limits replaced by UniverseGenTweaks. */
|
||||||
|
public const int VanillaMaxStarCount = 80;
|
||||||
|
public const int VanillaGalaxyCapacity = 25700;
|
||||||
|
public const int VanillaSectorCapacity = 25600;
|
||||||
|
|
||||||
|
/* Expanded capacities used by UniverseGenTweaks. */
|
||||||
|
public const int ExpandedGalaxyCapacity = 102500;
|
||||||
|
public const int ExpandedSectorCapacity = 102500;
|
||||||
|
|
||||||
|
/* Maximum star count settings. */
|
||||||
|
public const int MinStarCount = 32;
|
||||||
|
public const int MaxStarCount = 1024;
|
||||||
|
public const int DefaultMaxStarCount = 128;
|
||||||
|
public const float StarCountSliderMin = 64f;
|
||||||
|
public const float StarCountSliderMax = 1024f;
|
||||||
|
public const int StarCountAlignmentMask = 7; // round up to multiple of 8
|
||||||
|
|
||||||
|
/* UIGalaxySelect custom slider limits (slider value = parameter * StepSliderScale). */
|
||||||
|
public const float StepSliderScale = 10f;
|
||||||
|
|
||||||
|
public const float MinDistSliderMin = 10f;
|
||||||
|
public const float MinDistSliderMax = 50f;
|
||||||
|
|
||||||
|
public const float MaxStepSliderMax = 100f;
|
||||||
|
|
||||||
|
public const float FlattenSliderMin = 1f;
|
||||||
|
public const float FlattenSliderMax = 50f;
|
||||||
|
public const double FlattenSliderScale = 50.0;
|
||||||
|
|
||||||
|
/* Vertical spacing between added slider rows in the galaxy select UI. */
|
||||||
|
public const float SliderRowSpacing = -36f;
|
||||||
|
|
||||||
|
/* Epic difficulty resource multiplier slider. */
|
||||||
|
public const float ResourceMultiplierSliderMax = 11f;
|
||||||
|
|
||||||
|
/* Oil multiplier thresholds used by Epic difficulty. */
|
||||||
|
public const float OilMultiplierThreshold = 0.05f;
|
||||||
|
public const float OilMultiplierBase = 0.5f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using BepInEx.Logging;
|
||||||
|
|
||||||
|
namespace UXAssist.Common;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides safe invocation helpers for game events.
|
||||||
|
/// </summary>
|
||||||
|
public static class GameEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes each handler in the action's invocation list individually,
|
||||||
|
/// logging a warning if any handler throws an exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The action to invoke.</param>
|
||||||
|
/// <param name="logger">The logger to use for warnings.</param>
|
||||||
|
/// <param name="name">The name of the event for diagnostic messages.</param>
|
||||||
|
public static void InvokeSafe(this Action action, ManualLogSource logger, string name)
|
||||||
|
{
|
||||||
|
if (action == null) return;
|
||||||
|
foreach (var d in action.GetInvocationList())
|
||||||
|
{
|
||||||
|
try { d.DynamicInvoke(); }
|
||||||
|
catch (Exception ex) { logger?.LogWarning($"GameEvent '{name}' handler failed: {ex}"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +1,58 @@
|
|||||||
using System;
|
using System;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
|
||||||
namespace UXAssist.Common;
|
namespace UXAssist.Common;
|
||||||
|
|
||||||
public class GameLogic: PatchImpl<GameLogic>
|
/// <summary>
|
||||||
|
/// Provides game lifecycle events for UXAssist and dependent mods.
|
||||||
|
/// </summary>
|
||||||
|
public class GameLogic : PatchImpl<GameLogic>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Raised after game data has finished loading.
|
||||||
|
/// </summary>
|
||||||
public static Action OnDataLoaded;
|
public static Action OnDataLoaded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when a game session begins.
|
||||||
|
/// </summary>
|
||||||
public static Action OnGameBegin;
|
public static Action OnGameBegin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when a game session ends.
|
||||||
|
/// </summary>
|
||||||
public static Action OnGameEnd;
|
public static Action OnGameEnd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Harmony postfix for <see cref="VFPreload.InvokeOnLoadWorkEnded"/>.
|
||||||
|
/// Raises <see cref="OnDataLoaded"/>.
|
||||||
|
/// </summary>
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(VFPreload), nameof(VFPreload.InvokeOnLoadWorkEnded))]
|
[HarmonyPatch(typeof(VFPreload), nameof(VFPreload.InvokeOnLoadWorkEnded))]
|
||||||
public static void VFPreload_InvokeOnLoadWorkEnded_Postfix()
|
public static void VFPreload_InvokeOnLoadWorkEnded_Postfix()
|
||||||
{
|
{
|
||||||
OnDataLoaded?.Invoke();
|
OnDataLoaded.InvokeSafe(UXAssist.Logger, nameof(OnDataLoaded));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Harmony postfix for <see cref="GameMain.Begin"/>.
|
||||||
|
/// Raises <see cref="OnGameBegin"/>.
|
||||||
|
/// </summary>
|
||||||
[HarmonyPostfix, HarmonyPriority(Priority.First)]
|
[HarmonyPostfix, HarmonyPriority(Priority.First)]
|
||||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
|
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
|
||||||
public static void GameMain_Begin_Postfix()
|
public static void GameMain_Begin_Postfix()
|
||||||
{
|
{
|
||||||
OnGameBegin?.Invoke();
|
OnGameBegin.InvokeSafe(UXAssist.Logger, nameof(OnGameBegin));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Harmony postfix for <see cref="GameMain.End"/>.
|
||||||
|
/// Raises <see cref="OnGameEnd"/>.
|
||||||
|
/// </summary>
|
||||||
[HarmonyPostfix, HarmonyPriority(Priority.Last)]
|
[HarmonyPostfix, HarmonyPriority(Priority.Last)]
|
||||||
[HarmonyPatch(typeof(GameMain), nameof(GameMain.End))]
|
[HarmonyPatch(typeof(GameMain), nameof(GameMain.End))]
|
||||||
public static void GameMain_End_Postfix()
|
public static void GameMain_End_Postfix()
|
||||||
{
|
{
|
||||||
OnGameEnd?.Invoke();
|
OnGameEnd.InvokeSafe(UXAssist.Logger, nameof(OnGameEnd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+74
-41
@@ -4,34 +4,66 @@ using HarmonyLib;
|
|||||||
|
|
||||||
namespace UXAssist.Common;
|
namespace UXAssist.Common;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides bilingual localization helpers that integrate with the game's <see cref="Localization"/> system.
|
||||||
|
/// </summary>
|
||||||
public static class I18N
|
public static class I18N
|
||||||
{
|
{
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
private static bool _dirty;
|
private static bool _dirty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked whenever the active language is applied or changed and all registered strings have been applied.
|
||||||
|
/// </summary>
|
||||||
public static Action OnInitialized;
|
public static Action OnInitialized;
|
||||||
|
|
||||||
|
private static bool _initCalled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the localization hooks with Harmony.
|
||||||
|
/// </summary>
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
|
if (_initCalled) return;
|
||||||
|
_initCalled = true;
|
||||||
Harmony.CreateAndPatchAll(typeof(I18N));
|
Harmony.CreateAndPatchAll(typeof(I18N));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the localization system has finished its initial load.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c> if localization is initialized; otherwise <c>false</c>.</returns>
|
||||||
public static bool Initialized() => _initialized;
|
public static bool Initialized() => _initialized;
|
||||||
private static readonly List<Tuple<string, string, int>> Keys = [];
|
|
||||||
private static readonly Dictionary<int, List<string>> Strings = [];
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the English and Simplified Chinese localized values for a single entry.
|
||||||
|
/// </summary>
|
||||||
|
private sealed class LocalizedString
|
||||||
|
{
|
||||||
|
public string En { get; }
|
||||||
|
public string Zh { get; }
|
||||||
|
|
||||||
|
public LocalizedString(string en, string zh)
|
||||||
|
{
|
||||||
|
En = en;
|
||||||
|
Zh = zh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, LocalizedString> Entries = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a localized string pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The lookup key.</param>
|
||||||
|
/// <param name="enus">The English text.</param>
|
||||||
|
/// <param name="zhcn">The Simplified Chinese text.</param>
|
||||||
public static void Add(string key, string enus, string zhcn = null)
|
public static void Add(string key, string enus, string zhcn = null)
|
||||||
{
|
{
|
||||||
if (zhcn == null && key == enus) return;
|
// Skip identity fallback entries: if no Chinese translation is provided and the key equals the English text,
|
||||||
Keys.Add(Tuple.Create(key, enus, -1));
|
// there is no need to register a separate entry because the key already serves as the fallback text.
|
||||||
if (Strings.TryGetValue(2052, out var zhcnList))
|
if (zhcn is null && key == enus) return;
|
||||||
{
|
Entries[key] = new LocalizedString(enus, string.IsNullOrEmpty(zhcn) ? enus : zhcn);
|
||||||
zhcnList.Add(string.IsNullOrEmpty(zhcn) ? enus : zhcn);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Strings.Add(2052, [string.IsNullOrEmpty(zhcn) ? enus : zhcn]);
|
|
||||||
}
|
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,25 +71,17 @@ public static class I18N
|
|||||||
{
|
{
|
||||||
var indexer = Localization.namesIndexer;
|
var indexer = Localization.namesIndexer;
|
||||||
var index = indexer.Count;
|
var index = indexer.Count;
|
||||||
var len = Keys.Count;
|
foreach (var key in Entries.Keys)
|
||||||
for (var i = 0; i < len; i++)
|
|
||||||
{
|
{
|
||||||
var (key, def, value) = Keys[i];
|
if (indexer.TryGetValue(key, out _)) continue;
|
||||||
if (value >= 0) continue;
|
|
||||||
if (indexer.TryGetValue(key, out var idx))
|
|
||||||
{
|
|
||||||
Keys[i] = Tuple.Create(key, def, idx);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
indexer[key] = index;
|
indexer[key] = index;
|
||||||
Keys[i] = Tuple.Create(key, def, index);
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
_dirty = false;
|
_dirty = false;
|
||||||
var strings = Localization.strings;
|
var strings = Localization.strings;
|
||||||
if (strings == null) return;
|
if (strings == null) return;
|
||||||
var len2 = strings.Length;
|
var len = strings.Length;
|
||||||
for (var i = 0; i < len2; i++)
|
for (var i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
ApplyLanguage(i);
|
ApplyLanguage(i);
|
||||||
if (i != Localization.currentLanguageIndex) continue;
|
if (i != Localization.currentLanguageIndex) continue;
|
||||||
@@ -90,31 +114,40 @@ public static class I18N
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyLength = Keys.Count;
|
var isChinese = Localization.Languages[index].lcId == 2052;
|
||||||
if (Strings.TryGetValue(Localization.Languages[index].lcId, out var list))
|
foreach (var entry in Entries)
|
||||||
{
|
{
|
||||||
for (var j = 0; j < keyLength; j++)
|
if (!Localization.namesIndexer.TryGetValue(entry.Key, out var idx)) continue;
|
||||||
{
|
strs[idx] = isChinese ? entry.Value.Zh : entry.Value.En;
|
||||||
strs[Keys[j].Item3] = list[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (var j = 0; j < keyLength; j++)
|
|
||||||
{
|
|
||||||
strs[Keys[j].Item3] = Keys[j].Item2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies any pending localization changes to the game's localization tables.
|
||||||
|
/// </summary>
|
||||||
public static void Apply()
|
public static void Apply()
|
||||||
{
|
{
|
||||||
if (!_initialized) return;
|
if (!_initialized) return;
|
||||||
if (Keys.Count == 0) return;
|
if (Entries.Count == 0) return;
|
||||||
if (!_dirty) return;
|
if (!_dirty) return;
|
||||||
ApplyIndexers();
|
ApplyIndexers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the localized text for the given key in the currently active language,
|
||||||
|
/// falling back to the key itself when no entry is registered.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The lookup key.</param>
|
||||||
|
/// <returns>The localized text, or <paramref name="key"/> if no entry exists.</returns>
|
||||||
|
internal static string Translate(string key)
|
||||||
|
{
|
||||||
|
if (!Entries.TryGetValue(key, out var loc)) return key;
|
||||||
|
var languageIndex = Localization.currentLanguageIndex;
|
||||||
|
if (languageIndex >= 0 && languageIndex < Localization.Languages.Length && Localization.Languages[languageIndex].lcId == 2052)
|
||||||
|
return loc.Zh;
|
||||||
|
return loc.En;
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPostfix, HarmonyPriority(Priority.Last), HarmonyPatch(typeof(Localization), nameof(Localization.LoadSettings))]
|
[HarmonyPostfix, HarmonyPriority(Priority.Last), HarmonyPatch(typeof(Localization), nameof(Localization.LoadSettings))]
|
||||||
private static void Localization_LoadSettings_Postfix()
|
private static void Localization_LoadSettings_Postfix()
|
||||||
{
|
{
|
||||||
@@ -122,18 +155,18 @@ public static class I18N
|
|||||||
_initialized = true;
|
_initialized = true;
|
||||||
Apply();
|
Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix, HarmonyPriority(Priority.Last), HarmonyPatch(typeof(Localization), nameof(Localization.LoadLanguage))]
|
[HarmonyPostfix, HarmonyPriority(Priority.Last), HarmonyPatch(typeof(Localization), nameof(Localization.LoadLanguage))]
|
||||||
private static void Localization_LoadLanguage_Postfix(int index)
|
private static void Localization_LoadLanguage_Postfix(int index)
|
||||||
{
|
{
|
||||||
if (!_initialized) return;
|
if (!_initialized) return;
|
||||||
ApplyLanguage(index);
|
ApplyLanguage(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix, HarmonyPriority(Priority.Last), HarmonyPatch(typeof(Localization), nameof(Localization.NotifyLanguageChange))]
|
[HarmonyPostfix, HarmonyPriority(Priority.Last), HarmonyPatch(typeof(Localization), nameof(Localization.NotifyLanguageChange))]
|
||||||
private static void Localization_NotifyLanguageChange_Postfix()
|
private static void Localization_NotifyLanguageChange_Postfix()
|
||||||
{
|
{
|
||||||
if (!_initialized) return;
|
if (!_initialized) return;
|
||||||
OnInitialized?.Invoke();
|
OnInitialized?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,470 @@
|
|||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace UXAssist.Common;
|
||||||
|
|
||||||
|
public static class I18NKeys
|
||||||
|
{
|
||||||
|
public const string Unknown = "Unknown";
|
||||||
|
public const string DoYouWantToUseMetadataToBuyoutTheFollowingTech = "Do you want to use metadata to buyout the following tech?";
|
||||||
|
public const string TheFollowingIsTheRequiredMetadataForBuyout = "The following is the required metadata for buyout:";
|
||||||
|
public const string BatchBuyoutTech = "Batch buyout tech";
|
||||||
|
public const string EnableAutoConstruct = "Enable auto-construct";
|
||||||
|
public const string DisableAutoConstruct = "Disable auto-construct";
|
||||||
|
public const string BuildingsToConstruct0 = "Buildings to construct: {0}";
|
||||||
|
public const string EnableAutoCruise = "Enable auto-cruise";
|
||||||
|
public const string DisableAutoCruise = "Disable auto-cruise";
|
||||||
|
public const string KEYOpenUXAssistConfigWindow = "KEYOpenUXAssistConfigWindow";
|
||||||
|
public const string UXAssistConfig = "UXAssist Config";
|
||||||
|
public const string NoRecentMilkywayUploadResults = "No recent milkyway upload results";
|
||||||
|
public const string Success = "Success";
|
||||||
|
public const string Failure = "Failure: ";
|
||||||
|
public const string ShowTopPlayers = "Show top players";
|
||||||
|
public const string HideTopPlayers = "Hide top players";
|
||||||
|
public const string HighYield = "High yield";
|
||||||
|
public const string Perfect = "Perfect";
|
||||||
|
public const string UnionResults = "Union results";
|
||||||
|
public const string All6BasicOres = "All 6 Basic Ores";
|
||||||
|
public const string ShowOriginalName = "Show original name";
|
||||||
|
public const string ShowDistance = "Show distance";
|
||||||
|
public const string ShowPlanetCount = "Show planet count";
|
||||||
|
public const string ShowAllInformation = "Show all information";
|
||||||
|
public const string UXAssistNoNodeToFill = "[UXAssist] No node to fill";
|
||||||
|
public const string KEYToggleDoNotRenderEntities = "KEYToggleDoNotRenderEntities";
|
||||||
|
public const string KEYOffgridForPaths = "KEYOffgridForPaths";
|
||||||
|
public const string KEYCutConveyorBelt = "KEYCutConveyorBelt";
|
||||||
|
public const string KEYDismantleBlueprintSelection = "KEYDismantleBlueprintSelection";
|
||||||
|
public const string KEYSelectAllBuildingsInBlueprintCopy = "KEYSelectAllBuildingsInBlueprintCopy";
|
||||||
|
public const string KEYUPSSpeedDown = "KEYUPSSpeedDown";
|
||||||
|
public const string KEYUPSSpeedUp = "KEYUPSSpeedUp";
|
||||||
|
public const string LogicalFrameRate0X = "Logical frame rate: {0}x";
|
||||||
|
public const string KEYShowAllStarsName = "KEYShowAllStarsName";
|
||||||
|
public const string KEYToggleAllStarsName = "KEYToggleAllStarsName";
|
||||||
|
public const string KEYToggleAutoCruise = "KEYToggleAutoCruise";
|
||||||
|
public const string AutoCruiseOn = "AutoCruiseOn";
|
||||||
|
public const string AutoCruiseOff = "AutoCruiseOff";
|
||||||
|
public const string SorterCargoStackingPrefix = "Sorter cargo stacking prefix";
|
||||||
|
public const string UXAssist = "UXAssist";
|
||||||
|
public const string General = "General";
|
||||||
|
public const string Factory = "Factory";
|
||||||
|
public const string Logistics = "Logistics";
|
||||||
|
public const string PlayerMecha = "Player/Mecha";
|
||||||
|
public const string DysonSphere = "Dyson Sphere";
|
||||||
|
public const string TechCombatUI = "Tech/Combat/UI";
|
||||||
|
public const string EnableGameWindowResize = "Enable game window resize";
|
||||||
|
public const string RemeberWindowPositionAndSizeOnLastExit = "Remeber window position and size on last exit";
|
||||||
|
public const string BetterAutoSaveMechanism = "Better auto-save mechanism";
|
||||||
|
public const string BetterAutoSaveMechanismTips = "Better auto-save mechanism tips";
|
||||||
|
public const string ConvertOldSavesToCombatModeOnLoading = "Convert old saves to Combat Mode on loading";
|
||||||
|
public const string ProfileBasedSaveFolder = "Profile-based save folder";
|
||||||
|
public const string ProfileBasedSaveFolderTips = "Profile-based save folder tips";
|
||||||
|
public const string ProfileBasedOption = "Profile-based option";
|
||||||
|
public const string ProfileBasedOptionTips = "Profile-based option tips";
|
||||||
|
public const string DefaultProfileName = "Default profile name";
|
||||||
|
public const string LogicalFrameRate = "Logical Frame Rate";
|
||||||
|
public const string Reset = "Reset";
|
||||||
|
public const string ProcessPriority = "Process priority";
|
||||||
|
public const string High = "High";
|
||||||
|
public const string AboveNormal = "Above Normal";
|
||||||
|
public const string Normal = "Normal";
|
||||||
|
public const string BelowNormal = "Below Normal";
|
||||||
|
public const string Idle = "Idle";
|
||||||
|
public const string ShowRecentMilkywayUploadResults = "Show recent milkyway upload results";
|
||||||
|
public const string UnlimitedInteractiveRange = "Unlimited interactive range";
|
||||||
|
public const string NightLight = "Night Light";
|
||||||
|
public const string AngleX = "Angle X:";
|
||||||
|
public const string RemoveSomeBuildConditions = "Remove some build conditions";
|
||||||
|
public const string RemoveBuildRangeLimit = "Remove build range limit";
|
||||||
|
public const string LargerAreaForUpgradeAndDismantle = "Larger area for upgrade and dismantle";
|
||||||
|
public const string LargerAreaForTerraform = "Larger area for terraform";
|
||||||
|
public const string OffGridBuildingAndSteppedRotation = "Off-grid building and stepped rotation";
|
||||||
|
public const string EnablePlayerActionsInGlobeView = "Enable player actions in globe view";
|
||||||
|
public const string HideTipsForSoilPilesChanges = "Hide tips for soil piles changes";
|
||||||
|
public const string EnhancedCountControlForHandMake = "Enhanced count control for hand-make";
|
||||||
|
public const string EnhancedCountControlForHandMakeTips = "Enhanced count control for hand-make tips";
|
||||||
|
public const string QuickBuildAndDismantleStackingLabs = "Quick build and dismantle stacking labs";
|
||||||
|
public const string FastFillInToAndTakeOutFromTanks = "Fast fill in to and take out from tanks";
|
||||||
|
public const string SpeedRatio = "Speed Ratio";
|
||||||
|
public const string CutConveyorBeltWithShortcutKey = "Cut conveyor belt (with shortcut key)";
|
||||||
|
public const string ProtectVeinsFromExhaustion = "Protect veins from exhaustion";
|
||||||
|
public const string ProtectVeinsFromExhaustionTips = "Protect veins from exhaustion tips";
|
||||||
|
public const string DoNotRenderFactoryEntities = "Do not render factory entities";
|
||||||
|
public const string HideSortersToo = "Hide sorters too";
|
||||||
|
public const string DragBuildingPowerPolesInMaximumConnectionRange = "Drag building power poles in maximum connection range";
|
||||||
|
public const string BuildTeslaTowerAndWirelessPowerTowerAlternately = "Build Tesla Tower and Wireless Power Tower alternately";
|
||||||
|
public const string AutoConstructButton = "Auto-construct button";
|
||||||
|
public const string BeltSignalsForBuyOutDarkFogItemsAutomatically = "Belt signals for buy out dark fog items automatically";
|
||||||
|
public const string MemoryUnit = "Memory Unit";
|
||||||
|
public const string EnergyFragment = "Energy Fragment";
|
||||||
|
public const string SiliconNeuron = "Silicon Neuron";
|
||||||
|
public const string NegentropySingularity = "Negentropy Singularity";
|
||||||
|
public const string MatterReassembler = "Matter Reassembler";
|
||||||
|
public const string VirtualParticle = "Virtual Particle";
|
||||||
|
public const string CtrlShiftClickToPickItemsFromWholeBelts = "Ctrl+Shift+Click to pick items from whole belts";
|
||||||
|
public const string IncludeBranchesOfBelts = "Include branches of belts";
|
||||||
|
public const string IncludeConnectedInserters = "Include connected inserters";
|
||||||
|
public const string AutoConfigLogisticStations = "Auto-config logistic stations";
|
||||||
|
public const string LimitAutoReplenishCountToValuesBelow = "Limit auto-replenish count to values below";
|
||||||
|
public const string Dispenser = "Dispenser";
|
||||||
|
public const string BattlefieldAnalysisBase = "Battlefield Analysis Base";
|
||||||
|
public const string PLS = "PLS";
|
||||||
|
public const string ILS = "ILS";
|
||||||
|
public const string AdvancedMiningMachine = "Advanced Mining Machine";
|
||||||
|
public const string OrbitalCollectorProductLimit = "Orbital Collector product limit";
|
||||||
|
public const string ApplyToUniverse = "Apply to universe";
|
||||||
|
public const string SetDefaultRemoteLogicToStorage = "Set default remote logic to storage";
|
||||||
|
public const string MaxChargingPower = "Max. Charging Power";
|
||||||
|
public const string CountOfBotsFilled = "Count of Bots filled";
|
||||||
|
public const string DroneTransportRange = "Drone transport range";
|
||||||
|
public const string MinLoadOfDrones = "Min. Load of Drones";
|
||||||
|
public const string OutgoingIntegrationCount = "Outgoing integration count";
|
||||||
|
public const string CountOfDronesFilled = "Count of Drones filled";
|
||||||
|
public const string VesselTransportRange = "Vessel transport range";
|
||||||
|
public const string WarpDistance = "Warp distance";
|
||||||
|
public const string MinLoadOfVessels = "Min. Load of Vessels";
|
||||||
|
public const string IncludeOrbitalCollector = "Include Orbital Collector";
|
||||||
|
public const string WarpersRequired = "Warpers required";
|
||||||
|
public const string CountOfVesselsFilled = "Count of Vessels filled";
|
||||||
|
public const string CollectingSpeed = "Collecting Speed";
|
||||||
|
public const string MinPilerValue = "Min. Piler Value";
|
||||||
|
public const string UseTechMaxForPiler = "Use tech max for piler";
|
||||||
|
public const string Cancel = "Cancel";
|
||||||
|
public const string OK = "OK";
|
||||||
|
public const string ApplyConfigToPlanet = "Apply config to planet";
|
||||||
|
public const string ApplyAllConfigToPlanet = "Apply all config to planet";
|
||||||
|
public const string ApplyConfigToPlanetTips = "Apply config to planet tips";
|
||||||
|
public const string ApplyAllConfigToPlanetTips = "Apply all config to planet tips";
|
||||||
|
public const string AllowOverflowForLogisticStationsAndAdvancedMiningMachines = "Allow overflow for Logistic Stations and Advanced Mining Machines";
|
||||||
|
public const string IncreaseMaximumPowerUsageInLogisticStationsAndAdvancedMiningMachines = "Increase maximum power usage in Logistic Stations and Advanced Mining Machines";
|
||||||
|
public const string EnhanceControlForLogisticStorageCapacities = "Enhance control for logistic storage capacities";
|
||||||
|
public const string EnhanceControlForLogisticStorageCapacitiesTips = "Enhance control for logistic storage capacities tips";
|
||||||
|
public const string LogisticsControlPanelImprovement = "Logistics Control Panel Improvement";
|
||||||
|
public const string LogisticsControlPanelImprovementTips = "Logistics Control Panel Improvement tips";
|
||||||
|
public const string RealTimeLogisticStationsInfoPanel = "Real-time logistic stations info panel";
|
||||||
|
public const string ShowStatusBarsForStorageItems = "Show status bars for storage items";
|
||||||
|
public const string TweakBuildingBuffers = "Tweak building buffers";
|
||||||
|
public const string TweakBuildingBuffersTips = "Tweak building buffers tips";
|
||||||
|
public const string AssemblerBufferTimeMultiplierInSeconds = "Assembler buffer time multiplier(in seconds)";
|
||||||
|
public const string AssemblerBufferMinimumMultiplier = "Assembler buffer minimum multiplier";
|
||||||
|
public const string BufferCountForAssemblingInLabs = "Buffer count for assembling in labs";
|
||||||
|
public const string ExtraBufferCountForSelfEvolutionLabs = "Extra buffer count for Self-evolution Labs";
|
||||||
|
public const string BufferCountForResearchingInLabs = "Buffer count for researching in labs";
|
||||||
|
public const string RayReceiverGravitonLensBufferCount = "Ray Receiver Graviton Lens buffer count";
|
||||||
|
public const string EjectorSolarSailsBufferCount = "Ejector Solar Sails buffer count";
|
||||||
|
public const string SiloRocketsBufferCount = "Silo Rockets buffer count";
|
||||||
|
public const string ShortcutKeysForBlueprintCopyMode = "Shortcut keys for Blueprint Copy mode";
|
||||||
|
public const string ShortcutKeysForBlueprintCopyModeTips = "Shortcut keys for Blueprint Copy mode tips";
|
||||||
|
public const string ShortcutKeysForShowingStarsName = "Shortcut keys for showing stars' name";
|
||||||
|
public const string AutoNavigationOnSailings = "Auto navigation on sailings";
|
||||||
|
public const string AutoBoost = "Auto boost";
|
||||||
|
public const string DistanceToUseWarp = "Distance to use warp";
|
||||||
|
public const string NewNavigationAlgorithm = "New navigation algorithm";
|
||||||
|
public const string StopAutoNavigationOnManualInput = "Stop auto-navigation on manual input";
|
||||||
|
public const string UseWarp = "Use warp";
|
||||||
|
public const string UseWarpMinimalEnergy = "Use warp minimal energy";
|
||||||
|
public const string AutoBoostMinimalEnergy = "Auto boost minimal energy";
|
||||||
|
public const string DarkFogHiveFollowDistance = "Dark Fog Hive follow distance";
|
||||||
|
public const string DarkFogCarrierFollowDistance = "Dark Fog Carrier follow distance";
|
||||||
|
public const string AutoNavigationActive = "Auto-navigation active";
|
||||||
|
public const string AutoNavigationStarted = "Auto-navigation started";
|
||||||
|
public const string AutoNavigationStopped = "Auto-navigation stopped";
|
||||||
|
public const string TreatStackItemsAsSingleInMonitorComponents = "Treat stack items as single in monitor components";
|
||||||
|
public const string InitializeThisPlanet = "Initialize This Planet";
|
||||||
|
public const string InitializeThisPlanetConfirm = "Initialize This Planet Confirm";
|
||||||
|
public const string ReturnBuildingsToPlayerWhenInitializingPlanet = "Return buildings to player when initializing planet";
|
||||||
|
public const string ReturnLogisticStorageItemsToPlayerWhenInitializingPlanet = "Return logistic storage items to player when initializing planet";
|
||||||
|
public const string ReturnBeltAndFactoryItemsToPlayerWhenInitializingPlanet = "Return belt and factory items to player when initializing planet";
|
||||||
|
public const string DismantleAllBuildings = "Dismantle All Buildings";
|
||||||
|
public const string DismantleAllBuildingsConfirm = "Dismantle All Buildings Confirm";
|
||||||
|
public const string QuickBuildOrbitalCollectors = "Quick build Orbital Collectors";
|
||||||
|
public const string MaximumCountToBuild = "Maximum count to build";
|
||||||
|
public const string Max = "max";
|
||||||
|
public const string StopEjectorsWhenAvailableNodesAreAllFilledUp = "Stop ejectors when available nodes are all filled up";
|
||||||
|
public const string ConstructOnlyStructurePointsButFrames = "Construct only structure points but frames";
|
||||||
|
public const string InitializeDysonSphere = "Initialize Dyson Sphere";
|
||||||
|
public const string InitializeDysonSphereConfirm = "Initialize Dyson Sphere Confirm";
|
||||||
|
public const string ClickToDismantleSelectedLayer = "Click to dismantle selected layer";
|
||||||
|
public const string DismantleSelectedLayer = "Dismantle selected layer";
|
||||||
|
public const string DismantleSelectedLayerConfirm = "Dismantle selected layer Confirm";
|
||||||
|
public const string AutoFastBuildSpeedMultiplier = "Auto Fast Build Speed Multiplier";
|
||||||
|
public const string RestoreUpgradesOfSorterCargoStackingOnPanel = "Restore upgrades of \"Sorter Cargo Stacking\" on panel";
|
||||||
|
public const string DisableBattleRelatedTechsInPeaceMode = "Disable battle-related techs in Peace mode";
|
||||||
|
public const string BuyOutTechsWithTheirPrerequisites = "Buy out techs with their prerequisites";
|
||||||
|
public const string SetSorterCargoStackingToUnresearchedState = "Set \"Sorter Cargo Stacking\" to unresearched state";
|
||||||
|
public const string UnlockAllTechsWithMetadata = "Unlock all techs with metadata";
|
||||||
|
public const string OpenDarkFogCommunicator = "Open Dark Fog Communicator";
|
||||||
|
public const string PlanetVeinUtilization = "Planet vein utilization";
|
||||||
|
public const string Metadata = "Metadata";
|
||||||
|
public const string InsufficientMetadata = "Insufficient metadata";
|
||||||
|
public const string FirstTimeUsingMetadataDescription = "First time using metadata description";
|
||||||
|
public const string FirstTimeUsingMetadataTitle = "First time using metadata";
|
||||||
|
public const string TechLevelPrefix = "Tech level prefix";
|
||||||
|
public const string AutoSaveEntry = "Auto-save entry";
|
||||||
|
|
||||||
|
public static void Register()
|
||||||
|
{
|
||||||
|
I18N.Add(Unknown, "Unknown", "未知");
|
||||||
|
I18N.Add(DoYouWantToUseMetadataToBuyoutTheFollowingTech, "Do you want to use metadata to buyout the following tech?", "要使用元数据买断以下科技吗?");
|
||||||
|
I18N.Add(TheFollowingIsTheRequiredMetadataForBuyout, "The following is the required metadata for buyout:", "以下是买断所需元数据:");
|
||||||
|
I18N.Add(BatchBuyoutTech, "Batch buyout tech", "批量买断科技");
|
||||||
|
I18N.Add(EnableAutoConstruct, "Enable auto-construct", "启用自动建造");
|
||||||
|
I18N.Add(DisableAutoConstruct, "Disable auto-construct", "禁用自动建造");
|
||||||
|
I18N.Add(BuildingsToConstruct0, "Buildings to construct: {0}", "待建造数量: {0}");
|
||||||
|
I18N.Add(EnableAutoCruise, "Enable auto-cruise", "启用自动巡航");
|
||||||
|
I18N.Add(DisableAutoCruise, "Disable auto-cruise", "禁用自动巡航");
|
||||||
|
I18N.Add(KEYOpenUXAssistConfigWindow, "[UXA] Open UXAssist Config Window", "[UXA] 打开UX助手设置面板");
|
||||||
|
I18N.Add(UXAssistConfig, "UXAssist Config", "UX助手设置");
|
||||||
|
I18N.Add(NoRecentMilkywayUploadResults, "No recent milkyway upload results", "没有最近的银河系发电数据上传结果");
|
||||||
|
I18N.Add(Success, "Success", "成功");
|
||||||
|
I18N.Add(Failure, "Failure: ", "失败: ");
|
||||||
|
I18N.Add(ShowTopPlayers, "Show top players", "显示玩家排行榜");
|
||||||
|
I18N.Add(HideTopPlayers, "Hide top players", "隐藏玩家排行榜");
|
||||||
|
I18N.Add(HighYield, "High yield", "高产");
|
||||||
|
I18N.Add(Perfect, "Perfect", "完美");
|
||||||
|
I18N.Add(UnionResults, "Union results", "结果取并集");
|
||||||
|
I18N.Add(All6BasicOres, "All 6 Basic Ores", "六种基础矿物齐全");
|
||||||
|
I18N.Add(ShowOriginalName, "Show original name", "显示原始名称");
|
||||||
|
I18N.Add(ShowDistance, "Show distance", "显示距离");
|
||||||
|
I18N.Add(ShowPlanetCount, "Show planet count", "显示行星数");
|
||||||
|
I18N.Add(ShowAllInformation, "Show all information", "显示全部信息");
|
||||||
|
I18N.Add(UXAssistNoNodeToFill, "[UXAssist] No node to fill", "[UXAssist] 无可建造节点");
|
||||||
|
I18N.Add(KEYToggleDoNotRenderEntities, "[UXA] Toggle Do Not Render Factory Entities", "[UXA] 切换不渲染工厂建筑实体");
|
||||||
|
I18N.Add(KEYOffgridForPaths, "[UXA] Build belts offgrid", "[UXA] 脱离网格建造传送带");
|
||||||
|
I18N.Add(KEYCutConveyorBelt, "[UXA] Cut conveyor belt", "[UXA] 切割传送带");
|
||||||
|
I18N.Add(KEYDismantleBlueprintSelection, "[UXA] Dismantle blueprint selected buildings", "[UXA] 拆除蓝图选中的建筑");
|
||||||
|
I18N.Add(KEYSelectAllBuildingsInBlueprintCopy, "[UXA] Select all buildings in Blueprint Copy Mode", "[UXA] 蓝图复制时选择所有建筑");
|
||||||
|
I18N.Add(KEYUPSSpeedDown, "[UXA] Decrease logical frame rate", "[UXA] 降低逻辑帧率");
|
||||||
|
I18N.Add(KEYUPSSpeedUp, "[UXA] Increase logical frame rate", "[UXA] 提升逻辑帧率");
|
||||||
|
I18N.Add(LogicalFrameRate0X, "[UXA] Logical frame rate: {0}x", "[UXA] 逻辑帧速率: {0}x");
|
||||||
|
I18N.Add(KEYShowAllStarsName, "[UXA] Keep pressing to show all Stars' name", "[UXA] 按住显示所有星系名称");
|
||||||
|
I18N.Add(KEYToggleAllStarsName, "[UXA] Toggle display of all Stars' name", "[UXA] 切换所有星系名称显示状态");
|
||||||
|
I18N.Add(KEYToggleAutoCruise, "[UXA] Toggle auto-cruise", "[UXA] 切换自动巡航");
|
||||||
|
I18N.Add(AutoCruiseOn, "Auto-cruise enabled", "已启用自动巡航");
|
||||||
|
I18N.Add(AutoCruiseOff, "Auto-cruise disabled", "已禁用自动巡航");
|
||||||
|
I18N.Add(SorterCargoStackingPrefix, "Sorter Mk.III cargo stacking : ", "极速分拣器每次可运送 ");
|
||||||
|
I18N.Add(UXAssist, "UXAssist", "UX助手");
|
||||||
|
I18N.Add(General, "General", "常规");
|
||||||
|
I18N.Add(Factory, "Factory", "工厂");
|
||||||
|
I18N.Add(Logistics, "Logistics", "物流");
|
||||||
|
I18N.Add(PlayerMecha, "Player/Mecha", "玩家/机甲");
|
||||||
|
I18N.Add(DysonSphere, "Dyson Sphere", "戴森球");
|
||||||
|
I18N.Add(TechCombatUI, "Tech/Combat/UI", "科研/战斗/UI");
|
||||||
|
I18N.Add(EnableGameWindowResize, "Enable game window resize (maximum box and thick frame)", "可调整游戏窗口大小(可最大化和拖动边框)");
|
||||||
|
I18N.Add(RemeberWindowPositionAndSizeOnLastExit, "Remeber window position and size on last exit", "记住上次退出时的窗口位置和大小");
|
||||||
|
I18N.Add(BetterAutoSaveMechanism, "Better auto-save mechanism", "更好的自动存档机制");
|
||||||
|
I18N.Add(BetterAutoSaveMechanismTips, "Auto saves are stored in 'Save\\AutoSaves' folder, filenames are combined with cluster address and date-time", "自动存档会以星区地址和日期时间组合为文件名存储在'Save\\AutoSaves'文件夹中");
|
||||||
|
I18N.Add(ConvertOldSavesToCombatModeOnLoading, "Convert old saves to Combat Mode on loading (Use settings in new game panel)", "读取旧档时转为战斗模式(使用新游戏面板的战斗难度设置)");
|
||||||
|
I18N.Add(ProfileBasedSaveFolder, "Mod manager profile based save folder", "基于mod管理器配置档案名的存档文件夹");
|
||||||
|
I18N.Add(ProfileBasedSaveFolderTips, """
|
||||||
|
Save files are stored in 'Save\<ProfileName>' folder.
|
||||||
|
Will use original save location if matching default profile name
|
||||||
|
""", """
|
||||||
|
存档文件会存储在'Save\<ProfileName>'文件夹中
|
||||||
|
如果匹配默认配置档案名则使用原始存档位置
|
||||||
|
""");
|
||||||
|
I18N.Add(ProfileBasedOption, "Mod manager profile based option", "基于mod管理器配置档案名的选项设置");
|
||||||
|
I18N.Add(ProfileBasedOptionTips, """
|
||||||
|
Options are stored in 'Option\<ProfileName>.xml'.
|
||||||
|
Will use original location if matching default profile name
|
||||||
|
""", """
|
||||||
|
配置选项会存储在'Option\<ProfileName>.xml'里
|
||||||
|
如果匹配默认配置档案名则使用原始位置
|
||||||
|
""");
|
||||||
|
I18N.Add(DefaultProfileName, "Default profile name", "默认配置档案名");
|
||||||
|
I18N.Add(LogicalFrameRate, "Logical Frame Rate", "逻辑帧倍率");
|
||||||
|
I18N.Add(Reset, "Reset", "重置");
|
||||||
|
I18N.Add(ProcessPriority, "Process priority", "进程优先级");
|
||||||
|
I18N.Add(High, "High", "高");
|
||||||
|
I18N.Add(AboveNormal, "Above Normal", "高于正常");
|
||||||
|
I18N.Add(Normal, "Normal", "正常");
|
||||||
|
I18N.Add(BelowNormal, "Below Normal", "低于正常");
|
||||||
|
I18N.Add(Idle, "Idle", "空闲");
|
||||||
|
I18N.Add(ShowRecentMilkywayUploadResults, "Show recent milkyway upload results", "显示最近的银河系发电数据上传结果");
|
||||||
|
I18N.Add(UnlimitedInteractiveRange, "Unlimited interactive range", "无限交互距离");
|
||||||
|
I18N.Add(NightLight, "Sunlight at night", "夜间日光灯");
|
||||||
|
I18N.Add(AngleX, "Angle X:", "入射角度X:");
|
||||||
|
I18N.Add(RemoveSomeBuildConditions, "Remove some build conditions", "移除部分不影响游戏逻辑的建造条件");
|
||||||
|
I18N.Add(RemoveBuildRangeLimit, "Remove build count and range limit", "移除建造数量和距离限制");
|
||||||
|
I18N.Add(LargerAreaForUpgradeAndDismantle, "Larger area for upgrade and dismantle", "范围升级和拆除的最大区域扩大");
|
||||||
|
I18N.Add(LargerAreaForTerraform, "Larger area for terraform", "范围铺设地基的最大区域扩大");
|
||||||
|
I18N.Add(OffGridBuildingAndSteppedRotation, "Off-grid building and stepped rotation (Hold Shift)", "脱离网格建造以及小角度旋转(按住Shift)");
|
||||||
|
I18N.Add(EnablePlayerActionsInGlobeView, "Enable player actions in globe view", "在行星视图中允许玩家操作");
|
||||||
|
I18N.Add(HideTipsForSoilPilesChanges, "Hide tips for soil piles changes", "隐藏沙土数量变动的提示");
|
||||||
|
I18N.Add(EnhancedCountControlForHandMake, "Enhanced count control for hand-make", "手动制造物品的数量控制改进");
|
||||||
|
I18N.Add(EnhancedCountControlForHandMakeTips, """
|
||||||
|
Maximum count is increased to 1000.
|
||||||
|
Hold Ctrl/Shift/Alt to change the count rapidly.
|
||||||
|
""", """
|
||||||
|
最大数量提升至1000
|
||||||
|
按住Ctrl/Shift/Alt可快速改变数量
|
||||||
|
""");
|
||||||
|
I18N.Add(QuickBuildAndDismantleStackingLabs, "Quick build and dismantle stacking labs/storages/tanks(hold shift)", "快速建造和拆除堆叠研究站/储物仓/储液罐(按住shift)");
|
||||||
|
I18N.Add(FastFillInToAndTakeOutFromTanks, "Fast fill in to and take out from tanks", "储液罐快速注入和抽取液体");
|
||||||
|
I18N.Add(SpeedRatio, "Speed Ratio", "速度倍率");
|
||||||
|
I18N.Add(CutConveyorBeltWithShortcutKey, "Cut conveyor belt (with shortcut key)", "切割传送带(使用快捷键)");
|
||||||
|
I18N.Add(ProtectVeinsFromExhaustion, "Protect veins from exhaustion", "保护矿脉不会耗尽");
|
||||||
|
I18N.Add(ProtectVeinsFromExhaustionTips, """
|
||||||
|
By default, the vein amount is protected at 100, and oil speed is protected at 1.0/s, you can set them yourself in config file.
|
||||||
|
When reach the protection value, veins/oils steeps will not be mined/extracted any longer.
|
||||||
|
Close this function to resume mining and pumping, usually when you have enough level on `Veins Utilization`
|
||||||
|
""", """
|
||||||
|
默认矿脉数量保护于剩余100,采油速保护于速度1.0/s,你可以在配置文件中自行设置。
|
||||||
|
当达到保护值时,矿脉和油井将不再被开采。
|
||||||
|
关闭此功能以恢复开采,一般是当你在`矿物利用`上有足够的等级时。
|
||||||
|
|
||||||
|
""");
|
||||||
|
I18N.Add(DoNotRenderFactoryEntities, "Do not render factory entities (except belts and sorters)", "不渲染工厂建筑实体(除了传送带和分拣器)");
|
||||||
|
I18N.Add(HideSortersToo, "Hide sorters too", "同时隐藏分拣器");
|
||||||
|
I18N.Add(DragBuildingPowerPolesInMaximumConnectionRange, "Drag building power poles in maximum connection range", "拖动建造电线杆时自动使用最大连接距离间隔");
|
||||||
|
I18N.Add(BuildTeslaTowerAndWirelessPowerTowerAlternately, "Build Tesla Tower and Wireless Power Tower alternately", "交替建造电力感应塔和无线输电塔");
|
||||||
|
I18N.Add(AutoConstructButton, "Auto-construct button", "自动建造按钮");
|
||||||
|
I18N.Add(BeltSignalsForBuyOutDarkFogItemsAutomatically, "Belt signals for buy out dark fog items automatically", "用于自动购买黑雾物品的传送带信号");
|
||||||
|
I18N.Add(MemoryUnit, "Memory Unit", "存储单元");
|
||||||
|
I18N.Add(EnergyFragment, "Energy Fragment", "能量碎片");
|
||||||
|
I18N.Add(SiliconNeuron, "Silicon Neuron", "硅基神经元");
|
||||||
|
I18N.Add(NegentropySingularity, "Negentropy Singularity", "负熵奇点");
|
||||||
|
I18N.Add(MatterReassembler, "Matter Reassembler", "物质重组器");
|
||||||
|
I18N.Add(VirtualParticle, "Virtual Particle", "虚粒子");
|
||||||
|
I18N.Add(CtrlShiftClickToPickItemsFromWholeBelts, "Ctrl+Shift+Click to pick items from whole belts", "按住Ctrl+Shift点击从整条传送带抓取物品");
|
||||||
|
I18N.Add(IncludeBranchesOfBelts, "Include branches of belts", "包含传送带分支");
|
||||||
|
I18N.Add(IncludeConnectedInserters, "Include connected inserters (and their connected belts if above is checked)", "包含连接的分拣器(若勾选上面的选项则包含分拣器连接的传送带)");
|
||||||
|
I18N.Add(AutoConfigLogisticStations, "Auto-config logistic stations", "自动配置物流设施");
|
||||||
|
I18N.Add(LimitAutoReplenishCountToValuesBelow, "Limit auto-replenish count to values below", "限制自动补充数量为下面配置的值");
|
||||||
|
I18N.Add(Dispenser, "Logistics Distributor", "物流配送器");
|
||||||
|
I18N.Add(BattlefieldAnalysisBase, "Battlefield Analysis Base", "战场分析基站");
|
||||||
|
I18N.Add(PLS, "PLS", "行星物流站");
|
||||||
|
I18N.Add(ILS, "ILS", "星际物流站");
|
||||||
|
I18N.Add(AdvancedMiningMachine, "Advanced Mining Machine", "大型采矿机");
|
||||||
|
I18N.Add(OrbitalCollectorProductLimit, "Orbital Collector product limit", "轨道采集器产物上限");
|
||||||
|
I18N.Add(ApplyToUniverse, "Apply to universe", "应用到全宇宙");
|
||||||
|
I18N.Add(SetDefaultRemoteLogicToStorage, "Set default remote logic to storage", "设置默认远程逻辑为仓储");
|
||||||
|
I18N.Add(MaxChargingPower, "Max. Charging Power", "最大充能功率");
|
||||||
|
I18N.Add(CountOfBotsFilled, "Count of Bots filled", "填充的配送机数量");
|
||||||
|
I18N.Add(DroneTransportRange, "Drone transport range", "运输机最远路程");
|
||||||
|
I18N.Add(MinLoadOfDrones, "Min. Load of Drones", "运输机起送量");
|
||||||
|
I18N.Add(OutgoingIntegrationCount, "Outgoing integration count", "输出货物集装数量");
|
||||||
|
I18N.Add(CountOfDronesFilled, "Count of Drones filled", "填充的运输机数量");
|
||||||
|
I18N.Add(VesselTransportRange, "Vessel transport range", "运输船最远路程");
|
||||||
|
I18N.Add(WarpDistance, "Warp distance", "曲速启用路程");
|
||||||
|
I18N.Add(MinLoadOfVessels, "Min. Load of Vessels", "运输船起送量");
|
||||||
|
I18N.Add(IncludeOrbitalCollector, "Include Orbital Collector", "包含轨道采集器");
|
||||||
|
I18N.Add(WarpersRequired, "Warpers required", "翘曲器必备");
|
||||||
|
I18N.Add(CountOfVesselsFilled, "Count of Vessels filled", "填充的运输船数量");
|
||||||
|
I18N.Add(CollectingSpeed, "Collecting Speed", "开采速度");
|
||||||
|
I18N.Add(MinPilerValue, "Outgoing integration count", "输出货物集装数量");
|
||||||
|
I18N.Add(UseTechMaxForPiler, "Use tech max for piler", "集装使用科技上限");
|
||||||
|
I18N.Add(Cancel, "Cancel", "取消");
|
||||||
|
I18N.Add(OK, "OK", "确定");
|
||||||
|
I18N.Add(ApplyConfigToPlanet, "Apply", "应用");
|
||||||
|
I18N.Add(ApplyAllConfigToPlanet, "Apply All", "应用全部");
|
||||||
|
I18N.Add(ApplyConfigToPlanetTips, "Apply this value to all facilities of this type on the current planet", "将此项数值应用到当前行星上所有该类型物流设施");
|
||||||
|
I18N.Add(ApplyAllConfigToPlanetTips, "Apply all settings of this category to all facilities of this type on the current planet", "将本分类的所有设置数值应用到当前行星上所有该类型物流设施");
|
||||||
|
I18N.Add(AllowOverflowForLogisticStationsAndAdvancedMiningMachines, "Allow overflow for Logistic Stations and Advanced Mining Machines", "允许物流站和大型采矿机物品溢出");
|
||||||
|
I18N.Add(IncreaseMaximumPowerUsageInLogisticStationsAndAdvancedMiningMachines, "Increase maximum power usage in Logistic Stations and Advanced Mining Machines", "提升物流塔和大型采矿机的最大功耗");
|
||||||
|
I18N.Add(EnhanceControlForLogisticStorageCapacities, "Enhance control for logistic storage capacities", "物流塔存储容量控制改进");
|
||||||
|
I18N.Add(EnhanceControlForLogisticStorageCapacitiesTips, """
|
||||||
|
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.
|
||||||
|
Use arrow keys to adjust logistic storage capacities:
|
||||||
|
←/→: -/+10 ↓↑: -/+100
|
||||||
|
""", """
|
||||||
|
当升级'运输机舱扩容'时,不会对各种物流塔的存储容量按比例提升,除非设置为最大允许容量或者已经超过升级后的最大容量。
|
||||||
|
你可以使用方向键微调物流塔存储容量:
|
||||||
|
←→: -/+10 ↓↑: -/+100
|
||||||
|
""");
|
||||||
|
I18N.Add(LogisticsControlPanelImprovement, "Logistics Control Panel Improvement", "物流控制面板改进");
|
||||||
|
I18N.Add(LogisticsControlPanelImprovementTips, """
|
||||||
|
Auto apply filter with item under mouse cursor while opening the panel
|
||||||
|
Quick-set item filter while right-clicking item icons in storage list on the panel
|
||||||
|
""", """
|
||||||
|
打开面板时自动将鼠标指向物品设为筛选条件
|
||||||
|
在控制面板物流塔列表中右键点击物品图标快速设置为筛选条件
|
||||||
|
""");
|
||||||
|
I18N.Add(RealTimeLogisticStationsInfoPanel, "Real-time logistic stations info panel", "物流运输站实时信息面板");
|
||||||
|
I18N.Add(ShowStatusBarsForStorageItems, "Show status bars for storage items", "显示存储物品状态条");
|
||||||
|
I18N.Add(TweakBuildingBuffers, "Tweak building buffers", "调整建筑输入缓冲");
|
||||||
|
I18N.Add(TweakBuildingBuffersTips, """
|
||||||
|
Original in-game values:
|
||||||
|
Assembler buffer time multiplier (in seconds): 4
|
||||||
|
Assembler buffer minimum multiplier: 2
|
||||||
|
Buffer count for assembling in labs: 6
|
||||||
|
Extra buffer count for Self-evolution Labs: 3
|
||||||
|
Buffer count for researching in labs: 10
|
||||||
|
Ray Receiver Graviton Lens buffer count: 20
|
||||||
|
Ejector Solar Sails buffer count: 20
|
||||||
|
Silo Rockets buffer count: 20
|
||||||
|
""", """
|
||||||
|
游戏内原始值:
|
||||||
|
工厂配方缓冲时间倍率(秒):4
|
||||||
|
工厂配方缓冲最小倍率:2
|
||||||
|
研究站矩阵合成模式缓存数量:6
|
||||||
|
自演化研究站矩阵额外缓冲数量:3
|
||||||
|
研究站科研模式缓存数量:10
|
||||||
|
射线接收器透镜缓冲数量:20
|
||||||
|
弹射器太阳能帆缓冲数量:20
|
||||||
|
发射井火箭缓冲数量:20
|
||||||
|
""");
|
||||||
|
I18N.Add(AssemblerBufferTimeMultiplierInSeconds, "Assembler buffer time multiplier(in seconds)", "工厂配方缓冲时间倍率(秒)");
|
||||||
|
I18N.Add(AssemblerBufferMinimumMultiplier, "Assembler buffer minimum multiplier", "工厂配方缓冲最小倍率");
|
||||||
|
I18N.Add(BufferCountForAssemblingInLabs, "Buffer count for assembling in labs", "研究站矩阵合成模式缓存数量");
|
||||||
|
I18N.Add(ExtraBufferCountForSelfEvolutionLabs, "Extra buffer count for Self-evolution Labs", "自演化研究站矩阵额外缓冲数量");
|
||||||
|
I18N.Add(BufferCountForResearchingInLabs, "Buffer count for researching in labs", "研究站科研模式缓存数量");
|
||||||
|
I18N.Add(RayReceiverGravitonLensBufferCount, "Ray Receiver Graviton Lens buffer count", "射线接收器透镜缓冲数量");
|
||||||
|
I18N.Add(EjectorSolarSailsBufferCount, "Ejector Solar Sails buffer count", "弹射器太阳能帆缓冲数量");
|
||||||
|
I18N.Add(SiloRocketsBufferCount, "Silo Rockets buffer count", "发射井火箭缓冲数量");
|
||||||
|
I18N.Add(ShortcutKeysForBlueprintCopyMode, "Shortcut keys for Blueprint Copy mode", "蓝图复制模式快捷键");
|
||||||
|
I18N.Add(ShortcutKeysForBlueprintCopyModeTips, """
|
||||||
|
You can set 2 shortcut keys in Settings panel:
|
||||||
|
1. Select all buildings
|
||||||
|
2. Dismantle selected buildings
|
||||||
|
""", """
|
||||||
|
你可以在设置面板中设置2个快捷键:
|
||||||
|
1. 选择所有建筑
|
||||||
|
2. 拆除选中的建筑
|
||||||
|
""");
|
||||||
|
I18N.Add(ShortcutKeysForShowingStarsName, "Shortcut keys for showing stars' name", "启用显示所有星系名称的快捷键");
|
||||||
|
I18N.Add(AutoNavigationOnSailings, "Auto navigation on sailings", "宇宙航行时自动导航");
|
||||||
|
I18N.Add(AutoBoost, "Auto boost", "自动加速");
|
||||||
|
I18N.Add(DistanceToUseWarp, "Distance to use warp (AU)", "使用曲速的距离(AU)");
|
||||||
|
I18N.Add(NewNavigationAlgorithm, "New navigation algorithm", "新导航算法");
|
||||||
|
I18N.Add(StopAutoNavigationOnManualInput, "Stop auto-navigation on manual input", "手动输入时停止自动导航");
|
||||||
|
I18N.Add(UseWarp, "Use warp", "启用曲速");
|
||||||
|
I18N.Add(UseWarpMinimalEnergy, "Minimum energy to use warp (MJ)", "使用曲速最低能量(MJ)");
|
||||||
|
I18N.Add(AutoBoostMinimalEnergy, "Minimum energy for auto boost (MJ)", "自动加速最低能量(MJ)");
|
||||||
|
I18N.Add(DarkFogHiveFollowDistance, "Dark Fog Hive follow distance (AU)", "黑雾巢穴跟踪距离(AU)");
|
||||||
|
I18N.Add(DarkFogCarrierFollowDistance, "Dark Fog Carrier follow distance (m)", "黑雾火种跟踪距离(m)");
|
||||||
|
I18N.Add(AutoNavigationActive, "Auto-navigation active", "自动导航中");
|
||||||
|
I18N.Add(AutoNavigationStarted, "Auto-navigation started", "自动导航启动");
|
||||||
|
I18N.Add(AutoNavigationStopped, "Auto-navigation stopped", "自动导航关闭");
|
||||||
|
I18N.Add(TreatStackItemsAsSingleInMonitorComponents, "Treat stack items as single in monitor components", "在流速计中将堆叠物品视为单个物品");
|
||||||
|
I18N.Add(InitializeThisPlanet, "Initialize this planet", "初始化本行星");
|
||||||
|
I18N.Add(InitializeThisPlanetConfirm, "This operation will destroy all buildings and revert terrains on this planet, are you sure?", "此操作将会摧毁本行星上的所有建筑并恢复地形,确定吗?");
|
||||||
|
I18N.Add(ReturnBuildingsToPlayerWhenInitializingPlanet, "Return buildings to player when initializing planet", "初始化行星时将建筑归还给玩家");
|
||||||
|
I18N.Add(ReturnLogisticStorageItemsToPlayerWhenInitializingPlanet, "Return logistic storage items to player when initializing planet", "初始化行星时将物流塔存储的物品归还给玩家");
|
||||||
|
I18N.Add(ReturnBeltAndFactoryItemsToPlayerWhenInitializingPlanet, "Return belt and factory items to player when initializing planet", "初始化行星时将传送带和工厂里的物品归还给玩家");
|
||||||
|
I18N.Add(DismantleAllBuildings, "Dismantle all buildings", "拆除所有建筑");
|
||||||
|
I18N.Add(DismantleAllBuildingsConfirm, "This operation will dismantle all buildings on this planet, are you sure?", "此操作将会拆除本行星上的所有建筑,确定吗?");
|
||||||
|
I18N.Add(QuickBuildOrbitalCollectors, "Quick build Orbital Collectors", "快速建造轨道采集器");
|
||||||
|
I18N.Add(MaximumCountToBuild, "Maximum count to build", "最大建造数量");
|
||||||
|
I18N.Add(Max, "max", "最大");
|
||||||
|
I18N.Add(StopEjectorsWhenAvailableNodesAreAllFilledUp, "Stop ejectors when available nodes are all filled up", "可用节点全部造完时停止弹射");
|
||||||
|
I18N.Add(ConstructOnlyStructurePointsButFrames, "Construct only structure points but frames", "只造节点不造框架");
|
||||||
|
I18N.Add(InitializeDysonSphere, "Initialize Dyson Sphere", "初始化戴森球");
|
||||||
|
I18N.Add(InitializeDysonSphereConfirm, "This operation will destroy all layers on this dyson sphere, are you sure?", "此操作将会摧毁戴森球上的所有层级,确定吗?");
|
||||||
|
I18N.Add(ClickToDismantleSelectedLayer, "Click to dismantle selected layer", "点击拆除对应的戴森壳");
|
||||||
|
I18N.Add(DismantleSelectedLayer, "Dismantle selected layer", "拆除选中的戴森壳");
|
||||||
|
I18N.Add(DismantleSelectedLayerConfirm, "This operation will dismantle selected layer, are you sure?", "此操作将会拆除选中的戴森壳,确定吗?");
|
||||||
|
I18N.Add(AutoFastBuildSpeedMultiplier, "Auto Fast Build Speed Multiplier", "自动快速建造速度倍率");
|
||||||
|
I18N.Add(RestoreUpgradesOfSorterCargoStackingOnPanel, "Restore upgrades of \"Sorter Cargo Stacking\" on panel", "在升级面板上恢复\"分拣器货物叠加\"的升级");
|
||||||
|
I18N.Add(DisableBattleRelatedTechsInPeaceMode, "Disable battle-related techs in Peace mode", "在和平模式下隐藏战斗相关科技");
|
||||||
|
I18N.Add(BuyOutTechsWithTheirPrerequisites, "Buy out techs with their prerequisites", "购买科技也同时购买所有前置科技");
|
||||||
|
I18N.Add(SetSorterCargoStackingToUnresearchedState, "Set \"Sorter Cargo Stacking\" to unresearched state", "将\"分拣器货物叠加\"设为未研究状态");
|
||||||
|
I18N.Add(UnlockAllTechsWithMetadata, "Unlock all techs with metadata", "使用元数据解锁所有科技");
|
||||||
|
I18N.Add(OpenDarkFogCommunicator, "Open Dark Fog Communicator", "打开黑雾通讯器");
|
||||||
|
I18N.Add(PlanetVeinUtilization, "Planet vein utilization in star map", "宇宙视图行星/星系矿脉数量显示");
|
||||||
|
I18N.Add(Metadata, "Metadata", "元数据");
|
||||||
|
I18N.Add(InsufficientMetadata, "Insufficient metadata", "元数据不足");
|
||||||
|
I18N.Add(FirstTimeUsingMetadataDescription, "Using metadata will disable achievements in this save. Are you sure?", "使用元数据会禁用本存档成就,确定吗?");
|
||||||
|
I18N.Add(FirstTimeUsingMetadataTitle, "First time using metadata", "初次使用元数据");
|
||||||
|
I18N.Add(TechLevelPrefix, " Lv.", "等级");
|
||||||
|
I18N.Add(AutoSaveEntry, "Auto-save entry", "自动存档条目");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace UXAssist.Common;
|
||||||
|
|
||||||
|
public enum KnownItemId : int
|
||||||
|
{
|
||||||
|
Drone = 5001,
|
||||||
|
Ship = 5002,
|
||||||
|
Bot = 5003,
|
||||||
|
Warper = 1210,
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using BepInEx;
|
||||||
|
using BepInEx.Bootstrap;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace UXAssist.Common.ModCompat;
|
||||||
|
|
||||||
|
public static class ModCompatHelper
|
||||||
|
{
|
||||||
|
public static bool TryGetLoadedPluginInfo(string guid, out BepInEx.PluginInfo pluginInfo)
|
||||||
|
{
|
||||||
|
return Chainloader.PluginInfos.TryGetValue(guid, out pluginInfo) && pluginInfo != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetPluginType(BepInEx.PluginInfo pluginInfo, string typeName, out Type type)
|
||||||
|
{
|
||||||
|
type = null;
|
||||||
|
if (pluginInfo?.Instance == null) return false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
type = pluginInfo.Instance.GetType().Assembly.GetType(typeName, throwOnError: false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
return type != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetPluginType(string guid, string typeName, out Type type)
|
||||||
|
{
|
||||||
|
type = null;
|
||||||
|
return TryGetLoadedPluginInfo(guid, out var pluginInfo) && TryGetPluginType(pluginInfo, typeName, out type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetField(Type type, string fieldName, out FieldInfo field)
|
||||||
|
{
|
||||||
|
field = null;
|
||||||
|
if (type == null) return false;
|
||||||
|
field = AccessTools.Field(type, fieldName);
|
||||||
|
return field != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetFieldValue<T>(Type type, string fieldName, object instance, out T value)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
if (!TryGetField(type, fieldName, out var field)) return false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = field.GetValue(instance);
|
||||||
|
if (result is T t)
|
||||||
|
{
|
||||||
|
value = t;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetMethod(Type type, string methodName, out MethodInfo method)
|
||||||
|
{
|
||||||
|
method = null;
|
||||||
|
if (type == null) return false;
|
||||||
|
method = AccessTools.Method(type, methodName);
|
||||||
|
return method != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetPropertySetter(Type type, string propertyName, out MethodInfo setter)
|
||||||
|
{
|
||||||
|
setter = null;
|
||||||
|
if (type == null) return false;
|
||||||
|
var property = AccessTools.Property(type, propertyName);
|
||||||
|
if (property == null) return false;
|
||||||
|
setter = property.GetSetMethod(nonPublic: true);
|
||||||
|
return setter != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
namespace UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface implemented by instance mod features registered with <see cref="ModFeatureRegistry"/>.
|
||||||
|
/// The registry drives the lifecycle; individual mods never call these methods directly.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// <strong>Timing contract.</strong> The registry guarantees the following relative ordering, which
|
||||||
|
/// feature implementations may rely on:
|
||||||
|
/// </para>
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item><see cref="Init"/> runs <strong>eagerly</strong> at registration time — synchronously inside
|
||||||
|
/// <see cref="ModFeatureRegistry.Register{T}"/>, normally during the registering mod's BepInEx
|
||||||
|
/// <c>Awake</c> phase. It is the phase for early setup such as keybind registration via CommonAPI's
|
||||||
|
/// <c>CustomKeyBindSystem</c>, whose registered bindings are copied by the game's
|
||||||
|
/// <c>UIOptionWindow._OnCreate</c> only after all plugins finish loading. A late-discovered feature may
|
||||||
|
/// initialize after the host lifecycle has begun, so implementations must not depend on either the game
|
||||||
|
/// being loaded or unloaded here.</item>
|
||||||
|
/// <item><see cref="Start"/> runs <strong>once</strong> when UXAssist starts the deferred lifecycle.
|
||||||
|
/// This is normally during the host mod's <c>Start</c>; if a feature is registered afterwards, the registry
|
||||||
|
/// starts that feature immediately after <see cref="Init"/>. This is the phase for activating behavior that
|
||||||
|
/// requires the game/runtime to be ready. It is driven solely by UXAssist; dependent mods must not start
|
||||||
|
/// features themselves.</item>
|
||||||
|
/// <item><see cref="Uninit"/> runs during the host's teardown (<c>OnDestroy</c>) and resets the feature
|
||||||
|
/// so it could be started again.</item>
|
||||||
|
/// <item><see cref="OnInputUpdate"/> and <see cref="OnUpdate"/> are called every frame by UXAssist; the
|
||||||
|
/// registry guarantees at most one invocation per frame even if multiple drivers exist.</item>
|
||||||
|
/// </list>
|
||||||
|
/// <para>
|
||||||
|
/// The same timing contract applies to static features discovered via <see cref="ModFeatureAttribute"/>;
|
||||||
|
/// see that attribute for details.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public interface IModFeature
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called eagerly at registration time, normally during the registering mod's <c>Awake</c> phase.
|
||||||
|
/// Use this for early setup such as keybind registration. A late-discovered feature may initialize
|
||||||
|
/// after the host lifecycle has begun, so do not depend on the game being loaded or unloaded here.
|
||||||
|
/// Runs at most once per registration.
|
||||||
|
/// </summary>
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called once when UXAssist starts the deferred lifecycle. If this feature is registered after the
|
||||||
|
/// lifecycle has already started, the registry invokes this immediately after <see cref="Init"/>. Use
|
||||||
|
/// this to activate behavior that requires the game/runtime to be ready. Driven solely by UXAssist;
|
||||||
|
/// runs at most once (a repeated driver call is a no-op for an already-started feature).
|
||||||
|
/// </summary>
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called during the host's teardown (<c>OnDestroy</c>). Reset any state created in
|
||||||
|
/// <see cref="Init"/>/<see cref="Start"/> so the feature could be re-started. Runs on every
|
||||||
|
/// registered feature.
|
||||||
|
/// </summary>
|
||||||
|
void Uninit();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called every frame for input handling. Should be lightweight. The registry guarantees at most
|
||||||
|
/// one invocation per frame.
|
||||||
|
/// </summary>
|
||||||
|
void OnInputUpdate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called every frame for general updates. Should be lightweight. The registry guarantees at most
|
||||||
|
/// one invocation per frame.
|
||||||
|
/// </summary>
|
||||||
|
void OnUpdate();
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace UXAssist.Common.ModFeatures;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks a class as a mod feature so that <see cref="ModFeatureRegistry"/> can discover it.
|
||||||
|
/// Lifecycle methods (<c>Init</c>, <c>Start</c>, <c>Uninit</c>, <c>OnInputUpdate</c>, <c>OnUpdate</c>)
|
||||||
|
/// are optional and are skipped if missing.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// <strong>Timing contract</strong> (same as <see cref="IModFeature"/>): <c>Init</c> runs eagerly at
|
||||||
|
/// discovery time, synchronously inside <see cref="ModFeatureRegistry.Discover"/>, normally during the
|
||||||
|
/// registering mod's BepInEx <c>Awake</c> phase. This is the phase where early setup such as keybind
|
||||||
|
/// registration must run. A late-discovered feature can initialize after the host lifecycle has begun.
|
||||||
|
/// <c>Start</c> runs once during the host mod's (UXAssist) <c>Start</c>.
|
||||||
|
/// If a feature is discovered after that lifecycle has already begun, the registry starts it immediately
|
||||||
|
/// after <c>Init</c>. The per-frame methods are called by UXAssist with at most one invocation per frame.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||||
|
public sealed class ModFeatureAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Optional display name of the feature.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execution order among discovered static features. Lower values run first.
|
||||||
|
/// </summary>
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ModFeatureAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Optional display name of the feature.</param>
|
||||||
|
public ModFeatureAttribute(string name = null)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user