├── Config
├── icon.png
├── thunderstore.toml
└── README.md
├── AssemblyPublicizer.exe
├── Libs
├── UnityEngine.UI.dll
└── Assembly-CSharp.dll
├── Staging
├── plugins
│ └── commonapi
└── CHANGELOG.md
├── CommonAPIPreloader
├── CommonAPIPreloader.csproj
├── Directory.Build.props
└── Preloader.cs
├── CommonAPI
├── Util
│ ├── Interfaces
│ │ └── Update
│ │ │ ├── IDrawUpdate.cs
│ │ │ ├── IUpdate.cs
│ │ │ ├── IPowerUpdate.cs
│ │ │ ├── IPreUpdate.cs
│ │ │ ├── IPostUpdate.cs
│ │ │ ├── IUpdateMultithread.cs
│ │ │ ├── IPowerUpdateMultithread.cs
│ │ │ ├── IPreUpdateMultithread.cs
│ │ │ └── IPostUpdateMultithread.cs
│ ├── Data
│ │ ├── IPoolable.cs
│ │ ├── ISerializeState.cs
│ │ └── InstanceRegistry.cs
│ ├── Logging
│ │ ├── CommonLogger.cs
│ │ ├── ICommonLogger.cs
│ │ └── LoggerWrapper.cs
│ ├── Extensions
│ │ ├── GameVersionUtil.cs
│ │ ├── CodeMatcherExtension.cs
│ │ ├── CecilExtension.cs
│ │ ├── GeneralExtensions.cs
│ │ ├── HarmonyRegisterExtension.cs
│ │ ├── TopologicalSortExtension.cs
│ │ └── ConfigFileExtension.cs
│ ├── UI
│ │ ├── ColorProperties.cs
│ │ └── MaterialFixer.cs
│ ├── Submodules
│ │ ├── CommonAPISubmoduleDependency.cs
│ │ └── BaseSubmodule.cs
│ ├── ShotScene
│ │ ├── Patches
│ │ │ └── PostProcessingMaterialFactoryPatch.cs
│ │ └── TPCameraController.cs
│ ├── AcceptableValueOptionsList.cs
│ └── PointsHelper.cs
├── Systems
│ ├── LocalizationModule
│ │ ├── documentation
│ │ │ ├── folders.png
│ │ │ └── file-format.png
│ │ ├── Patch
│ │ │ ├── Text_Patch.cs
│ │ │ └── UIBehaviour_Patch.cs
│ │ ├── ExtraLanguageData.cs
│ │ ├── TextDefaultFont.cs
│ │ └── README.md
│ ├── CustomDescSystem
│ │ ├── CustomDesc.cs
│ │ ├── CustomDescSystem.cs
│ │ ├── Patches
│ │ │ └── PrefabDescPatch.cs
│ │ ├── Extensions
│ │ │ └── PrefabDescExtensions.cs
│ │ └── ConfigurableDesc.cs
│ ├── Networks
│ │ ├── INetwork.cs
│ │ ├── NodeExtensions.cs
│ │ ├── PowerNetworkWrapper.cs
│ │ └── NetworksSystem.cs
│ ├── StarExtensionSystem
│ │ ├── IStarExtension.cs
│ │ ├── Nebula
│ │ │ ├── StarExtensionData.cs
│ │ │ └── StarExtensionLoadRequest.cs
│ │ └── Patches
│ │ │ └── StarExtensionHooks.cs
│ ├── PlanetExtensionSystem
│ │ ├── Extensions
│ │ │ ├── IPropertySerializer.cs
│ │ │ └── PlanetFactoryExtensions.cs
│ │ ├── IPlanetExtension.cs
│ │ └── Nebula
│ │ │ ├── PlanetExtensionData.cs
│ │ │ └── PlanetSystemLoadRequest.cs
│ ├── ComponentSystem
│ │ ├── ICopyPasteSettings.cs
│ │ ├── Extensions
│ │ │ └── EntityExtensions.cs
│ │ ├── UI
│ │ │ ├── Widgets
│ │ │ │ ├── IStorage.cs
│ │ │ │ └── UIPowerIndicator.cs
│ │ │ ├── CustomMachineUISystem.cs
│ │ │ └── CustomMachineWindow.cs
│ │ ├── IComponentStateListener.cs
│ │ ├── ComponentDesc.cs
│ │ ├── Patches
│ │ │ ├── CustomDataPatches.cs
│ │ │ └── UIGamePatch.cs
│ │ ├── ComponentExtensionModule.cs
│ │ ├── FactoryComponent.cs
│ │ └── ComponentTypePool.cs
│ ├── TabSystem
│ │ ├── TabData.cs
│ │ ├── UI
│ │ │ └── UITabButton.cs
│ │ ├── Patches
│ │ │ ├── UIItemPickerPatch.cs
│ │ │ ├── UIRecipePickerPatch.cs
│ │ │ └── UIReplicatorPatch.cs
│ │ └── TabSystem.cs
│ ├── ProtoRegistrySystem
│ │ ├── Patches
│ │ │ ├── GameMain_Patch.cs
│ │ │ ├── StorageComponentPatch.cs
│ │ │ ├── UIBuildMenuPatch.cs
│ │ │ ├── VertaBufferPatch.cs
│ │ │ ├── IconSetPatch.cs
│ │ │ ├── ProtoSet_Patch.cs
│ │ │ └── ResourcesPatch.cs
│ │ ├── ModLoadState.cs
│ │ ├── Extensions
│ │ │ └── ItemProtoExtenstion.cs
│ │ ├── LodMaterials.cs
│ │ └── ResourceData.cs
│ ├── AssemblerRecipeSystem
│ │ ├── RecipeExtensions.cs
│ │ ├── ExtendedAssemberDesc.cs
│ │ ├── Patches
│ │ │ ├── AssemblerComponentPatch.cs
│ │ │ └── UIAssemblerWindowPatch.cs
│ │ └── AssemblerRecipeSystem.cs
│ ├── UtilSystem
│ │ ├── UtilSystem.cs
│ │ ├── LoadSaveOnLoad.cs
│ │ └── Patches
│ │ │ └── GameLoaderPatch.cs
│ ├── KeyBindSystem
│ │ ├── Patches
│ │ │ └── KeyBindPatches.cs
│ │ ├── KeyBindConflict.cs
│ │ ├── PressKeyBind.cs
│ │ └── README.md
│ ├── PickerExtensionSystem
│ │ ├── README.md
│ │ ├── IPickerExtension.cs
│ │ ├── UI
│ │ │ └── UIShowSignalTipExtension.cs
│ │ ├── PickerExtensionsSystem.cs
│ │ ├── UIItemPickerExtension.cs
│ │ ├── UISignalPickerExtension.cs
│ │ ├── UIRecipePickerExtension.cs
│ │ └── Patches
│ │ │ └── UIItemPicker_Patch.cs
│ └── README.md
├── CommonAPI.csproj
├── Directory.Build.props
└── NebulaCompatPlugin.cs
├── NuGet.Config
├── CommonAPITests
├── CommonAPITests.csproj
├── Util.cs
├── FakeLogger.cs
├── Factory
│ └── FactoryComponentTest.cs
├── Data
│ ├── PrefabDataTest.cs
│ └── EntityDataTest.cs
└── Directory.Build.props
├── Directory.Build.targets
├── version.json
├── DevEnv.targets.example
├── .run
├── RunDSP.run.xml
└── PublicizeAssembly.run.xml
├── Licenses
└── R2API LICENSE
├── CommonAPIPublish.sln
├── CommonAPI.sln
├── SharedConfig.targets
├── .github
└── workflows
│ └── workflow.yml
└── README.md
/Config/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limoka/CommonAPI/HEAD/Config/icon.png
--------------------------------------------------------------------------------
/AssemblyPublicizer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limoka/CommonAPI/HEAD/AssemblyPublicizer.exe
--------------------------------------------------------------------------------
/Libs/UnityEngine.UI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limoka/CommonAPI/HEAD/Libs/UnityEngine.UI.dll
--------------------------------------------------------------------------------
/Libs/Assembly-CSharp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limoka/CommonAPI/HEAD/Libs/Assembly-CSharp.dll
--------------------------------------------------------------------------------
/Staging/plugins/commonapi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limoka/CommonAPI/HEAD/Staging/plugins/commonapi
--------------------------------------------------------------------------------
/CommonAPIPreloader/CommonAPIPreloader.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IDrawUpdate.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | public interface IDrawUpdate
4 | {
5 | void Draw();
6 | }
7 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/LocalizationModule/documentation/folders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limoka/CommonAPI/HEAD/CommonAPI/Systems/LocalizationModule/documentation/folders.png
--------------------------------------------------------------------------------
/CommonAPI/Systems/LocalizationModule/documentation/file-format.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/limoka/CommonAPI/HEAD/CommonAPI/Systems/LocalizationModule/documentation/file-format.png
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CommonAPITests/CommonAPITests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 |
6 |
7 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/CustomDescSystem/CustomDesc.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | public abstract class CustomDesc : MonoBehaviour
6 | {
7 | public abstract void ApplyProperties(PrefabDesc desc);
8 | }
9 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/Networks/INetwork.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using PowerNetworkStructures;
3 |
4 | namespace CommonAPI
5 | {
6 | public interface INetwork
7 | {
8 | int GetId();
9 |
10 | List GetNodes();
11 | }
12 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/StarExtensionSystem/IStarExtension.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI.Systems
2 | {
3 | ///
4 | /// Defines a extension, which has one instance per star.
5 | ///
6 | public interface IStarExtension : ISerializeState
7 | {
8 | void Init(StarData star);
9 | }
10 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/CustomDescSystem/CustomDescSystem.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Patches;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | public class CustomDescSystem : BaseSubmodule
6 | {
7 | internal override void SetHooks()
8 | {
9 | CommonAPIPlugin.harmony.PatchAll(typeof(PrefabDescPatch));
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/Networks/NodeExtensions.cs:
--------------------------------------------------------------------------------
1 | using PowerNetworkStructures;
2 | using UnityEngine;
3 |
4 | namespace CommonAPI
5 | {
6 | public static class NodeExtensions
7 | {
8 | public static Vector3 GetPoint(this Node node)
9 | {
10 | return new Vector3(node.x, node.y, node.z);
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PlanetExtensionSystem/Extensions/IPropertySerializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace CommonAPI
5 | {
6 | public interface IPropertySerializer
7 | {
8 | void Export(object obj, BinaryWriter w);
9 | object Import(BinaryReader r);
10 | Type GetTargetType();
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Data/IPoolable.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace CommonAPI
4 | {
5 | ///
6 | /// Interface for objects that can be contained an a
7 | ///
8 | public interface IPoolable : ISerializeState
9 | {
10 | int GetId();
11 | void SetId(int id);
12 | }
13 | }
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IUpdate.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | ///
6 | public interface IUpdate
7 | {
8 | ///
9 | /// This call will happen after main factory update
10 | ///
11 | void Update();
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IPowerUpdate.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | ///
6 | public interface IPowerUpdate
7 | {
8 | ///
9 | /// This call will happen before power update
10 | ///
11 | void PowerUpdate();
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IPreUpdate.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | ///
6 | public interface IPreUpdate
7 | {
8 | ///
9 | /// This call will happen before main factory update
10 | ///
11 | void PreUpdate();
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Data/ISerializeState.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace CommonAPI
4 | {
5 | ///
6 | /// Interface used to save and load class data to Binary Reader/Writer
7 | ///
8 | public interface ISerializeState
9 | {
10 | void Free();
11 |
12 | void Export(BinaryWriter w);
13 |
14 | void Import(BinaryReader r);
15 | }
16 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PlanetExtensionSystem/IPlanetExtension.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 |
4 | namespace CommonAPI.Systems
5 | {
6 | ///
7 | /// Defines a extension, which has one instance per planet.
8 | ///
9 | public interface IPlanetExtension : ISerializeState
10 | {
11 | void Init(PlanetFactory factory);
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IPostUpdate.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | ///
6 | public interface IPostUpdate
7 | {
8 | ///
9 | /// This call will happen after everything else had already updated
10 | ///
11 | void PostUpdate();
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Logging/CommonLogger.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Static container for logger interface to appease Unit testing assembly...
5 | ///
6 | public class CommonLogger
7 | {
8 | public static ICommonLogger logger;
9 |
10 | public static void SetLogger(ICommonLogger _logger)
11 | {
12 | logger = _logger;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/ICopyPasteSettings.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | public interface ICopyPasteSettings
6 | {
7 | void WriteCopyData(BinaryWriter w);
8 | bool CanPasteSettings(FactoryComponent originalObject, BinaryReader r);
9 | void PasteSettings(int sourceType, BinaryReader r);
10 | string GetCopyMessage();
11 | string GetPasteMessage();
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/Extensions/EntityExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI.Systems.Extensions
2 | {
3 | public static class EntityExtensions
4 | {
5 | public static int GetCustomId(this EntityData entity)
6 | {
7 | return entity.customId;
8 | }
9 |
10 | public static int GetCustomType(this EntityData entity)
11 | {
12 | return entity.customType;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/UI/Widgets/IStorage.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 |
4 | public interface IItem
5 | {
6 | int GetItemId();
7 | int GetCount();
8 | int GetMaxStackSize();
9 |
10 | }
11 |
12 | public interface IStorage
13 | {
14 | int size { get; }
15 | bool changed { get; set; }
16 |
17 | IItem GetAt(int index);
18 | void SetAt(int index, IItem stack);
19 | }
20 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/LocalizationModule/Patch/Text_Patch.cs:
--------------------------------------------------------------------------------
1 | using HarmonyLib;
2 | using UnityEngine.UI;
3 |
4 | namespace CommonAPI.Systems.ModLocalization.Patch
5 | {
6 | public class Text_Patch
7 | {
8 |
9 | [HarmonyPatch(typeof(Text), nameof(Text.font), MethodType.Getter)]
10 | [HarmonyPrefix]
11 | public static void Prefix(Text __instance)
12 | {
13 | LocalizationModule.Get(__instance)?.OnGetFont();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
3 | "version": "1.6.7",
4 | "assemblyVersion": {
5 | "precision": "build"
6 | },
7 | "gitCommitIdShortFixedLength": 7,
8 | "publicReleaseRefSpec": [
9 | "^refs/heads/master$"
10 | ],
11 | "release": {
12 | "versionIncrement": "build",
13 | "firstUnstableTag": ""
14 | },
15 | "inherit": false
16 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/IComponentStateListener.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI.Systems
2 | {
3 | ///
4 | /// Allows to listen to factory component add/remove events
5 | ///
6 | public interface IComponentStateListener
7 | {
8 | void OnLogicComponentsAdd(int entityId, PrefabDesc desc, int prebuildId);
9 | void OnPostlogicComponentsAdd(int entityId, PrefabDesc desc, int prebuildId);
10 | void OnLogicComponentsRemove(int entityId);
11 | }
12 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/TabSystem/TabData.cs:
--------------------------------------------------------------------------------
1 | using JetBrains.Annotations;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | [UsedImplicitly]
6 | public class TabData
7 | {
8 | public int tabIndex;
9 | public readonly string tabName;
10 | public readonly string tabIconPath;
11 |
12 | public TabData(string tabName, string tabIconPath)
13 | {
14 | this.tabName = tabName;
15 | this.tabIconPath = tabIconPath;
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/ComponentDesc.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace CommonAPI.Systems
3 | {
4 | public class ComponentDesc : CustomDesc
5 | {
6 | public const string FIELD_NAME = CommonAPIPlugin.ID + ":componentId";
7 |
8 | public string componentId;
9 | public override void ApplyProperties(PrefabDesc desc)
10 | {
11 | int id = ComponentExtension.componentRegistry.GetUniqueId(componentId);
12 | desc.SetProperty(FIELD_NAME, id);
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Patches/GameMain_Patch.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using HarmonyLib;
3 |
4 | namespace CommonAPI.Patches
5 | {
6 | [HarmonyPatch]
7 | public static class GameMain_Patch
8 | {
9 | [HarmonyPatch(typeof(GameMain), "Begin")]
10 | [HarmonyPostfix]
11 | public static void OnGameBegin()
12 | {
13 | ModProtoHistory.CheckMissingMachines();
14 | ModProtoHistory.DisplayRemovedMessage();
15 | }
16 |
17 | }
18 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PlanetExtensionSystem/Extensions/PlanetFactoryExtensions.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace CommonAPI.Systems
3 | {
4 | public static class PlanetFactoryExtensions
5 | {
6 | public static T GetSystem(this PlanetFactory factory, int systemId) where T : IPlanetExtension
7 | {
8 | PlanetExtensionSystem.Instance.ThrowIfNotLoaded();
9 | if (systemId <= 0) return default;
10 | return (T)PlanetExtensionSystem.extensions[systemId].GetExtension(factory);
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/ModLoadState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | public class ModLoadState : IDisposable
6 | {
7 | public string modGUID;
8 |
9 | public ModLoadState(string modGUID)
10 | {
11 | this.modGUID = modGUID;
12 | }
13 |
14 | public void Dispose()
15 | {
16 | ProtoRegistry.currentMod = "";
17 | CommonAPIPlugin.logger.LogInfo($"Mod {modGUID} loading phase is over.");
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Logging/ICommonLogger.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Logger interface to appease Unit testing assembly...
5 | ///
6 | public interface ICommonLogger
7 | {
8 | public void LogFatal(object data);
9 |
10 | public void LogError(object data);
11 |
12 | public void LogWarning(object data);
13 |
14 | public void LogMessage(object data);
15 |
16 | public void LogInfo(object data);
17 |
18 | public void LogDebug(object data);
19 | }
20 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IUpdateMultithread.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | /// This version also supports multithreading. Note that non single thread version will not get called!
6 | ///
7 | public interface IUpdateMultithread : IUpdate
8 | {
9 | ///
10 | /// This call will happen after main factory update
11 | ///
12 | void UpdateMultithread(int usedThreadCount, int currentThreadIdx, int minimumCount);
13 | }
14 | }
--------------------------------------------------------------------------------
/DevEnv.targets.example:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | C:\Program Files (x86)\Steam\
6 |
7 | C:\Program Files (x86)\Steam\steamapps\common\Dyson Sphere Program\
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/Networks/PowerNetworkWrapper.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using PowerNetworkStructures;
3 |
4 | namespace CommonAPI
5 | {
6 | public class PowerNetworkWrapper : INetwork
7 | {
8 | public PowerNetwork data;
9 |
10 | public PowerNetworkWrapper(PowerNetwork network)
11 | {
12 | data = network;
13 | }
14 |
15 | public int GetId()
16 | {
17 | return data.id;
18 | }
19 |
20 | public List GetNodes()
21 | {
22 | return data.nodes;
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IPowerUpdateMultithread.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | /// This version also supports multithreading. Note that non single thread version will not get called!
6 | ///
7 | public interface IPowerUpdateMultithread : IPowerUpdate
8 | {
9 | ///
10 | /// This call will happen before power update
11 | ///
12 | void PowerUpdateMultithread(int usedThreadCount, int currentThreadIdx, int minimumCount);
13 | }
14 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IPreUpdateMultithread.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | /// This version also supports multithreading. Note that non single thread version will not get called!
6 | ///
7 | public interface IPreUpdateMultithread : IPreUpdate
8 | {
9 | ///
10 | /// This call will happen before main factory update
11 | ///
12 | void PreUpdateMultithread(int usedThreadCount, int currentThreadIdx, int minimumCount);
13 | }
14 | }
--------------------------------------------------------------------------------
/CommonAPITests/Util.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace CommonAPITests
5 | {
6 | public static class Util
7 | {
8 | public static void GetSerializationSetup(Action write, Action read)
9 | {
10 | MemoryStream stream = new MemoryStream();
11 | BinaryWriter writer = new BinaryWriter(stream);
12 |
13 | write(writer);
14 |
15 | stream.Position = 0;
16 | BinaryReader reader = new BinaryReader(stream);
17 |
18 | read(reader);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Extensions/GameVersionUtil.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | public static class GameVersionUtil
4 | {
5 | public static Version GetVersion(int major, int minor, int release, int build)
6 | {
7 | return new Version(major, minor, release)
8 | {
9 | Build = build
10 | };
11 | }
12 |
13 | public static bool CompatibleWith(this Version first, Version other)
14 | {
15 | return first.Major == other.Major &&
16 | first.Minor == other.Minor &&
17 | first.Release == other.Release;
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/CommonAPI/CommonAPI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 | A modding library for Dyson Sphere Program. Provides multiple features to make adding custom content to DSP easier.
6 | https://github.com/kremnev8/CommonAPI
7 | DysonSphereProgram.Modding.CommonAPI
8 | DSP Common API
9 | $(MSBuildThisFileDirectory)/Nuget/
10 | GPL-3.0-only
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/CommonAPI/Util/Extensions/CodeMatcherExtension.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection.Emit;
2 | using HarmonyLib;
3 |
4 | namespace CommonAPI
5 | {
6 | public static class CodeMatcherExtension
7 | {
8 | public static CodeMatcher GetInstructionAndAdvance(this CodeMatcher matcher, out OpCode opCode, out object operand)
9 | {
10 | opCode = matcher.Opcode;
11 | operand = matcher.Operand;
12 | matcher.Advance(1);
13 | return matcher;
14 | }
15 |
16 | public static CodeMatcher GetLabel(this CodeMatcher matcher, out Label label)
17 | {
18 | label = (Label) matcher.Instruction.operand;
19 | return matcher;
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/.run/RunDSP.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Config/thunderstore.toml:
--------------------------------------------------------------------------------
1 | [config]
2 | schemaVersion = "0.0.1"
3 |
4 | [package]
5 | namespace = "CommonAPI"
6 | name = "CommonAPI"
7 | description = "A modding library for Dyson Sphere Program. Currently is under development."
8 | websiteUrl = "https://github.com/kremnev8/CommonAPI"
9 | containsNsfwContent = false
10 |
11 | [package.dependencies]
12 | xiaoye97-BepInEx = "5.4.17"
13 | xiaoye97-LDBTool = "3.0.1"
14 | CommonAPI-DSPModSave = "1.2.1"
15 |
16 | [build]
17 | icon = "./icon.png"
18 | readme = "./README.md"
19 | outdir = "./../Build"
20 |
21 | [[build.copy]]
22 | source = "./../Staging"
23 | target = "./"
24 |
25 | [publish]
26 | repository = "https://thunderstore.io"
27 | communities = [ "dyson-sphere-program" ]
28 | categories = [ ]
--------------------------------------------------------------------------------
/.run/PublicizeAssembly.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CommonAPI/Util/UI/ColorProperties.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace CommonAPI
4 | {
5 | [CreateAssetMenu(fileName = "Color Properties", menuName = "DSP/Color Properties", order = 0)]
6 | public class ColorProperties : ScriptableObject
7 | {
8 | [Header("Colors & Settings")] public Color powerNormalColor;
9 |
10 | public Color powerLowColor;
11 |
12 | public Color powerNormalIconColor;
13 |
14 | public Color powerLowIconColor;
15 |
16 | public Color powerOffColor;
17 |
18 | public Color idleColor;
19 |
20 | public Color workNormalColor;
21 |
22 | public Color workStoppedColor;
23 |
24 | public Color marqueeOnColor;
25 |
26 | public Color marqueeOffColor;
27 | }
28 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Submodules/CommonAPISubmoduleDependency.cs:
--------------------------------------------------------------------------------
1 | #nullable enable
2 | using System;
3 |
4 | namespace CommonAPI
5 | {
6 | #pragma warning disable 649
7 | ///
8 | /// Attribute to have at the top of your BaseUnityPlugin class if you want to load a specific R2API Submodule.
9 | /// Parameter(s) are the nameof the submodules.
10 | /// e.g: [CommonAPISubmoduleDependency("", "")]
11 | ///
12 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
13 | public class CommonAPISubmoduleDependency : Attribute {
14 | public string?[]? SubmoduleNames { get; }
15 |
16 | public CommonAPISubmoduleDependency(params string[] submoduleName) {
17 | SubmoduleNames = submoduleName;
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/Patches/CustomDataPatches.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using HarmonyLib;
5 | using UnityEngine;
6 |
7 | // ReSharper disable InconsistentNaming
8 |
9 | // ReSharper disable UnusedParameter.Global
10 | // ReSharper disable RedundantAssignment
11 |
12 | namespace CommonAPI.Patches
13 | {
14 |
15 | [HarmonyPatch]
16 | static class EntityDataSetNullPatch
17 | {
18 | [HarmonyPatch(typeof(EntityData), "SetNull")]
19 | [HarmonyPostfix]
20 | public static void SetNull(ref EntityData __instance)
21 | {
22 | __instance.customId = 0;
23 | __instance.customType = -1;
24 | __instance.customData = null;
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Interfaces/Update/IPostUpdateMultithread.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Allow this factory system to receive update calls
5 | /// This version also supports multithreading. Note that non single thread version will not get called!
6 | ///
7 | public interface IPostUpdateMultithread : IPostUpdate
8 | {
9 |
10 | ///
11 | /// This call will happen after everything else had already updated
12 | ///
13 | ///
14 | ///
15 | ///
16 | void PostUpdateMultithread(int usedThreadCount, int currentThreadIdx, int minimumCount);
17 | }
18 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/AssemblerRecipeSystem/RecipeExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI.Systems
2 | {
3 | public static class RecipeExtensions
4 | {
5 | ///
6 | /// Checks if provided belongs to recipe type
7 | ///
8 | /// Recipe
9 | /// Integer ID
10 | ///
11 | public static bool BelongsToType(this RecipeProto proto, int typeId)
12 | {
13 | AssemblerRecipeSystem.Instance.ThrowIfNotLoaded();
14 | if (typeId >= AssemblerRecipeSystem.recipeTypeLists.Count) return false;
15 |
16 | return AssemblerRecipeSystem.recipeTypeLists[typeId].BinarySearch(proto.ID) >= 0;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/UtilSystem/UtilSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using CommonAPI.Systems.Patches;
4 |
5 | namespace CommonAPI.Systems
6 | {
7 | public class UtilSystem : BaseSubmodule
8 | {
9 | internal static List> messageHandlers = new List>();
10 |
11 | internal static UtilSystem Instance => CommonAPIPlugin.GetModuleInstance();
12 |
13 | internal override void SetHooks()
14 | {
15 | CommonAPIPlugin.harmony.PatchAll(typeof(GameLoaderPatch));
16 | }
17 |
18 |
19 | public static void AddLoadMessageHandler(Func handler)
20 | {
21 | Instance.ThrowIfNotLoaded();
22 | messageHandlers.Add(handler);
23 | }
24 |
25 | }
26 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Extensions/CecilExtension.cs:
--------------------------------------------------------------------------------
1 | using Mono.Cecil;
2 |
3 | namespace CommonAPI {
4 |
5 | // Source code is taken from R2API: https://github.com/risk-of-thunder/R2API/tree/master
6 |
7 | public static class CecilExtension {
8 |
9 | internal static bool IsSubTypeOf(this TypeDefinition typeDefinition, string typeFullName) {
10 | if (typeDefinition.FullName == typeFullName) {
11 | return true;
12 | }
13 |
14 | var typeDefBaseType = typeDefinition.BaseType?.Resolve();
15 | while (typeDefBaseType != null) {
16 | if (typeDefBaseType.FullName == typeFullName) {
17 | return true;
18 | }
19 |
20 | typeDefBaseType = typeDefBaseType.BaseType?.Resolve();
21 | }
22 |
23 | return false;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Patches/StorageComponentPatch.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using HarmonyLib;
3 |
4 | namespace CommonAPI.Patches
5 | {
6 | //Fix item stack size not working
7 | [HarmonyPatch]
8 | static class StorageComponentPatch
9 | {
10 | private static bool staticLoad;
11 |
12 | [HarmonyPatch(typeof(StorageComponent), "LoadStatic")]
13 | [HarmonyPostfix]
14 | public static void Postfix()
15 | {
16 | if (!staticLoad)
17 | {
18 | foreach (var kv in ProtoRegistry.items)
19 | {
20 | StorageComponent.itemIsFuel[kv.Key] = (kv.Value.HeatValue > 0L);
21 | StorageComponent.itemStackCount[kv.Key] = kv.Value.StackSize;
22 | }
23 |
24 | staticLoad = true;
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/CommonAPITests/FakeLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CommonAPI;
3 |
4 | namespace CommonAPITests
5 | {
6 | public class FakeLogger : ICommonLogger
7 | {
8 | public void LogFatal(object data)
9 | {
10 | Console.WriteLine(data);
11 | }
12 |
13 | public void LogError(object data)
14 | {
15 | Console.WriteLine(data);
16 | }
17 |
18 | public void LogWarning(object data)
19 | {
20 | Console.WriteLine(data);
21 | }
22 |
23 | public void LogMessage(object data)
24 | {
25 | Console.WriteLine(data);
26 | }
27 |
28 | public void LogInfo(object data)
29 | {
30 | Console.WriteLine(data);
31 | }
32 |
33 | public void LogDebug(object data)
34 | {
35 | Console.WriteLine(data);
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/LocalizationModule/Patch/UIBehaviour_Patch.cs:
--------------------------------------------------------------------------------
1 | using HarmonyLib;
2 | using UnityEngine.EventSystems;
3 | using UnityEngine.UI;
4 |
5 | namespace CommonAPI.Systems.ModLocalization.Patch
6 | {
7 | public class UIBehaviour_Patch
8 | {
9 | [HarmonyPatch(typeof(UIBehaviour), "Awake")]
10 | [HarmonyPrefix]
11 | public static void OnAwake(UIBehaviour __instance)
12 | {
13 | if (__instance is Text text)
14 | {
15 | LocalizationModule.Add(text);
16 | }
17 | }
18 |
19 | [HarmonyPatch(typeof(UIBehaviour), "OnDestroy")]
20 | [HarmonyPrefix]
21 | public static void OnOnDestroy(UIBehaviour __instance)
22 | {
23 | if (__instance is Text text)
24 | {
25 | LocalizationModule.Remove(text);
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/LocalizationModule/ExtraLanguageData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 |
4 | namespace CommonAPI.Systems.ModLocalization
5 | {
6 | public class ExtraLanguageData
7 | {
8 | private Dictionary _modStrings;
9 | private Dictionary _stringsToEdit;
10 | public Font customFont;
11 |
12 | public Dictionary modStrings
13 | {
14 | get
15 | {
16 | _modStrings ??= new Dictionary();
17 | return _modStrings;
18 | }
19 | }
20 |
21 | public Dictionary stringsToEdit
22 | {
23 | get
24 | {
25 | _stringsToEdit ??= new Dictionary();
26 | return _stringsToEdit;
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/AssemblerRecipeSystem/ExtendedAssemberDesc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace CommonAPI.Systems
5 | {
6 | public class ExtendedAssemberDesc : CustomDesc
7 | {
8 | public const string RECIPE_TYPE_NAME = CommonAPIPlugin.ID + ":recipeType";
9 |
10 | public string recipeType;
11 |
12 | public float speed = 1f;
13 |
14 | public override void ApplyProperties(PrefabDesc desc)
15 | {
16 | AssemblerRecipeSystem.Instance.ThrowIfNotLoaded();
17 | desc.assemblerSpeed = Mathf.RoundToInt(speed * 10000f);
18 | desc.assemblerRecipeType = ERecipeType.Custom;
19 | desc.SetProperty(RECIPE_TYPE_NAME, AssemblerRecipeSystem.recipeTypes.GetUniqueId(recipeType));
20 |
21 | desc.isAssembler = (desc.assemblerRecipeType > ERecipeType.None);
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Patches/UIBuildMenuPatch.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using HarmonyLib;
3 |
4 | namespace CommonAPI.Patches
5 | {
6 | [HarmonyPatch]
7 | static class UIBuildMenuPatch
8 | {
9 | [HarmonyPatch(typeof(UIBuildMenu), "StaticLoad")]
10 | [HarmonyPostfix]
11 | public static void Postfix(ItemProto[,] ___protos)
12 | {
13 | foreach (var kv in ProtoRegistry.items)
14 | {
15 | int buildIndex = kv.Value.BuildIndex;
16 | if (buildIndex > 0)
17 | {
18 | int num = buildIndex / 100;
19 | int num2 = buildIndex % 100;
20 | if (num <= 12 && num2 <= 12)
21 | {
22 | ___protos[num, num2] = kv.Value;
23 | }
24 | }
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Extensions/ItemProtoExtenstion.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace CommonAPI
4 | {
5 | public static class ItemProtoExtenstion
6 | {
7 | public static void SetIcon(this ItemProto proto, string path, bool propageToRecipe = true)
8 | {
9 | if (string.IsNullOrEmpty(path)) return;
10 |
11 | Sprite sprite = Resources.Load(path);
12 |
13 | proto.IconPath = path;
14 | proto._iconSprite = sprite;
15 |
16 | if (propageToRecipe && proto.maincraft != null)
17 | {
18 | RecipeProto recipe = LDB.recipes.Select(proto.maincraft.ID);
19 | CommonAPIPlugin.logger.LogInfo($"Changing recipe icon: {recipe != null}");
20 |
21 | recipe.IconPath = "";
22 | recipe._iconSprite = sprite;
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/ComponentExtensionModule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CommonAPI.Patches;
3 |
4 | namespace CommonAPI.Systems
5 | {
6 | public class ComponentExtensionModule : BaseSubmodule
7 | {
8 | internal override Type[] Dependencies => new[] { typeof(CustomDescSystem) };
9 |
10 | internal override void SetHooks()
11 | {
12 | CommonAPIPlugin.harmony.PatchAll(typeof(CopyPastePatch));
13 | CommonAPIPlugin.harmony.PatchAll(typeof(EntityDataSetNullPatch));
14 | CommonAPIPlugin.harmony.PatchAll(typeof(UIGamePatch));
15 | }
16 |
17 | internal override void Load()
18 | {
19 | CommonAPIPlugin.registries.Add($"{CommonAPIPlugin.ID}:ComponentRegistry", ComponentExtension.componentRegistry);
20 | PlanetExtensionSystem.registry.Register(ComponentExtension.systemID, typeof(ComponentExtension));
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/KeyBindSystem/Patches/KeyBindPatches.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using CommonAPI.Systems;
4 | using HarmonyLib;
5 |
6 | namespace CommonAPI.Patches
7 | {
8 | [HarmonyPatch]
9 | public class KeyBindPatches
10 | {
11 | [HarmonyPatch(typeof(UIOptionWindow), "_OnCreate")]
12 | [HarmonyPrefix]
13 | private static void AddKeyBind(UIOptionWindow __instance)
14 | {
15 | PressKeyBind[] newKeys = CustomKeyBindSystem.customKeys.Values.ToArray();
16 | if (newKeys.Length == 0) return;
17 |
18 | int index = DSPGame.key.builtinKeys.Length;
19 | Array.Resize(ref DSPGame.key.builtinKeys, index + CustomKeyBindSystem.customKeys.Count);
20 |
21 | for (int i = 0; i < newKeys.Length; i++)
22 | {
23 | DSPGame.key.builtinKeys[index + i] = newKeys[i].defaultBind;
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/KeyBindSystem/KeyBindConflict.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI.Systems
2 | {
3 | public class KeyBindConflict
4 | {
5 | // Conflict group bit usages by game's keybindings
6 | // Each bit defines a group where two keybinds cannot have same keys
7 | // Bits after 4096 are not used
8 | public const int MOVEMENT = 1;
9 | public const int UI = 2;
10 | public const int BUILD_MODE_1 = 4;
11 | public const int BUILD_MODE_2 = 8;
12 | public const int BUILD_MODE_3 = 16;
13 | public const int INVENTORY = 32;
14 | public const int CAMERA_1 = 64;
15 | public const int CAMERA_2 = 128;
16 | public const int FLYING = 256;
17 | public const int SAILING = 512;
18 | public const int EXTRA = 1024;
19 |
20 | //Defines whether keybind uses keyboard or mouse
21 | public const int KEYBOARD_KEYBIND = 2048;
22 | public const int MOUSE_KEYBIND = 4096;
23 | }
24 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/TabSystem/UI/UITabButton.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using UnityEngine.UI;
4 |
5 | namespace CommonAPI.Systems
6 | {
7 | public class UITabButton : MonoBehaviour
8 | {
9 | public string tabName;
10 | public int tabIndex;
11 |
12 | public Localizer localizer;
13 | public UIButton button;
14 | public Image icon;
15 |
16 |
17 | public void Init(Sprite newIcon, string name, int index, Action pressCallback)
18 | {
19 | tabName = name;
20 | tabIndex = index;
21 | localizer.stringKey = tabName;
22 | icon.sprite = newIcon;
23 | button.data = index;
24 | button.onClick += pressCallback;
25 | }
26 |
27 | public void TabSelected(int index)
28 | {
29 | button.highlighted = index == tabIndex;
30 | button.button.interactable = index != tabIndex;
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PlanetExtensionSystem/Nebula/PlanetExtensionData.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using NebulaAPI;
3 | using NebulaAPI.Networking;
4 | using NebulaAPI.Packets;
5 |
6 | namespace CommonAPI.Nebula
7 | {
8 | public class PlanetExtensionData
9 | {
10 | public int planetId { get; set; }
11 | public byte[] binaryData { get; set; }
12 |
13 | public PlanetExtensionData() { }
14 | public PlanetExtensionData(int id, byte[] data)
15 | {
16 | planetId = id;
17 | binaryData = data;
18 | }
19 | }
20 |
21 | [RegisterPacketProcessor]
22 | public class PlanetExtensionDataProcessor : BasePacketProcessor
23 | {
24 | public override void ProcessPacket(PlanetExtensionData packet, INebulaConnection conn)
25 | {
26 | if (IsHost) return;
27 |
28 | PlanetExtensionSystem.pendingData.Add(packet.planetId, packet.binaryData);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Patches/VertaBufferPatch.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using CommonAPI.Systems;
3 | using HarmonyLib;
4 |
5 | namespace CommonAPI.Patches
6 | {
7 | [HarmonyPatch]
8 | static class VertaBufferPatch
9 | {
10 | [HarmonyPatch(typeof(VertaBuffer), "LoadFromFile")]
11 | [HarmonyPrefix]
12 | public static bool Prefix(ref string filename)
13 | {
14 | foreach (var resource in ProtoRegistry.modResources)
15 | {
16 | if (!filename.ToLower().Contains(resource.keyWord.ToLower()) || !resource.HasVertaFolder()) continue;
17 |
18 | string newName = $"{resource.vertaFolder}/{filename}";
19 | if (!File.Exists(newName)) continue;
20 |
21 | filename = newName;
22 | CommonAPIPlugin.logger.LogDebug("Loading registered verta file " + filename);
23 | break;
24 | }
25 |
26 | return true;
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Extensions/GeneralExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CommonAPI
4 | {
5 | public static class GeneralExtensions
6 | {
7 | public static String[] units = {"", "k", "M", "G", "T"};
8 |
9 | public static String FormatNumber(this int number)
10 | {
11 | if (number == 0) return "0";
12 | bool sign = false;
13 | if (number <= 0)
14 | {
15 | number = Math.Abs(number);
16 | sign = true;
17 | }
18 | int digitGroups = (int) (Math.Log10(number) / Math.Log10(1000));
19 | return $"{(sign ? "-" : "")}{number / Math.Pow(1000, digitGroups):0.#}" + units[digitGroups];
20 | }
21 |
22 | public static bool IsModInstalled(this string modGUID)
23 | {
24 | if (BepInEx.Bootstrap.Chainloader.PluginInfos == null) return false;
25 |
26 | return BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey(modGUID);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/LodMaterials.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | public class LodMaterials
6 | {
7 | public Material[] this[int key]
8 | {
9 | get => materials[key];
10 | set => materials[key] = value;
11 | }
12 |
13 | public LodMaterials()
14 | {
15 | materials = new Material[4][];
16 | }
17 |
18 | public LodMaterials(int lod, Material[] lod0)
19 | {
20 | materials = new Material[4][];
21 | AddLod(lod, lod0);
22 | }
23 |
24 | public LodMaterials(Material[] lod0) : this(0, lod0) { }
25 |
26 | public void AddLod(int lod, Material[] mats)
27 | {
28 | if (lod >= 0 && lod < 4)
29 | {
30 | materials[lod] = mats;
31 | }
32 | }
33 |
34 | public bool HasLod(int lod)
35 | {
36 | return materials[lod] != null;
37 | }
38 |
39 | public Material[][] materials;
40 | }
41 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/CustomDescSystem/Patches/PrefabDescPatch.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CommonAPI.Systems;
3 | using HarmonyLib;
4 |
5 | namespace CommonAPI.Patches
6 | {
7 | [HarmonyPatch]
8 | public static class PrefabDescPatch
9 | {
10 | [HarmonyPatch(typeof(PrefabDesc), "ReadPrefab")]
11 | [HarmonyPostfix]
12 | public static void Postfix(PrefabDesc __instance)
13 | {
14 | if (__instance.prefab != null)
15 | {
16 | __instance.customData = new Dictionary();
17 | CustomDesc[] descs = __instance.prefab.GetComponentsInChildren();
18 | foreach (CustomDesc desc in descs)
19 | {
20 | desc.ApplyProperties(__instance);
21 | }
22 | }
23 | }
24 |
25 |
26 | [HarmonyPatch(typeof(PrefabDesc), "Free")]
27 | [HarmonyPostfix]
28 | public static void Free(PrefabDesc __instance)
29 | {
30 | __instance.customData = null;
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/Licenses/R2API LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Risk of Thunder
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/CommonAPI/Util/Logging/LoggerWrapper.cs:
--------------------------------------------------------------------------------
1 | using BepInEx.Logging;
2 |
3 | namespace CommonAPI
4 | {
5 | ///
6 | /// Logger wrapper to appease Unit testing assembly...
7 | ///
8 | public class LoggerWrapper : ICommonLogger
9 | {
10 | public ManualLogSource logSource;
11 |
12 | public LoggerWrapper(ManualLogSource logSource)
13 | {
14 | this.logSource = logSource;
15 | }
16 |
17 |
18 | public void LogFatal(object data)
19 | {
20 | logSource.LogFatal(data);
21 | }
22 |
23 | public void LogError(object data)
24 | {
25 | logSource.LogError(data);
26 | }
27 |
28 | public void LogWarning(object data)
29 | {
30 | logSource.LogWarning(data);
31 | }
32 |
33 | public void LogMessage(object data)
34 | {
35 | logSource.LogMessage(data);
36 | }
37 |
38 | public void LogInfo(object data)
39 | {
40 | logSource.LogInfo(data);
41 | }
42 |
43 | public void LogDebug(object data)
44 | {
45 | logSource.LogDebug(data);
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/AssemblerRecipeSystem/Patches/AssemblerComponentPatch.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using HarmonyLib;
3 |
4 | namespace CommonAPI.Patches
5 | {
6 | [HarmonyPatch]
7 | public static class AssemblerComponentPatch
8 | {
9 | [HarmonyPatch(typeof(AssemblerComponent), "SetRecipe")]
10 | [HarmonyPrefix]
11 | public static bool CheckRecipe(ref AssemblerComponent __instance, int recpId, SignData[] signPool)
12 | {
13 | if (recpId > 0)
14 | {
15 | RecipeProto recipeProto = LDB.recipes.Select(recpId);
16 | if (recipeProto.Type == ERecipeType.Custom)
17 | {
18 | // ReSharper disable once Harmony003
19 | int protoId = GameMain.localPlanet.factory.entityPool[__instance.entityId].protoId;
20 | int recipeType = LDB.items.Select(protoId).prefabDesc.GetProperty(ExtendedAssemberDesc.RECIPE_TYPE_NAME);
21 | if (!recipeProto.BelongsToType(recipeType))
22 | {
23 | return false;
24 | }
25 | }
26 | }
27 |
28 | return true;
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/README.md:
--------------------------------------------------------------------------------
1 | # Picker Extension System
2 | Picker Extension system is a submodule that allows to extend behavior of Item and Recipe picker UI. The extension allows to filter which items/recipes will be shown to the player.
3 |
4 | ### Usage example:
5 | Make sure to add `[CommonAPISubmoduleDependency(nameof(PickerExtensionsSystem))]` to your plugin attributes. This will load the submodule.
6 |
7 | Show only buildings to which Assembler Mk.I can be upgraded
8 | ```cs
9 | int itemId = 2303; //Assembling machine Mk.I
10 | Vector2 pos = new Vector2(-300, 238); //Roughly center of the screen
11 | UIItemPickerExtension.Popup(pos, proto =>
12 | {
13 | // Do something
14 | }, proto => proto.Upgrades.Contains(itemId));
15 | ```
16 |
17 | Show only recipes which can be crafted by hand
18 | ```cs
19 | Vector2 pos = new Vector2(-300, 238); //Roughly center of the screen
20 | UIRecipePickerExtension.Popup(pos, proto =>
21 | {
22 | // Do something
23 | }, proto => proto.Handcraft);
24 | ```
25 |
26 | There is also an advanced usage for ItemPickerExtension which allows to define a class which acts like addon to UIItemPicker. To do so implement `IItemPickerExtension` interface. Contact me if you want an example.
27 |
--------------------------------------------------------------------------------
/CommonAPI/Util/ShotScene/Patches/PostProcessingMaterialFactoryPatch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HarmonyLib;
3 | using UnityEngine;
4 | using UnityEngine.PostProcessing;
5 |
6 | namespace CommonAPI.ShotScene.Patches
7 | {
8 | [HarmonyPatch]
9 | public static class PostProcessingMaterialFactoryPatch
10 | {
11 | public static Material modifiedMaterial;
12 |
13 | [HarmonyPatch(typeof(MaterialFactory), "Get")]
14 | [HarmonyPostfix]
15 | public static void ChangeShader(MaterialFactory __instance, string shaderName, ref Material __result)
16 | {
17 | if (!shaderName.Equals("Hidden/Post FX/Uber Shader")) return;
18 | if (!GeneratorSceneController.isShotSceneLoaded) return;
19 |
20 | if (modifiedMaterial == null)
21 | {
22 | Shader shader = (Shader)CommonAPIPlugin.resource.bundle.LoadAsset("Assets/CommonAPI/PostProcessingV1/Shaders/Uber.shader");
23 | modifiedMaterial = new Material(shader)
24 | {
25 | name = $"PostFX - {shaderName.Substring(shaderName.LastIndexOf("/", StringComparison.Ordinal) + 1)}",
26 | hideFlags = HideFlags.DontSave
27 | };
28 | }
29 | __result = modifiedMaterial;
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Submodules/BaseSubmodule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CommonAPI
4 | {
5 | public abstract class BaseSubmodule
6 | {
7 | ///
8 | /// Return true if the submodule is loaded.
9 | ///
10 | public bool Loaded { get; internal set; }
11 |
12 | internal virtual Version Build => new Version();
13 | internal virtual Type[] Dependencies => Type.EmptyTypes;
14 |
15 | internal void ThrowIfNotLoaded()
16 | {
17 | if (!Loaded)
18 | {
19 | var submoduleName = GetType().Name;
20 | string message = $"{submoduleName} is not loaded. Please use [{nameof(CommonAPISubmoduleDependency)}(nameof({submoduleName})]";
21 | throw new InvalidOperationException(message);
22 | }
23 | }
24 |
25 | internal virtual void SetHooks() {}
26 | internal virtual void Load() {}
27 | internal virtual void PostLoad() {}
28 | internal virtual void Unload() {}
29 | internal virtual void UnsetHooks() {}
30 |
31 | internal virtual bool LoadCheck()
32 | {
33 | return true;
34 | }
35 |
36 | internal virtual Type[] GetOptionalDependencies()
37 | {
38 | return Array.Empty();
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/StarExtensionSystem/Nebula/StarExtensionData.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using NebulaAPI;
3 | using NebulaAPI.Interfaces;
4 | using NebulaAPI.Networking;
5 | using NebulaAPI.Packets;
6 |
7 | namespace CommonAPI.Nebula
8 | {
9 | public class StarExtensionData
10 | {
11 | public int starIndex { get; set; }
12 | public byte[] binaryData { get; set; }
13 |
14 | public StarExtensionData() { }
15 | public StarExtensionData(int starIndex, byte[] data)
16 | {
17 | this.starIndex = starIndex;
18 | binaryData = data;
19 | }
20 | }
21 |
22 | [RegisterPacketProcessor]
23 | public class StarExtensionDataProcessor : BasePacketProcessor
24 | {
25 | public override void ProcessPacket(StarExtensionData packet, INebulaConnection conn)
26 | {
27 | if (IsHost) return;
28 |
29 | StarData star = GameMain.galaxy.StarById(packet.starIndex + 1);
30 | using IReaderProvider p = NebulaModAPI.GetBinaryReader(packet.binaryData);
31 |
32 | for (int i = 1; i < StarExtensionSystem.registry.data.Count; i++)
33 | {
34 | StarExtensionStorage extension = StarExtensionSystem.extensions[i];
35 | extension.GetSystem(star).Import(p.BinaryReader);
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/CustomDescSystem/Extensions/PrefabDescExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | public static class PrefabDescExtensions
4 | {
5 |
6 | public static bool HasProperty(this PrefabDesc desc, string name)
7 | {
8 | return desc.customData.ContainsKey(name);
9 | }
10 |
11 | public static void SetProperty(this PrefabDesc desc, string name, T value)
12 | {
13 | if (desc.customData.ContainsKey(name))
14 | {
15 | desc.customData[name] = value;
16 | }
17 | else
18 | {
19 | desc.customData.Add(name, value);
20 | }
21 | }
22 |
23 | public static T GetProperty(this PrefabDesc desc, string name)
24 | {
25 |
26 |
27 | if (desc.customData.ContainsKey(name))
28 | {
29 | return (T)desc.customData[name];
30 | }
31 |
32 | return default;
33 | }
34 |
35 | public static T GetOrAddProperty(this PrefabDesc desc, string name) where T : new()
36 | {
37 | if (desc.customData.ContainsKey(name))
38 | {
39 | return (T) desc.customData[name];
40 | }
41 |
42 | T result = new T();
43 | desc.customData.Add(name, result);
44 |
45 | return result;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/CommonAPITests/Factory/FactoryComponentTest.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI;
2 | using CommonAPI.Systems;
3 | using NUnit.Framework;
4 | using static NUnit.Framework.Assert;
5 |
6 | namespace CommonAPITests.Factory
7 | {
8 | [TestFixture]
9 | public class FactoryComponentTest
10 | {
11 | public FactoryComponent component;
12 |
13 | [SetUp]
14 | public void Setup()
15 | {
16 | component = new FactoryComponent();
17 | }
18 |
19 | [Test]
20 | public void Test()
21 | {
22 | component.SetId(4);
23 | AreEqual(4, component.GetId());
24 |
25 | component.entityId = 2;
26 | component.pcId = 8;
27 |
28 | component.Free();
29 | AreEqual(0, component.GetId());
30 | AreEqual(0, component.entityId);
31 | AreEqual(0, component.pcId);
32 |
33 | component.SetId(4);
34 | component.entityId = 2;
35 | component.pcId = 8;
36 |
37 | Util.GetSerializationSetup(w =>
38 | {
39 | component.Export(w);
40 | }, r =>
41 | {
42 | component.Free();
43 | component.Import(r);
44 | });
45 |
46 | AreEqual(4, component.GetId());
47 | AreEqual(2, component.entityId);
48 | AreEqual(8, component.pcId);
49 | }
50 |
51 | }
52 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/StarExtensionSystem/Nebula/StarExtensionLoadRequest.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using NebulaAPI;
3 | using NebulaAPI.Interfaces;
4 | using NebulaAPI.Networking;
5 | using NebulaAPI.Packets;
6 |
7 | namespace CommonAPI.Nebula
8 | {
9 | public class StarExtensionLoadRequest
10 | {
11 | public int starIndex { get; set; }
12 |
13 | public StarExtensionLoadRequest() { }
14 | public StarExtensionLoadRequest(int starIndex)
15 | {
16 | this.starIndex = starIndex;
17 | }
18 | }
19 |
20 | [RegisterPacketProcessor]
21 | public class StarExtensionLoadRequestProcessor : BasePacketProcessor
22 | {
23 | public override void ProcessPacket(StarExtensionLoadRequest packet, INebulaConnection conn)
24 | {
25 | if (IsClient) return;
26 |
27 | StarData star = GameMain.galaxy.StarById(packet.starIndex + 1);
28 | StarExtensionSystem.InitNewStar(star);
29 |
30 | using IWriterProvider p = NebulaModAPI.GetBinaryWriter();
31 |
32 | for (int i = 1; i < StarExtensionSystem.registry.data.Count; i++)
33 | {
34 | StarExtensionStorage extension = StarExtensionSystem.extensions[i];
35 | extension.GetSystem(star).Export(p.BinaryWriter);
36 | }
37 | conn.SendPacket(new StarExtensionData(packet.starIndex, p.CloseAndGetBytes()));
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/UtilSystem/LoadSaveOnLoad.cs:
--------------------------------------------------------------------------------
1 | using HarmonyLib;
2 |
3 | namespace CommonAPI
4 | {
5 | ///
6 | /// Allows to load directly into a save once the game has loaded.
7 | /// To use add loadSave <Save File Name> argument when launching the game
8 | ///
9 | [HarmonyPatch]
10 | public static class LoadSaveOnLoad
11 | {
12 | internal static string saveName;
13 | internal static bool isValid => saveName != null && !saveName.Equals("");
14 |
15 | internal static string GetArg(string name)
16 | {
17 | var args = System.Environment.GetCommandLineArgs();
18 | for (int i = 0; i < args.Length; i++)
19 | {
20 | if (args[i] == name && args.Length > i + 1)
21 | {
22 | return args[i + 1];
23 | }
24 | }
25 | return null;
26 | }
27 |
28 | internal static void Init()
29 | {
30 | saveName = GetArg("loadSave");
31 | if (isValid)
32 | {
33 | DSPGame.LoadFile = saveName;
34 | CommonAPIPlugin.logger.LogInfo($"Loading save {saveName} by default!");
35 | }
36 | }
37 |
38 | internal static void LoadSave()
39 | {
40 | if (!isValid || !GameSave.SaveExist(saveName)) return;
41 |
42 | DSPGame.StartGame(saveName);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PlanetExtensionSystem/Nebula/PlanetSystemLoadRequest.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI.Systems;
2 | using NebulaAPI;
3 | using NebulaAPI.Interfaces;
4 | using NebulaAPI.Networking;
5 | using NebulaAPI.Packets;
6 |
7 | namespace CommonAPI.Nebula
8 | {
9 | public class PlanetSystemLoadRequest
10 | {
11 | public int planetID { get; set; }
12 |
13 | public PlanetSystemLoadRequest() { }
14 | public PlanetSystemLoadRequest(int planetID)
15 | {
16 | this.planetID = planetID;
17 | }
18 | }
19 |
20 | [RegisterPacketProcessor]
21 | public class PlanetSystemLoadRequestProcessor : BasePacketProcessor
22 | {
23 | public override void ProcessPacket(PlanetSystemLoadRequest packet, INebulaConnection conn)
24 | {
25 | if (IsClient) return;
26 |
27 | PlanetData planet = GameMain.galaxy.PlanetById(packet.planetID);
28 | PlanetFactory factory = GameMain.data.GetOrCreateFactory(planet);
29 |
30 | using IWriterProvider p = NebulaModAPI.GetBinaryWriter();
31 |
32 | for (int i = 1; i < PlanetExtensionSystem.registry.data.Count; i++)
33 | {
34 | PlanetExtensionStorage extension = PlanetExtensionSystem.extensions[i];
35 | extension.GetExtension(factory).Export(p.BinaryWriter);
36 | }
37 | conn.SendPacket(new PlanetExtensionData(packet.planetID, p.CloseAndGetBytes()));
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/UI/MaterialFixer.cs:
--------------------------------------------------------------------------------
1 | using CommonAPI;
2 | using CommonAPI.Systems;
3 | using UnityEngine;
4 |
5 | namespace CommonAPI
6 | {
7 | public class MaterialFixer : MonoBehaviour
8 | {
9 | private static readonly int colorGlass = Shader.PropertyToID("_ColorGlass");
10 | private static readonly int vibrancy = Shader.PropertyToID("_Vibrancy");
11 | private static readonly int brightness = Shader.PropertyToID("_Brightness");
12 | private static readonly int flatten = Shader.PropertyToID("_Flatten");
13 |
14 | private void Start()
15 | {
16 | if (!Application.isEditor)
17 | {
18 | Material trsmat = ProtoRegistry.CreateMaterial("UI/TranslucentImage", "trs-mat", "#00000000", null,
19 | new[] {"_EMISSION"});
20 |
21 | trsmat.SetFloat(colorGlass, 1f);
22 | trsmat.SetFloat(vibrancy, 1.1f);
23 | trsmat.SetFloat(brightness, -0.5f);
24 | trsmat.SetFloat(flatten, 0.005f);
25 |
26 | TranslucentImage[] images = GetComponentsInChildren(true);
27 | foreach (TranslucentImage image in images)
28 | {
29 | image.material = trsmat;
30 | //image.vibrancy = 1.1f;
31 | //image.brightness = -0.5f;
32 | //image.flatten = 0.005f;
33 | image.spriteBlending = 0.7f;
34 | }
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/TabSystem/Patches/UIItemPickerPatch.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CommonAPI.Systems;
3 | using HarmonyLib;
4 | using UnityEngine;
5 |
6 | namespace CommonAPI.Patches
7 | {
8 | [HarmonyPatch]
9 | public class UIItemPickerPatch
10 | {
11 | private static List tabs;
12 |
13 | [HarmonyPatch(typeof(UIItemPicker), "_OnCreate")]
14 | [HarmonyPostfix]
15 | public static void Create(UIItemPicker __instance)
16 | {
17 | var datas = TabSystem.GetAllTabs();
18 | tabs = new List(datas.Length - 3);
19 |
20 | foreach (TabData tab in datas)
21 | {
22 | if (tab == null) continue;
23 |
24 | GameObject button = Object.Instantiate(TabSystem.GetTabPrefab(), __instance.pickerTrans, false);
25 | ((RectTransform)button.transform).anchoredPosition = new Vector2(70 * tab.tabIndex - 54, -75);
26 | UITabButton tabButton = button.GetComponent();
27 | Sprite sprite = Resources.Load(tab.tabIconPath);
28 | tabButton.Init(sprite, tab.tabName, tab.tabIndex, __instance.OnTypeButtonClick);
29 | tabs.Add(tabButton);
30 | }
31 | }
32 |
33 | [HarmonyPatch(typeof(UIItemPicker), "OnTypeButtonClick")]
34 | [HarmonyPostfix]
35 | public static void OnTypeClicked(int type)
36 | {
37 | foreach (UITabButton tab in tabs)
38 | {
39 | tab.TabSelected(type);
40 | }
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Extensions/HarmonyRegisterExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using HarmonyLib;
6 |
7 | namespace CommonAPI
8 | {
9 | [AttributeUsage(AttributeTargets.Class)]
10 | public class RegisterPatch : Attribute
11 | {
12 | public string typeKey;
13 |
14 | public RegisterPatch(string typeKey)
15 | {
16 | this.typeKey = typeKey;
17 | }
18 | }
19 |
20 | public static class HarmonyRegisterExtension
21 | {
22 | public static IEnumerable GetTypesWithAttributeInAssembly(Assembly assembly) where T : Attribute
23 | {
24 | return assembly.GetTypes().Where(t => t.GetCustomAttributes(typeof(T), true).Length > 0);
25 | }
26 |
27 | public static void PatchAll(this Harmony harmony, string typeKey)
28 | {
29 | Assembly assembly = Assembly.GetCallingAssembly();
30 | var types = GetTypesWithAttributeInAssembly(assembly);
31 | foreach (Type type in types)
32 | {
33 | if (type.IsClass)
34 | {
35 | RegisterPatch attribute = type.GetCustomAttribute();
36 | if (attribute.typeKey.Equals(typeKey))
37 | {
38 | harmony.PatchAll(type);
39 | }
40 | }
41 | else
42 | {
43 | CommonAPIPlugin.logger.LogInfo($"Failed to patch: {type.FullName}.");
44 | }
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/TabSystem/Patches/UIRecipePickerPatch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection.Emit;
4 | using CommonAPI.Systems;
5 | using HarmonyLib;
6 | using UnityEngine;
7 | using Object = UnityEngine.Object;
8 |
9 | namespace CommonAPI.Patches
10 | {
11 | [HarmonyPatch]
12 | public class UIRecipePickerPatch
13 | {
14 | private static List tabs;
15 |
16 | [HarmonyPatch(typeof(UIRecipePicker), "_OnCreate")]
17 | [HarmonyPostfix]
18 | public static void Create(UIRecipePicker __instance)
19 | {
20 | var datas = TabSystem.GetAllTabs();
21 | tabs = new List(datas.Length - 3);
22 |
23 | foreach (TabData tab in datas)
24 | {
25 | if (tab == null) continue;
26 |
27 | GameObject button = Object.Instantiate(TabSystem.GetTabPrefab(), __instance.pickerTrans, false);
28 | ((RectTransform)button.transform).anchoredPosition = new Vector2(70 * tab.tabIndex - 54, -75);
29 | UITabButton tabButton = button.GetComponent();
30 | Sprite sprite = Resources.Load(tab.tabIconPath);
31 | tabButton.Init(sprite, tab.tabName, tab.tabIndex, __instance.OnTypeButtonClick);
32 | tabs.Add(tabButton);
33 | }
34 | }
35 |
36 | [HarmonyPatch(typeof(UIRecipePicker), "OnTypeButtonClick")]
37 | [HarmonyPostfix]
38 | public static void OnTypeClicked(int type)
39 | {
40 | foreach (UITabButton tab in tabs)
41 | {
42 | tab.TabSelected(type);
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Data/InstanceRegistry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace CommonAPI
5 | {
6 | ///
7 | /// Data structure that allows to register instances of objects with unique string ID's
8 | ///
9 | /// Base class for all instances
10 | public class InstanceRegistry : Registry
11 | {
12 | public List data = new List();
13 |
14 | public InstanceRegistry()
15 | {
16 | data.Add(default);
17 | }
18 |
19 | public InstanceRegistry(int startId) : this(startId, false)
20 | {
21 | }
22 |
23 | public InstanceRegistry(int startId, bool throwErrorOnConflict) : base(startId, throwErrorOnConflict)
24 | {
25 | for (int i = 0; i < startId; i++)
26 | {
27 | data.Add(default);
28 | }
29 | }
30 |
31 | ///
32 | /// Register new instance
33 | ///
34 | /// Unique string ID
35 | /// instance of object
36 | /// Assigned integer ID
37 | public virtual int Register(string key, T item)
38 | {
39 | return Register(key, (object)item);
40 | }
41 |
42 | protected override void OnItemRegistered(string key, int id, object item)
43 | {
44 | if (item is T o)
45 | {
46 | data.Add(o);
47 | return;
48 | }
49 | throw new ArgumentException($"Tried to register invalid type {item.GetType().FullName}, expected {typeof(T).FullName}");
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/IPickerExtension.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI
2 | {
3 | ///
4 | /// Extend Picker behavior
5 | ///
6 | /// Target Picker
7 | public interface IPickerExtension
8 | {
9 | ///
10 | /// Called when picker with extension is open
11 | ///
12 | void Open(T picker);
13 | ///
14 | /// Called when picker with extension is closed
15 | ///
16 | void Close(T picker);
17 | ///
18 | /// Called before picker is open
19 | ///
20 | void OnPopup(T picker);
21 | ///
22 | /// Called after picker is open
23 | ///
24 | void PostPopup(T picker);
25 | }
26 |
27 | ///
28 | /// Extend Picker behavior
29 | ///
30 | /// Target Picker
31 | public interface IMouseHandlerExtension : IPickerExtension
32 | {
33 | ///
34 | /// Called when player click left mouse button
35 | ///
36 | /// Should picker close
37 | bool OnBoxMouseDown(T picker);
38 |
39 | ///
40 | /// Called when mouse position being checked for intersection
41 | ///
42 | void TestMouseIndex(T picker);
43 | }
44 |
45 | public interface IUpdatePickerExtension : IPickerExtension
46 | {
47 | void OnUpdate(T picker);
48 | }
49 |
50 | ///
51 | /// If implemented all items will be shown, even if locked
52 | ///
53 | public interface ShowLocked
54 | {
55 |
56 | }
57 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/FactoryComponent.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | public class FactoryComponent : IPoolable
6 | {
7 | public int id;
8 | public int entityId;
9 | public int pcId;
10 |
11 | public virtual void Free()
12 | {
13 | id = 0;
14 | entityId = 0;
15 | pcId = 0;
16 | }
17 |
18 | public int GetId()
19 | {
20 | return id;
21 | }
22 |
23 | public void SetId(int _id)
24 | {
25 | id = _id;
26 | }
27 |
28 | public virtual void Import(BinaryReader r)
29 | {
30 | id = r.ReadInt32();
31 | entityId = r.ReadInt32();
32 | pcId = r.ReadInt32();
33 | }
34 |
35 | public virtual void Export(BinaryWriter w)
36 | {
37 | w.Write(id);
38 | w.Write(entityId);
39 | w.Write(pcId);
40 | }
41 |
42 | public virtual void OnAdded(PrebuildData data, PlanetFactory factory) { }
43 |
44 | public virtual void OnRemoved(PlanetFactory factory) { }
45 |
46 | public virtual int InternalUpdate(float power, PlanetFactory factory)
47 | {
48 | return 0;
49 | }
50 |
51 | public virtual void UpdateAnimation(ref AnimData data, int updateResult, float power)
52 | {
53 | }
54 |
55 | public virtual void UpdateSigns(ref SignData data, int updateResult, float power, PlanetFactory factory)
56 | {
57 | }
58 |
59 | public virtual void UpdatePowerState(ref PowerConsumerComponent component) { }
60 |
61 | public virtual int[] UpdateNeeds()
62 | {
63 | return System.Array.Empty();
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/UtilSystem/Patches/GameLoaderPatch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection.Emit;
4 | using HarmonyLib;
5 |
6 | namespace CommonAPI.Systems.Patches
7 | {
8 | [HarmonyPatch]
9 | public class GameLoaderPatch
10 | {
11 | public delegate void RefAction(ref T1 arg1);
12 |
13 | [HarmonyPatch(typeof(GameLoader), "FixedUpdate")]
14 | [HarmonyTranspiler]
15 | public static IEnumerable AddModificationWarn(IEnumerable instructions)
16 | {
17 | CodeMatcher matcher = new CodeMatcher(instructions)
18 | .MatchForward(false,
19 | new CodeMatch(OpCodes.Ldloc_0),
20 | new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(string), nameof(string.IsNullOrEmpty))),
21 | new CodeMatch(OpCodes.Brtrue)
22 | )
23 | .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloca_S, 0))
24 | .InsertAndAdvance(
25 | Transpilers.EmitDelegate>((ref string text) =>
26 | {
27 | if (UtilSystem.messageHandlers.Count > 0)
28 | {
29 | foreach (Func handler in UtilSystem.messageHandlers)
30 | {
31 | string message = handler();
32 | if (!string.IsNullOrEmpty(message))
33 | {
34 | text = text + "\r\n" + message;
35 | }
36 | }
37 | }
38 | }));
39 |
40 |
41 | return matcher.InstructionEnumeration();
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/CommonAPITests/Data/PrefabDataTest.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CommonAPI;
3 | using CommonAPI.Systems;
4 | using NUnit.Framework;
5 | using static NUnit.Framework.Assert;
6 |
7 | namespace CommonAPITests
8 | {
9 | public class TestComponent : FactoryComponent
10 | {
11 |
12 | }
13 |
14 | [TestFixture]
15 | public class PrefabDataTest
16 | {
17 | public ComponentDesc component;
18 | public PrefabDesc desc;
19 |
20 | [SetUp]
21 | public void Setup()
22 | {
23 | component = new ComponentDesc();
24 | desc = new PrefabDesc
25 | {
26 | customData = new Dictionary()
27 | };
28 | }
29 |
30 | [Test]
31 | public void TestComponentDesc()
32 | {
33 | component.componentId = "TEST:ID1";
34 |
35 | ComponentExtension.componentRegistry.Register("TEST:ID1", typeof(TestComponent));
36 |
37 | int id = ComponentExtension.componentRegistry.GetUniqueId("TEST:ID1");
38 |
39 | component.ApplyProperties(desc);
40 | int id2 = desc.GetProperty(ComponentDesc.FIELD_NAME);
41 |
42 | AreEqual(id, id2);
43 | }
44 |
45 | [Test]
46 | public void TestPrefabProperties()
47 | {
48 | False(desc.HasProperty("Test"));
49 | desc.SetProperty("Test", 5);
50 | desc.SetProperty("Test", 7);
51 |
52 | True(desc.HasProperty("Test"));
53 |
54 | AreEqual(7, desc.GetProperty("Test"));
55 | AreEqual(0, desc.GetProperty("Hello"));
56 |
57 | AreEqual(7, desc.GetOrAddProperty("Test"));
58 | AreEqual(0, desc.GetOrAddProperty("Hello"));
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Patches/IconSetPatch.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using CommonAPI.Systems;
3 | using HarmonyLib;
4 | using UnityEngine;
5 |
6 | namespace CommonAPI.Patches
7 | {
8 | [HarmonyPatch]
9 | public static class IconSetPatch
10 | {
11 | [HarmonyPatch(typeof(IconSet), "Create")]
12 | [HarmonyPostfix]
13 | public static void AddIconDescs(IconSet __instance)
14 | {
15 | foreach (var kv in ProtoRegistry.itemIconDescs)
16 | {
17 | if (kv.Key <= 0 || kv.Key >= 12000) continue;
18 | uint index = __instance.itemIconIndex[kv.Key];
19 | if (index <= 0U) continue;
20 |
21 | IconToolNew.IconDesc desc = kv.Value;
22 |
23 | FieldInfo[] fields = typeof(IconToolNew.IconDesc).GetFields(BindingFlags.Instance | BindingFlags.Public);
24 | uint offset = 0;
25 |
26 | foreach (var field in fields)
27 | {
28 | if (field.FieldType == typeof(float))
29 | {
30 | __instance.itemDescArr[index * 40U + offset++] = (float)field.GetValue(desc);
31 | }else if (field.FieldType == typeof(Color))
32 | {
33 | Color color = (Color)field.GetValue(desc);
34 | __instance.itemDescArr[index * 40U + offset++] = color.r;
35 | __instance.itemDescArr[index * 40U + offset++] = color.g;
36 | __instance.itemDescArr[index * 40U + offset++] = color.b;
37 | __instance.itemDescArr[index * 40U + offset++] = color.a;
38 | }
39 | }
40 | }
41 |
42 | __instance.itemIconDescBuffer.SetData(__instance.itemDescArr);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/TabSystem/TabSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using CommonAPI.Patches;
5 | using CommonAPI.Systems;
6 | using UnityEngine;
7 |
8 | namespace CommonAPI.Systems
9 | {
10 | public class TabSystem : BaseSubmodule
11 | {
12 | internal static InstanceRegistry tabsRegistry = new InstanceRegistry(3);
13 | private static GameObject tabPrefab;
14 |
15 | internal static TabSystem Instance => CommonAPIPlugin.GetModuleInstance();
16 | internal override Type[] Dependencies => new[] { typeof(ProtoRegistry) };
17 |
18 | internal override void SetHooks()
19 | {
20 | CommonAPIPlugin.harmony.PatchAll(typeof(UIItemPickerPatch));
21 | CommonAPIPlugin.harmony.PatchAll(typeof(UIRecipePickerPatch));
22 | CommonAPIPlugin.harmony.PatchAll(typeof(UIReplicatorPatch));
23 | }
24 |
25 |
26 | public static int RegisterTab(string tabId, TabData tab)
27 | {
28 | Instance.ThrowIfNotLoaded();
29 | int tabIndex = tabsRegistry.Register(tabId, tab);
30 | tab.tabIndex = tabIndex;
31 |
32 | return tabIndex;
33 | }
34 |
35 | public static int GetTabId(string tabId)
36 | {
37 | Instance.ThrowIfNotLoaded();
38 | return tabsRegistry.GetUniqueId(tabId);
39 | }
40 |
41 | public static TabData[] GetAllTabs()
42 | {
43 | return tabsRegistry.data.ToArray();
44 | }
45 |
46 | public static GameObject GetTabPrefab()
47 | {
48 | if (tabPrefab == null)
49 | {
50 | tabPrefab = CommonAPIPlugin.resource.bundle.LoadAsset("Assets/CommonAPI/UI/tab-button.prefab");
51 | }
52 |
53 | return tabPrefab;
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/AcceptableValueOptionsList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using BepInEx.Configuration;
4 | using HarmonyLib;
5 |
6 | namespace CommonAPI
7 | {
8 | public class AcceptableValueOptionsList : AcceptableValueBase
9 | {
10 | public AcceptableValueOptionsList(string[] acceptableValues) : base(typeof (string))
11 | {
12 | if (acceptableValues == null)
13 | throw new ArgumentNullException(nameof (acceptableValues));
14 | AcceptableValues = acceptableValues.Length != 0 ? acceptableValues : throw new ArgumentException("At least one acceptable value is needed", nameof (acceptableValues));
15 | }
16 |
17 | /// List of values that a setting can take.
18 | public string[] AcceptableValues { get; }
19 |
20 | ///
21 | public override object Clamp(object value)
22 | {
23 | if (!(value is string obj))
24 | return "";
25 | string[] options = obj.Split(',');
26 | return options
27 | .Select(s => s.Trim())
28 | .Where(s => AcceptableValues.Contains(s))
29 | .Join();
30 | }
31 |
32 | ///
33 | public override bool IsValid(object value)
34 | {
35 | if (!(value is string obj))
36 | return false;
37 | string[] options = obj.Split(',');
38 | return options.All(s => AcceptableValues.Contains(s.Trim()));
39 | }
40 |
41 | ///
42 | public override string ToDescriptionString()
43 | {
44 | return $"# Acceptable values: {string.Join(", ", AcceptableValues.Select((Func)(x => x.ToString())).ToArray())}\n" +
45 | "# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)";
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/CommonAPIPublish.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{08DB0E29-5C9B-41F3-A130-4CB9CAFAED70}"
4 | ProjectSection(SolutionItems) = preProject
5 | SharedConfig.targets = SharedConfig.targets
6 | Directory.Build.targets = Directory.Build.targets
7 | EndProjectSection
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonAPI", "CommonAPI\CommonAPI.csproj", "{AF2A8839-E3B2-4CF6-8636-D3389E517974}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonAPIPreloader", "CommonAPIPreloader\CommonAPIPreloader.csproj", "{4C01DC6A-E738-47BC-841D-946A977664B2}"
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|Any CPU = Debug|Any CPU
16 | Release|Any CPU = Release|Any CPU
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Release|Any CPU.Build.0 = Release|Any CPU
23 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Release|Any CPU.Build.0 = Release|Any CPU
31 | EndGlobalSection
32 | EndGlobal
33 |
--------------------------------------------------------------------------------
/CommonAPIPreloader/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(MSBuildThisFileDirectory)/../DevEnv.targets
6 |
7 |
8 |
9 |
10 |
11 |
12 | C:\Program Files (x86)\Steam\steamapps\common\Dyson Sphere Program\
13 | $([MSBuild]::EnsureTrailingSlash('$(DSPGameDir)'))
14 | $([MSBuild]::EnsureTrailingSlash('$(SteamDir)'))
15 | $(DSPGameDir)BepInEx\core\
16 | $(DSPGameDir)DSPGAME_Data\Managed\
17 | $(DSPGameDir)BepInEx\patchers\CommonAPI\
18 | 0
19 |
20 |
21 |
22 | false
23 | false
24 |
25 | $(PluginOutputDirectory)
26 | $(MSBuildThisFileDirectory)\..\Staging\patchers\
27 | $(OutputPath)
28 | net472
29 | 8.0
30 | true
31 | true
32 | $(DefaultItemExcludes);*.binlog
33 |
34 | portable
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/CommonAPI.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{08DB0E29-5C9B-41F3-A130-4CB9CAFAED70}"
4 | ProjectSection(SolutionItems) = preProject
5 | SharedConfig.targets = SharedConfig.targets
6 | Directory.Build.targets = Directory.Build.targets
7 | EndProjectSection
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonAPI", "CommonAPI\CommonAPI.csproj", "{AF2A8839-E3B2-4CF6-8636-D3389E517974}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonAPITests", "CommonAPITests\CommonAPITests.csproj", "{FE453D25-4104-41B2-AC55-A804CCA3212E}"
12 | EndProject
13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonAPIPreloader", "CommonAPIPreloader\CommonAPIPreloader.csproj", "{4C01DC6A-E738-47BC-841D-946A977664B2}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Release|Any CPU = Release|Any CPU
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {AF2A8839-E3B2-4CF6-8636-D3389E517974}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {FE453D25-4104-41B2-AC55-A804CCA3212E}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {4C01DC6A-E738-47BC-841D-946A977664B2}.Release|Any CPU.Build.0 = Release|Any CPU
33 | EndGlobalSection
34 | EndGlobal
35 |
--------------------------------------------------------------------------------
/CommonAPI/Util/ShotScene/TPCameraController.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace CommonAPI.ShotScene
4 | {
5 | public class TPCameraController : MonoBehaviour
6 | {
7 | public Transform lookAt;
8 | public Camera camera;
9 |
10 | private float currentX = 70;
11 | private float currentY = 40;
12 |
13 | public float yAngleMin = 10f;
14 | public float yAngleMax = 85f;
15 | public float cameraDistance = 100f;
16 | public float minCameraDistance = 1f;
17 | public float scrollSensitivity = 20f;
18 | public float sensitivity = 3;
19 | public Vector3 cameraOffset = new Vector3(0,2,0);
20 |
21 | private float currentDistance;
22 |
23 |
24 | private void Start()
25 | {
26 | currentY = Mathf.Clamp(currentY, yAngleMin, yAngleMax);
27 | currentDistance = 10;
28 | camera = GetComponent();
29 |
30 | }
31 |
32 | public void RecalculatePosition()
33 | {
34 | if (lookAt == null) return;
35 |
36 | Vector3 dir = new Vector3(0, 0, -currentDistance);
37 | Quaternion rotation = Quaternion.Euler(currentY, currentX, 0);
38 | var position = lookAt.position + cameraOffset;
39 |
40 | transform.position = position + rotation * dir;
41 |
42 | transform.LookAt(position);
43 | }
44 |
45 | private void Update()
46 | {
47 | if (GeneratorSceneController.pointerInside) return;
48 |
49 | float mouseScroll = -Input.mouseScrollDelta.y * scrollSensitivity;
50 | currentDistance += mouseScroll * Time.deltaTime;
51 | currentDistance = Mathf.Clamp(currentDistance, minCameraDistance, cameraDistance);
52 |
53 | if (!Input.GetMouseButton(0)) return;
54 |
55 | currentX += Input.GetAxis("Mouse X") * sensitivity;
56 | currentY += -Input.GetAxis("Mouse Y") * sensitivity;
57 |
58 | currentY = Mathf.Clamp(currentY, yAngleMin, yAngleMax);
59 | }
60 |
61 | private void LateUpdate()
62 | {
63 | RecalculatePosition();
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/AssemblerRecipeSystem/Patches/UIAssemblerWindowPatch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Reflection.Emit;
6 | using CommonAPI.Systems;
7 | using HarmonyLib;
8 | using UnityEngine;
9 |
10 | namespace CommonAPI.Patches
11 | {
12 | [HarmonyPatch]
13 | public static class UIAssemblerWindowPatch
14 | {
15 | [HarmonyPatch(typeof(UIAssemblerWindow), "OnSelectRecipeClick")]
16 | [HarmonyTranspiler]
17 | public static IEnumerable ChangePicker(IEnumerable instructions)
18 | {
19 | CodeMatcher matcher = new CodeMatcher(instructions)
20 | .MatchForward(false,
21 | new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo) i.operand).Name == "Popup"))
22 | .Advance(-1)
23 | .SetAndAdvance(OpCodes.Ldarg_0, null)
24 | .InsertAndAdvance(Transpilers.EmitDelegate>>(window =>
25 | {
26 | int entityId = window.factorySystem.assemblerPool[window.assemblerId].entityId;
27 | ItemProto itemProto = LDB.items.Select(window.factory.entityPool[entityId].protoId);
28 | ERecipeType assemblerRecipeType = itemProto.prefabDesc.assemblerRecipeType;
29 | int customRecipeType = itemProto.prefabDesc.GetProperty(ExtendedAssemberDesc.RECIPE_TYPE_NAME);
30 |
31 | return proto =>
32 | {
33 | if (proto.Type != assemblerRecipeType) return false;
34 |
35 | if (assemblerRecipeType == ERecipeType.Custom)
36 | {
37 | return proto.BelongsToType(customRecipeType);
38 | }
39 | return true;
40 | };
41 | }))
42 | .SetInstruction(Transpilers.EmitDelegate, Func>>(UIRecipePickerExtension.Popup));
43 |
44 | return matcher.InstructionEnumeration();
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Extensions/TopologicalSortExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace CommonAPI
5 | {
6 | public static class TopologicalSortExtension
7 | {
8 | public class CyclicDependencyException : Exception
9 | {
10 | public CyclicDependencyException() : base("Cyclic dependency found")
11 | {
12 | }
13 | }
14 |
15 | public static IEnumerable TopologicalSort( this IEnumerable source, Func> dependencies, Action circularDepHandler)
16 | {
17 | var sorted = new List();
18 | var visited = new HashSet();
19 |
20 | foreach( var item in source )
21 | Visit( item, visited, sorted, dependencies, circularDepHandler);
22 |
23 | return sorted;
24 | }
25 |
26 | public static IEnumerable GetDependants( this T source, Func> dependencies, Action circularDepHandler)
27 | {
28 | var sorted = new List();
29 | var visited = new HashSet();
30 |
31 | Visit( source, visited, sorted, dependencies, circularDepHandler);
32 |
33 | return sorted;
34 | }
35 |
36 |
37 | private static void Visit(T item, HashSet visited, List sorted, Func> dependencies , Action circularDepHandler)
38 | {
39 | if( !visited.Contains( item ) )
40 | {
41 | visited.Add( item );
42 |
43 | T lastDep = default;
44 |
45 | try
46 | {
47 | foreach (var dep in dependencies(item))
48 | {
49 | lastDep = dep;
50 | Visit(dep, visited, sorted, dependencies, circularDepHandler);
51 | }
52 |
53 | sorted.Add( item );
54 | }
55 | catch (CyclicDependencyException)
56 | {
57 | circularDepHandler(item, lastDep);
58 | }
59 | }
60 | else
61 | {
62 | if( !sorted.Contains( item ) )
63 | throw new CyclicDependencyException();
64 | }
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/AssemblerRecipeSystem/AssemblerRecipeSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using CommonAPI.Patches;
5 |
6 | namespace CommonAPI.Systems
7 | {
8 | public class AssemblerRecipeSystem : BaseSubmodule
9 | {
10 | internal static Registry recipeTypes = new Registry();
11 | internal static List> recipeTypeLists = new List>();
12 |
13 |
14 | internal static AssemblerRecipeSystem Instance => CommonAPIPlugin.GetModuleInstance();
15 |
16 | internal override Type[] Dependencies => new[] { typeof(PickerExtensionsSystem), typeof(CustomDescSystem), typeof(ProtoRegistry) };
17 |
18 | internal override void SetHooks()
19 | {
20 | CommonAPIPlugin.harmony.PatchAll(typeof(AssemblerComponentPatch));
21 | CommonAPIPlugin.harmony.PatchAll(typeof(UIAssemblerWindowPatch));
22 | }
23 |
24 |
25 | internal override void Load()
26 | {
27 | CommonAPIPlugin.registries.Add($"{ CommonAPIPlugin.ID}:RecipeTypeRegistry", recipeTypes);
28 | recipeTypeLists.Add(null);
29 | }
30 |
31 | public static bool IsRecipeTypeRegistered(int type)
32 | {
33 | Instance.ThrowIfNotLoaded();
34 | return type < recipeTypeLists.Count;
35 | }
36 |
37 | ///
38 | /// Register new recipe type. This can be used to create new machine types independent of vanilla machines.
39 | ///
40 | /// Unique string ID
41 | /// Assigned integer ID
42 | public static int RegisterRecipeType(string typeId)
43 | {
44 | Instance.ThrowIfNotLoaded();
45 | int id = recipeTypes.Register(typeId);
46 | if (id >= recipeTypeLists.Capacity)
47 | {
48 | recipeTypeLists.Capacity *= 2;
49 | }
50 |
51 | recipeTypeLists.Add(new List());
52 | return id;
53 | }
54 |
55 | internal static void BindRecipeToType(RecipeProto recipe, int type)
56 | {
57 | Instance.ThrowIfNotLoaded();
58 | recipeTypeLists[type].Add(recipe.ID);
59 | Algorithms.ListSortedAdd(recipeTypeLists[type], recipe.ID);
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/KeyBindSystem/PressKeyBind.cs:
--------------------------------------------------------------------------------
1 | namespace CommonAPI.Systems
2 | {
3 | ///
4 | /// Default implementation for KeyBind press type.
5 | /// Defines what keypresses should be detected.
6 | /// Reacts only when key is pressed
7 | ///
8 | public class PressKeyBind
9 | {
10 | ///
11 | /// Is KeyBind activated?
12 | ///
13 | public bool keyValue
14 | {
15 | get
16 | {
17 | if (!VFInput.override_keys[defaultBind.id].IsNull())
18 | {
19 | return ReadKey(VFInput.override_keys[defaultBind.id]);
20 | }
21 |
22 | return ReadDefaultKey();
23 | }
24 | }
25 |
26 | ///
27 | /// Default KeyBind
28 | ///
29 | public BuiltinKey defaultBind;
30 |
31 | public void Init(BuiltinKey defaultBind)
32 | {
33 | this.defaultBind = defaultBind;
34 | }
35 |
36 | ///
37 | /// Defines how this type of KeyBind should check default KeyBind
38 | ///
39 | /// If KeyBind is activated
40 | protected virtual bool ReadDefaultKey()
41 | {
42 | return ReadKey(defaultBind.key);
43 | }
44 |
45 | ///
46 | /// Defines how this type of KeyBind should check provided KeyBind
47 | ///
48 | /// Key to check
49 | /// If KeyBind is activated
50 | protected virtual bool ReadKey(CombineKey key)
51 | {
52 | return key.GetKeyDown();
53 | }
54 | }
55 |
56 | ///
57 | /// Alternate implementation of KeyBind. Reacts only when key is held
58 | ///
59 | public class HoldKeyBind : PressKeyBind
60 | {
61 | protected override bool ReadKey(CombineKey key)
62 | {
63 | return key.GetKey();
64 | }
65 | }
66 |
67 | ///
68 | /// Alternate implementation of KeyBind. Reacts only when key is released
69 | ///
70 | public class ReleaseKeyBind : PressKeyBind
71 | {
72 | protected override bool ReadKey(CombineKey key)
73 | {
74 | return key.GetKeyUp();
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/CommonAPITests/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(MSBuildThisFileDirectory)/../DevEnv.targets
6 |
7 |
8 |
9 |
10 |
11 |
12 | C:\Program Files (x86)\Steam\steamapps\common\Dyson Sphere Program\
13 | $([MSBuild]::EnsureTrailingSlash('$(DSPGameDir)'))
14 | $([MSBuild]::EnsureTrailingSlash('$(SteamDir)'))
15 | $(DSPGameDir)BepInEx\core\
16 | $(DSPGameDir)DSPGAME_Data\Managed\
17 | $(DSPGameDir)BepInEx\plugins\CommonAPI\
18 | $(DSPGameDir)BepInEx\DumpedAssemblies\
19 | $(MSBuildThisFileDirectory)\
20 |
21 |
22 |
23 | false
24 | false
25 |
26 | net472
27 | 8.0
28 | true
29 | true
30 | $(DefaultItemExcludes);*.binlog
31 |
32 | portable
33 | true
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | $(DumpedAssembliesDir)Assembly-CSharp.dll
50 |
51 |
52 | $(DSPAssemblyDir)UnityEngine.CoreModule.dll
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Patches/ProtoSet_Patch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using HarmonyLib;
5 | using UnityEngine;
6 |
7 | namespace CommonAPI.Patches
8 | {
9 | [HarmonyPatch]
10 | public static class ProtoSet_Patch
11 | {
12 | public static bool isEnabled = true;
13 |
14 | private static Sprite icon;
15 | private static ItemProto missingItem;
16 |
17 | static MethodBase TargetMethod()
18 | {
19 | return AccessTools.Method(typeof(ProtoSet<>).MakeGenericType(typeof(ItemProto)), "Select");
20 | }
21 |
22 | [HarmonyPostfix]
23 | public static void ChangeSelectDefault(object __instance, int id, ref object __result)
24 | {
25 | if (!isEnabled) return;
26 | if (id <= 0) return;
27 |
28 | if (__instance is ProtoSet)
29 | {
30 | if (__result == null)
31 | {
32 | if (icon == null)
33 | {
34 | icon = CommonAPIPlugin.resource.bundle.LoadAsset("Assets/CommonAPI/Textures/Icons/missing-icon.png");
35 | }
36 |
37 | if (missingItem == null)
38 | {
39 | missingItem = new ItemProto()
40 | {
41 | ID = id,
42 | Name = "Unknown Item",
43 | name = "Unknown Item",
44 | Type = EItemType.Material,
45 | StackSize = 500,
46 | FuelType = 0,
47 | IconPath = "",
48 | Description = "Unknown Item",
49 | description = "Unknown Item",
50 | produceFrom = "None",
51 | GridIndex = 0,
52 | DescFields = Array.Empty(),
53 | prefabDesc = PrefabDesc.none,
54 | Upgrades = Array.Empty(),
55 | recipes = new List(),
56 | handcrafts = new List(),
57 | makes = new List(),
58 | rawMats = new List(),
59 | _iconSprite = icon
60 | };
61 | }
62 |
63 | __result = missingItem;
64 | }
65 | }
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/KeyBindSystem/README.md:
--------------------------------------------------------------------------------
1 | # Custom KeyBind system
2 | Custom KeyBind system allows to register new keybinds that:
3 | - Can be rebinded by players using options menu
4 | - Have a short localized description
5 | - Have conflict groups which define which keybinds can't share same keys
6 | - Can be easily addressed in code without using static variables
7 |
8 | ### Example usage
9 | Make sure to add `[CommonAPISubmoduleDependency(nameof(CustomKeyBindSystem))]` to your plugin attributes. This will load the submodule.
10 |
11 | First you need to define default key user has to press. This is done using CombineKey class:
12 | ```cs
13 | CombineKey key = new CombineKey(int _keyCode, byte _modifier, ECombineKeyAction _action, bool _noneKey)
14 | ```
15 | Then you can call RegisterKeyBind method to register the keybind.
16 | ```cs
17 | CustomKeyBindSystem.RegisterKeyBind(new BuiltinKey
18 | {
19 | key = key, // Default KeyBind
20 | conflictGroup = 2052, // Conflict group is a bitfield. Each bit corresponds to a key group
21 | name = "ForceBPPlace", // Name of your KeyBind.
22 | canOverride = true // Can player rebind this KeyBind?
23 | });
24 | ```
25 | When registering new KeyBind apart from parameters you also have to specify KeyBind Type. By default there are three types:
26 | - PressKeyBind
27 | - HoldKeyBind
28 | - ReleasekeyBind
29 |
30 | You can also define your own KeyBind type by creating new class extending PressKeyBind class
31 |
32 | You also need to register the localized string for the KeyBind. To do that use ProtoRegistry system. Do note that there is `KEY` appended to the localized string. This is always the case.
33 | ```cs
34 | ProtoRegistry.RegisterString("KEYForceBPPlace", "Force Blueprint placement", "强制蓝图放置");
35 | ```
36 | Finally you can use your KeyBind anywhere in your code to get current state of that key
37 | ```cs
38 | CustomKeyBindSystem.GetKeyBind("ForceBPPlace").keyValue
39 | ```
40 | ## KeyBind conflict group descriptions
41 | As stated above `conflictGroup` is a bitfield, where each bit corresponds to a key group. No KeyBinds that share the same group can have the same Key bound to them. Vanilla game has already made use of some of these. I have listed here my assumed use for each group:
42 | Bit(In decimal) | Use
43 | ---- | ----
44 | 1 | Player movement KeyBinds
45 | 2 | UI
46 | 4 | Build mode key #1
47 | 8 | Build mode key #2
48 | 16 | Build mode key #3
49 | 32 | Inventory keys
50 | 64 | Camera control keys #1
51 | 128 | Camera control keys #1
52 | 256 | Player Flying
53 | 512 | Player Sailing
54 | 1024 | No sure
55 | 2048 | Is this key on a keyboard
56 | 4096 | Is this key on a mouse
57 | Other| Not Used
58 |
--------------------------------------------------------------------------------
/CommonAPI/Util/PointsHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using UnityEngine;
4 |
5 | namespace CommonAPI
6 | {
7 | public interface IPointsAssignable
8 | {
9 | void SetPoints(Vector3[] points);
10 | }
11 |
12 | public enum PointsType
13 | {
14 | Land,
15 | Water,
16 | Insert,
17 | Belt,
18 | Custom
19 | }
20 |
21 | ///
22 | /// Helper class to assign position data to classes such as or that implement
23 | ///
24 | public class PointsHelper : MonoBehaviour
25 | {
26 | public Component target;
27 | public Transform searchPoint;
28 | public PointsType pointsType;
29 |
30 | public void Assign()
31 | {
32 | if (searchPoint == null)
33 | {
34 | searchPoint = gameObject.transform;
35 | }
36 |
37 | Transform[] transforms = searchPoint.Cast().ToArray();
38 | Vector3[] points = transforms.Select(trs => trs.position).ToArray();
39 | if (target == null)
40 | {
41 | target = GetComponent();
42 | }else if (pointsType == PointsType.Land || pointsType == PointsType.Water)
43 | {
44 | target = target.gameObject.GetComponent();
45 | }else if (pointsType == PointsType.Insert || pointsType == PointsType.Belt)
46 | {
47 | target = target.gameObject.GetComponent();
48 | }
49 |
50 | if (target == null) return;
51 |
52 | if (target is IPointsAssignable trg && pointsType == PointsType.Custom)
53 | {
54 | trg.SetPoints(points);
55 | return;
56 | }
57 |
58 | if (target is BuildConditionConfig config)
59 | {
60 | if (pointsType == PointsType.Land)
61 | {
62 | config.landPoints = points;
63 | }
64 | else
65 | {
66 | config.waterPoints = points;
67 | }
68 | }
69 |
70 | if (target is SlotConfig slots)
71 | {
72 | if (pointsType == PointsType.Insert)
73 | {
74 | slots.insertPoses = transforms;
75 | }
76 | else
77 | {
78 | slots.slotPoses = transforms;
79 | }
80 | }
81 | }
82 | }
83 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/UI/Widgets/UIPowerIndicator.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using UnityEngine;
3 | using UnityEngine.UI;
4 |
5 | namespace CommonAPI.Systems
6 | {
7 | public class UIPowerIndicator : MonoBehaviour
8 | {
9 | public Image powerIcon;
10 | public Text powerText;
11 | public Text stateText;
12 |
13 | public ColorProperties colors;
14 | private StringBuilder powerServedSb;
15 |
16 | public CustomMachineWindow window;
17 |
18 | public void Init(CustomMachineWindow window)
19 | {
20 | this.window = window;
21 | powerServedSb = new StringBuilder(" W %", 20);
22 | }
23 |
24 | public void OnUpdate(int pcId)
25 | {
26 | PowerConsumerComponent powerConsumerComponent = window.powerSystem.consumerPool[pcId];
27 | int networkId = powerConsumerComponent.networkId;
28 | PowerNetwork powerNetwork = window.powerSystem.netPool[networkId];
29 | float num = powerNetwork == null || networkId <= 0 ? 0f : (float) powerNetwork.consumerRatio;
30 | double num2 = powerConsumerComponent.requiredEnergy * 60L;
31 | long valuel = (long) (num2 * num);
32 | StringBuilderUtility.WriteKMG(powerServedSb, 8, valuel);
33 | StringBuilderUtility.WriteUInt(powerServedSb, 12, 3, (uint) (num * 100f));
34 | if (num == 1f)
35 | {
36 | powerText.text = powerServedSb.ToString();
37 | powerIcon.color = colors.powerNormalIconColor;
38 | powerText.color = colors.powerNormalColor;
39 | }
40 | else if (num > 0.1f)
41 | {
42 | powerText.text = powerServedSb.ToString();
43 | powerIcon.color = colors.powerLowIconColor;
44 | powerText.color = colors.powerLowColor;
45 | }
46 | else
47 | {
48 | powerText.text = "未供电".Translate();
49 | powerIcon.color = Color.clear;
50 | powerText.color = colors.powerOffColor;
51 | }
52 |
53 | if (num == 1f)
54 | {
55 | stateText.text = "待机".Translate();
56 | stateText.color = colors.idleColor;
57 | }
58 | else if (num > 0.1f)
59 | {
60 | stateText.text = "电力不足".Translate();
61 | stateText.color = colors.powerLowColor;
62 | }
63 | else
64 | {
65 | stateText.text = "停止运转".Translate();
66 | stateText.color = colors.powerOffColor;
67 | }
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/README.md:
--------------------------------------------------------------------------------
1 | # Submodules
2 | ## What is a submodule
3 | Each folder on this page defines a submodule. Submodule is a building block of Common API. Each submodule has a single responsibility. For example ProtoRegistrySystem allows to register new Proto objects into game's LDB to add new content.
4 |
5 | A submodule is not loaded unless another mod requests that. This is needed to ensure that CommonAPI does not break in an event where one of submodules gets broken due to game update. If that happens the player only needs to uninstall all mods that depend on the broken module, and other mods will continue to work. Because of this it is preferable to split unrelated functions into different submodules.
6 |
7 | ## Using submodules in your mods
8 | To use any submodule you have to declare that in your plugin class. Use `CommonAPISubmoduleDependency` to declare all used submodules. make sure to only request submodules your code actually uses. Also don't forget to declare a dependency on CommonAPI plugin.
9 | ```cs
10 | [BepInPlugin(GUID, NAME, VERSION)]
11 |
12 | [BepInDependency(CommonAPIPlugin.GUID)]
13 | [CommonAPISubmoduleDependency(nameof(ProtoRegistry), nameof(CustomDescSystem))]
14 | public class MyPlugin : BaseUnityPlugin
15 | {
16 | public const string MODID = "myplugin";
17 | public const string GUID = "org.myname.plugin." + MODID;
18 | public const string NAME = "My Plugin";
19 |
20 | void Awake()
21 | {
22 | //Make use of modules here
23 | }
24 | }
25 | ```
26 |
27 | ## Creating Submodules
28 | To create a new submodule you need to create a new folder with the name of the module. In it create a new class with the same name. Here is a template of submodule class:
29 | ```cs
30 | public static class SubmoduleName : BaseSubmodule
31 | {
32 |
33 | public static void SomeAPIMethod()
34 | {
35 | // Ensure that you call this method in ALL interface methods
36 | // This ensures that if your module is not loaded, a error will be thrown
37 | Instance.ThrowIfNotLoaded();
38 | }
39 |
40 | internal static SubmoduleName Instance => CommonAPIPlugin.GetModuleInstance();
41 |
42 | // To declare submodule dependency use this property
43 | internal override Type[] Dependencies => new[] { typeof(LocalizationModule) };
44 |
45 | internal override void SetHooks()
46 | {
47 | // Register all patches needed for this submodule here
48 | }
49 |
50 | internal override void load()
51 | {
52 | // Other actions not related to patches can be done here
53 | }
54 |
55 | internal override void PostLoad()
56 | {
57 | // This method will be called after all modules are loaded
58 | // Here you can use other modules functions.
59 | }
60 | }
61 |
62 | ```
63 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/TabSystem/Patches/UIReplicatorPatch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection.Emit;
4 | using CommonAPI.Systems;
5 | using HarmonyLib;
6 | using UnityEngine;
7 | using Object = UnityEngine.Object;
8 |
9 | namespace CommonAPI.Patches
10 | {
11 |
12 | [HarmonyPatch]
13 | public static class UIReplicatorPatch
14 | {
15 | private static List tabs;
16 |
17 | [HarmonyPatch(typeof(UIReplicatorWindow), "_OnCreate")]
18 | [HarmonyPostfix]
19 | public static void Create(UIReplicatorWindow __instance)
20 | {
21 | var datas = TabSystem.GetAllTabs();
22 | tabs = new List(datas.Length - 3);
23 |
24 | foreach (TabData tab in datas)
25 | {
26 | if (tab == null) continue;
27 |
28 | GameObject button = Object.Instantiate(TabSystem.GetTabPrefab(), __instance.recipeGroup, false);
29 | ((RectTransform)button.transform).anchoredPosition = new Vector2( 70 * tab.tabIndex - 95, 50);
30 | UITabButton tabButton = button.GetComponent();
31 | Sprite sprite = Resources.Load(tab.tabIconPath);
32 | tabButton.Init(sprite, tab.tabName, tab.tabIndex, __instance.OnTypeButtonClick);
33 | tabs.Add(tabButton);
34 | }
35 | }
36 |
37 | [HarmonyPatch(typeof(UIReplicatorWindow), "SetSelectedRecipe")]
38 | [HarmonyTranspiler]
39 | static IEnumerable AddNewProperty(IEnumerable instructions)
40 | {
41 | CodeMatcher matcher = new CodeMatcher(instructions)
42 | .MatchForward(false,
43 | new CodeMatch(OpCodes.Ldloc_0),
44 | new CodeMatch(OpCodes.Ldc_I4_1)
45 | ).Advance(2);
46 |
47 | Label continueLabel = (Label)matcher.Operand;
48 |
49 | matcher.Advance(-1)
50 | .InsertAndAdvance(Transpilers.EmitDelegate>(type => type >= 3 && type < TabSystem.tabsRegistry.data.Count))
51 | .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue_S, continueLabel))
52 | .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_0));
53 |
54 | return matcher.InstructionEnumeration();
55 | }
56 |
57 |
58 | [HarmonyPatch(typeof(UIReplicatorWindow), "OnTypeButtonClick")]
59 | [HarmonyPostfix]
60 | public static void OnTypeClicked(int type)
61 | {
62 | foreach (UITabButton tab in tabs)
63 | {
64 | tab.TabSelected(type);
65 | }
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/UI/UIShowSignalTipExtension.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace CommonAPI.Systems.UI
4 | {
5 | public class UIShowSignalTipExtension : IUpdatePickerExtension
6 | {
7 | private float mouseInTime;
8 | private UISignalTip screenSignalTip;
9 |
10 | public void OnUpdate(UISignalPicker picker)
11 | {
12 | int xPos = -1;
13 | int yPos = -1;
14 | int signalId = 0;
15 | if (picker.hoveredIndex >= 0)
16 | {
17 | signalId = picker.signalArray[picker.hoveredIndex];
18 | xPos = picker.hoveredIndex % 14;
19 | yPos = picker.hoveredIndex / 14;
20 | }
21 |
22 | if (signalId != 0 && signalId < 1000)
23 | {
24 | mouseInTime += Time.deltaTime;
25 | if (mouseInTime > picker.showItemTipsDelay)
26 | {
27 | if (screenSignalTip == null)
28 | {
29 | screenSignalTip = UISignalTip.Create(signalId, picker.itemTipAnchor, new Vector2(xPos * 46 + 15, -(float)yPos * 46 - 50), picker.iconImage.transform);
30 | }
31 | if (!screenSignalTip.gameObject.activeSelf)
32 | {
33 | screenSignalTip.gameObject.SetActive(true);
34 | screenSignalTip.SetTip(signalId, picker.itemTipAnchor, new Vector2(xPos * 46 + 15, -(float)yPos * 46 - 50), picker.iconImage.transform);
35 | return;
36 | }
37 | if (screenSignalTip.showingSignalId != signalId)
38 | {
39 | screenSignalTip.SetTip(signalId, picker.itemTipAnchor, new Vector2(xPos * 46 + 15, -(float)yPos * 46 - 50), picker.iconImage.transform);
40 | }
41 | }
42 | }
43 | else
44 | {
45 | CloseTip();
46 | }
47 | }
48 |
49 | public void Open(UISignalPicker picker)
50 | {
51 | CloseTip();
52 | }
53 |
54 | public void Close(UISignalPicker picker)
55 | {
56 | CloseTip();
57 | }
58 |
59 | private void CloseTip()
60 | {
61 | if (mouseInTime > 0f)
62 | {
63 | mouseInTime = 0f;
64 | }
65 |
66 | if (screenSignalTip != null)
67 | {
68 | screenSignalTip.showingSignalId = 0;
69 | screenSignalTip.gameObject.SetActive(false);
70 | }
71 | }
72 |
73 | public void OnPopup(UISignalPicker picker)
74 | {
75 | }
76 |
77 | public void PostPopup(UISignalPicker picker)
78 | {
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/LocalizationModule/TextDefaultFont.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using HarmonyLib;
3 | using UnityEngine;
4 | using UnityEngine.UI;
5 |
6 | namespace CommonAPI.Systems.ModLocalization
7 | {
8 | ///
9 | /// Additional container for Text component - this should be always present but it's not a monobehaviour.
10 | /// Use static api of to request underlying font information
11 | ///
12 | public class TextDefaultFont
13 | {
14 | ///
15 | /// Field info helper to access font data
16 | ///
17 | private static readonly FieldInfo FieldInfo_FontData = AccessTools.Field(typeof(Text), "m_FontData");
18 |
19 | ///
20 | /// Default font used by this component
21 | ///
22 | public Font DefaultFont;
23 |
24 | ///
25 | /// Stored text refernece
26 | ///
27 | public Text Reference;
28 |
29 | ///
30 | /// FontData private field reference
31 | ///
32 | private FontData FontData;
33 |
34 | ///
35 | /// Default constructor
36 | ///
37 | ///
38 | public TextDefaultFont(Text reference)
39 | {
40 | Reference = reference;
41 | FontData = (FontData)FieldInfo_FontData.GetValue(Reference);
42 | DefaultFont = FontData.font;
43 | }
44 |
45 | ///
46 | /// Method invoked exclusively by
47 | ///
48 | public void OnGetFont()
49 | {
50 | if (DefaultFont == null || FontData == null) return;
51 |
52 | int currentLanguageId = Localization.CurrentLanguageLCID;
53 | if (!LocalizationModule.extraDataEntires.ContainsKey(currentLanguageId)) return;
54 |
55 | var languageData = LocalizationModule.extraDataEntires[currentLanguageId];
56 |
57 | if (languageData.customFont != null)
58 | {
59 | if (FontData.font != languageData.customFont)
60 | {
61 | FontData.font = languageData.customFont;
62 | }
63 | }
64 | else
65 | {
66 | if (FontData.font != DefaultFont)
67 | {
68 | FontData.font = DefaultFont;
69 | }
70 | }
71 | }
72 |
73 | ///
74 | /// Apply custom fond immediately skipping TextFontManager
75 | ///
76 | ///
77 | public void UseCustomFontImmediate(Font fontToUse)
78 | {
79 | Reference.font = fontToUse;
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/CommonAPIPreloader/Preloader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using BepInEx.Logging;
5 | using Mono.Cecil;
6 | using Mono.Cecil.Rocks;
7 |
8 |
9 | namespace CommonAPI
10 | {
11 | public static class Preloader
12 | {
13 | public static ManualLogSource logSource;
14 |
15 | public static void Initialize()
16 | {
17 | logSource = Logger.CreateLogSource("Common API Preloader");
18 | }
19 | // List of assemblies to patch
20 | // ReSharper disable once InconsistentNaming
21 | public static IEnumerable TargetDLLs { get; } = new[] {"Assembly-CSharp.dll"};
22 |
23 | // Patches the assemblies
24 | public static void Patch(AssemblyDefinition assembly)
25 | {
26 | ModuleDefinition module = assembly.MainModule;
27 | TypeDefinition entityData = module.Types.First (t => t.FullName == "EntityData");
28 | TypeDefinition prefabDesc = module.Types.First (t => t.FullName == "PrefabDesc");
29 |
30 | TypeDefinition recipeType = module.Types.First (t => t.FullName == "ERecipeType");
31 |
32 | bool flag = entityData == null || prefabDesc == null || recipeType == null;
33 | if (flag)
34 | {
35 | logSource.LogInfo("Preloader patching failed!");
36 | return;
37 | }
38 |
39 | //FieldDefinition field = new FieldDefinition("customType", FieldAttributes.Public, module.ImportReference(typeof(int)));
40 | //recipeProto.Fields.Add(field);
41 | //var ca_2 = new CustomAttribute(assembly.MainModule.ImportReference(typeof(NonSerializedAttribute).GetConstructor(new Type[] {})));
42 | //field.CustomAttributes.Add(ca_2);
43 |
44 | var enumCustomValue = new FieldDefinition("Custom", FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.Public | FieldAttributes.HasDefault, recipeType) { Constant = 20 };
45 | recipeType.Fields.Add(enumCustomValue);
46 |
47 | entityData.Fields.Add(new FieldDefinition("customId", FieldAttributes.Public, module.ImportReference(typeof(int))));
48 | entityData.Fields.Add(new FieldDefinition("customType", FieldAttributes.Public, module.ImportReference(typeof(int))));
49 |
50 | entityData.Fields.Add(new FieldDefinition("customData", FieldAttributes.Public,
51 | module.ImportReference(typeof(Dictionary<,>)).MakeGenericInstanceType(module.TypeSystem.String, module.TypeSystem.Object)));
52 |
53 | prefabDesc.Fields.Add(new FieldDefinition("customData", FieldAttributes.Public,
54 | module.ImportReference(typeof(Dictionary<,>)).MakeGenericInstanceType(module.TypeSystem.String, module.TypeSystem.Object)));
55 |
56 | logSource.LogInfo("Preloader patching is successful!");
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/PickerExtensionsSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CommonAPI.Patches;
3 | using CommonAPI.Systems.ModLocalization;
4 |
5 | namespace CommonAPI.Systems
6 | {
7 | public class PickerExtensionsSystem : BaseSubmodule
8 | {
9 | internal static PickerExtensionsSystem Instance => CommonAPIPlugin.GetModuleInstance();
10 | internal override Type[] Dependencies => new[] { typeof(LocalizationModule) };
11 |
12 |
13 | internal override void SetHooks()
14 | {
15 | CommonAPIPlugin.harmony.PatchAll(typeof(UIItemPicker_Patch));
16 | CommonAPIPlugin.harmony.PatchAll(typeof(UIRecipePicker_Patch));
17 | CommonAPIPlugin.harmony.PatchAll(typeof(UISignalPicker_Patch));
18 | }
19 |
20 | internal override void PostLoad()
21 | {
22 | LocalizationModule.RegisterTranslation("SIGNAL-401", "Signal Information");
23 | LocalizationModule.RegisterTranslation("SIGNAL-402", "Signal Warning");
24 | LocalizationModule.RegisterTranslation("SIGNAL-403", "Signal Critical warning");
25 | LocalizationModule.RegisterTranslation("SIGNAL-404", "Signal Error");
26 | LocalizationModule.RegisterTranslation("SIGNAL-405", "Signal Settings");
27 |
28 | LocalizationModule.RegisterTranslation("SIGNAL-501", "Signal Missing power connection");
29 | LocalizationModule.RegisterTranslation("SIGNAL-502", "Signal Not Enough Power");
30 | LocalizationModule.RegisterTranslation("SIGNAL-503", "Signal Lightning");
31 | LocalizationModule.RegisterTranslation("SIGNAL-504", "Signal Set Recipe");
32 | LocalizationModule.RegisterTranslation("SIGNAL-506", "Signal Product stacking");
33 | LocalizationModule.RegisterTranslation("SIGNAL-507", "Signal Vein depleting");
34 | LocalizationModule.RegisterTranslation("SIGNAL-508", "Signal No fuel");
35 | LocalizationModule.RegisterTranslation("SIGNAL-509", "Signal Can't do");
36 | LocalizationModule.RegisterTranslation("SIGNAL-510", "Signal Missing connection");
37 |
38 | for (int i = 0; i < 10; i++)
39 | {
40 | LocalizationModule.RegisterTranslation($"SIGNAL-60{i}", $"Signal {i}");
41 | }
42 |
43 | LocalizationModule.RegisterTranslation("setCountManually", "Select value");
44 | LocalizationModule.RegisterTranslation("CountLabel", "Value");
45 | LocalizationModule.RegisterTranslation("ConfirmButtonLabel", "Confirm");
46 |
47 | ProtoRegistry.onLoadingFinished += () =>
48 | {
49 | for (int i = 4; i <= 6; i++)
50 | {
51 | for (int j = 0; j <= 10; j++)
52 | {
53 | SignalProto proto = LDB.signals.Select(i*100+j);
54 | proto?.Preload();
55 | }
56 | }
57 | };
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/UIItemPickerExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace CommonAPI.Systems
5 | {
6 | public class PickerNotReadyException : Exception
7 | {
8 | public PickerNotReadyException() : base("UIItemPicker is not ready!") { }
9 | }
10 |
11 | public class UIItemPickerExtension
12 | {
13 | public static Func currentFilter;
14 | public static bool showLocked = false;
15 |
16 | public static IPickerExtension currentExtension;
17 |
18 |
19 | public static UIItemPicker PreparePicker()
20 | {
21 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
22 | if (UIRoot.instance == null)
23 | {
24 | throw new PickerNotReadyException();
25 | }
26 |
27 | UIItemPicker itemPicker = UIRoot.instance.uiGame.itemPicker;
28 | if (!itemPicker.inited || itemPicker.active)
29 | {
30 | throw new PickerNotReadyException();
31 | }
32 |
33 | return itemPicker;
34 | }
35 |
36 | public static void Popup(Vector2 pos, Action _onReturn, bool showLockedItems, Func filter)
37 | {
38 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
39 | try
40 | {
41 | showLocked = showLockedItems;
42 | currentExtension = null;
43 | UIItemPicker itemPicker = PreparePicker();
44 | if (itemPicker == null)
45 | {
46 | _onReturn?.Invoke(null);
47 | }
48 |
49 | currentFilter = filter;
50 |
51 | itemPicker.onReturn = _onReturn;
52 | itemPicker._Open();
53 | itemPicker.pickerTrans.anchoredPosition = pos;
54 | }
55 | catch (PickerNotReadyException)
56 | {
57 | _onReturn?.Invoke(null);
58 | }
59 | }
60 |
61 | public static void Popup(Vector2 pos, Action _onReturn, Func filter)
62 | {
63 | Popup(pos, _onReturn, false, filter);
64 | }
65 |
66 | public static void Popup(Vector2 pos, IPickerExtension extension)
67 | {
68 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
69 | try
70 | {
71 | // ReSharper disable once SuspiciousTypeConversion.Global
72 | showLocked = extension is ShowLocked;
73 | currentExtension = extension;
74 | UIItemPicker itemPicker = PreparePicker();
75 |
76 | extension.OnPopup(itemPicker);
77 |
78 | itemPicker._Open();
79 | itemPicker.pickerTrans.anchoredPosition = pos;
80 |
81 | extension.PostPopup(itemPicker);
82 | }
83 | catch (PickerNotReadyException) { }
84 | }
85 | }
86 | }
--------------------------------------------------------------------------------
/SharedConfig.targets:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | $(MSBuildThisFileDirectory)/DevEnv.targets
7 |
8 |
9 |
10 | C:\Program Files (x86)\Steam\steamapps\common\Dyson Sphere Program\
11 | $([MSBuild]::EnsureTrailingSlash('$(DSPGameDir)'))
12 | $(DSPGameDir)BepInEx\DumpedAssemblies\DSPGAME\
13 | $(MSBuildThisFileDirectory)\
14 | $([MSBuild]::EnsureTrailingSlash('$(UnityProject)'))Assets\StreamingAssets\AssetBundles\commonapi
15 | 0
16 |
17 |
18 |
22 |
23 |
26 |
27 |
28 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/CustomDescSystem/ConfigurableDesc.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using BepInEx.Configuration;
4 | using HarmonyLib;
5 |
6 | namespace CommonAPI.Systems
7 | {
8 | [AttributeUsage(AttributeTargets.Field)]
9 | public class UseConfigFile : Attribute
10 | {
11 | public string description;
12 |
13 | public UseConfigFile(){}
14 |
15 | public UseConfigFile(string description)
16 | {
17 | this.description = description;
18 | }
19 | }
20 |
21 | public abstract class ConfigurableDesc : CustomDesc
22 | {
23 | public int tier;
24 |
25 | public abstract string configCategory { get; }
26 | public abstract ConfigFile modConfig { get; }
27 |
28 | internal static MethodInfo bindMethod;
29 |
30 | static ConfigurableDesc()
31 | {
32 | MethodInfo[] methods = typeof(ConfigFile).GetMethods(BindingFlags.Instance | BindingFlags.Public);
33 | foreach (MethodInfo method in methods)
34 | {
35 | ParameterInfo[] parameters = method.GetParameters();
36 | if (method.Name != nameof(ConfigFile.Bind) || parameters.Length != 4) continue;
37 |
38 | if (parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType == typeof(string)
39 | && parameters[3].ParameterType == typeof(string))
40 | {
41 | bindMethod = method;
42 | return;
43 | }
44 | }
45 |
46 | CommonAPIPlugin.logger.LogDebug("Failed to find MethodInfo for ConfigFile.Bind!");
47 |
48 | }
49 |
50 | public override void ApplyProperties(PrefabDesc desc)
51 | {
52 | FieldInfo[] fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
53 | foreach (FieldInfo field in fields)
54 | {
55 | if (!Attribute.IsDefined(field, typeof(UseConfigFile))) continue;
56 |
57 | UseConfigFile[] attributes = (UseConfigFile[])field.GetCustomAttributes(false);
58 | if (attributes.Length <= 0) continue;
59 |
60 | MethodInfo method = bindMethod.MakeGenericMethod(field.FieldType);
61 | object entry = method.Invoke(modConfig,
62 | new[] {configCategory, $"Tier-{tier}_{field.Name}", field.GetValue(this), attributes[0].description});
63 |
64 | Type entryGenericType = typeof(ConfigEntry<>);
65 | Type entryType = entryGenericType.MakeGenericType(field.FieldType);
66 |
67 | PropertyInfo valueProperty = entryType.GetProperty(nameof(ConfigEntry.BoxedValue));
68 |
69 | object value = valueProperty.GetValue(entry);
70 | field.SetValue(this, value);
71 | }
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/Patches/UIGamePatch.cs:
--------------------------------------------------------------------------------
1 | using HarmonyLib;
2 | using CommonAPI;
3 | using CommonAPI.Systems;
4 |
5 | // ReSharper disable InconsistentNaming
6 |
7 | namespace CommonAPI.Patches
8 | {
9 | [HarmonyPatch]
10 | public class UIGamePatch
11 | {
12 | [HarmonyPatch(typeof(UIGame), "_OnCreate")]
13 | [HarmonyPostfix]
14 | public static void OnCreate(UIGame __instance)
15 | {
16 | CustomMachineUISystem.OnCreate(__instance);
17 | }
18 |
19 | [HarmonyPatch(typeof(UIGame), "_OnDestroy")]
20 | [HarmonyPostfix]
21 | public static void OnDestroy()
22 | {
23 | foreach (var window in CustomMachineUISystem.windows)
24 | {
25 | window._Destroy();
26 | }
27 | }
28 |
29 | [HarmonyPatch(typeof(UIGame), "_OnInit")]
30 | [HarmonyPostfix]
31 | public static void OnInit(UIGame __instance)
32 | {
33 | foreach (var window in CustomMachineUISystem.windows)
34 | {
35 | window._Init(__instance.gameData);
36 | window.Open(0);
37 | }
38 | }
39 |
40 | [HarmonyPatch(typeof(UIGame), "_OnFree")]
41 | [HarmonyPostfix]
42 | public static void OnFree()
43 | {
44 | foreach (var window in CustomMachineUISystem.windows)
45 | {
46 | window._Free();
47 | }
48 | }
49 |
50 | [HarmonyPatch(typeof(UIGame), "_OnUpdate")]
51 | [HarmonyPostfix]
52 | public static void OnUpdate()
53 | {
54 | foreach (var window in CustomMachineUISystem.windows)
55 | {
56 | window.OnUpdateUI();
57 | }
58 | }
59 |
60 | [HarmonyPatch(typeof(UIGame), "ShutInventoryConflictsWindows")]
61 | [HarmonyPatch(typeof(UIGame), "ShutAllFunctionWindow")]
62 | [HarmonyPostfix]
63 | public static void ShutAllFunctionWindow()
64 | {
65 | foreach (var window in CustomMachineUISystem.windows)
66 | {
67 | window.Close();
68 | }
69 | }
70 |
71 | [HarmonyPatch(typeof(UIGame), "isAnyFunctionWindowActive", MethodType.Getter)]
72 | [HarmonyPostfix]
73 | public static void IsAnyActive(ref bool __result)
74 | {
75 | if (__result) return;
76 |
77 | foreach (var window in CustomMachineUISystem.windows)
78 | {
79 | if (window.active)
80 | {
81 | __result = true;
82 | return;
83 | }
84 | }
85 | }
86 |
87 | [HarmonyPatch(typeof(UIGame), "OnPlayerInspecteeChange")]
88 | [HarmonyPostfix]
89 | public static void OnPlayerInspecteeChange(UIGame __instance, EObjectType objType, int objId)
90 | {
91 | CustomMachineUISystem.OnPlayerInspecteeChange(__instance, objType, objId);
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/LocalizationModule/README.md:
--------------------------------------------------------------------------------
1 | # Localization Module
2 | Localization module allows to add new translations, add new translation keys and edit existing translations.
3 |
4 | ## Example usage
5 | Make sure to add `[CommonAPISubmoduleDependency(nameof(LocalizationModule))]` to your plugin attributes. This will load the submodule.
6 |
7 | ## Adding new translations
8 | There are multiple ways of adding translations.
9 |
10 | ### Through method calls
11 | using method `RegisterTranslation()`. This method is useful if you don't have a lot of strings. Example:
12 |
13 | ```cs
14 | LocalizationModule.RegisterTranslation(
15 | "copperWireDesc",
16 | "By extruding copper we can make a component which allows current to be carried");
17 | ```
18 |
19 | ### By loading a set of localization files.
20 |
21 | To do this make the following structure in your plugin folder:
22 |
23 | 
24 |
25 | You can use language ids or abbreviations, whichever you like most. For example enUS id is `1033`. For modded languages, abbreviations are the only option.
26 |
27 | Inside language folders you need to add at least one file (Can be named freely, including file extension) as you want with following structure:
28 |
29 | 
30 |
31 | There shouldn't be any headers, and in total 4 values tab separated. First is key, and last is the translation. 2'nd and 3'rd values aren't used, and only exist for compatibility with vanilla format.
32 |
33 | Then in your plugin awake do this:
34 |
35 | ```cs
36 | string pluginfolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
37 | string localePath = Path.Combine(pluginfolder, "Locale");
38 |
39 | LocalizationModule.LoadTranslationsFromFolder(localePath);
40 | ```
41 |
42 | ### From raw data strings
43 | This method can be useful if you want to load translations from a bundle. To do that, read all text of your files and call this method in your awake method:
44 |
45 | ```cs
46 | var rawString = "bla bla"; // load the raw string data here
47 | LocalizationModule.LoadTranslationsFromString(rawString, "enUS");
48 | ```
49 |
50 | The raw string must follow the same format, as described in the file section.
51 |
52 | ## Adding custom languages
53 | Localization module supports adding new languages, to do that in your plugin awake call:
54 |
55 | ```cs
56 | LocalizationModule.AddLanguage(new Localization.Language()
57 | {
58 | name = "German",
59 | abbr = "deDE",
60 | abbr2 = "de",
61 | fallback = Localization.LCID_ENUS,
62 | glyph = Localization.EGlyph.Latin
63 | });
64 | ```
65 |
66 | From here you can add translations using all ways by using `deDE` abbreviation as the key or folder name. By doing this you can even add custom localizations for the game.
67 |
68 | ## Editing existing localizations
69 | Localization module also allows to edit existing localizations. To do so write this in your plugin awake:
70 |
71 | ```cs
72 | LocalizationModule.EditTranslation("非常困难", "Very Easy!");
73 | ```
74 | The localization must already exist, for this to work. You also can edit other mods localizations.
75 |
--------------------------------------------------------------------------------
/CommonAPI/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(MSBuildThisFileDirectory)/../DevEnv.targets
6 |
7 |
8 |
9 |
10 |
11 |
12 | C:\Program Files (x86)\Steam\steamapps\common\Dyson Sphere Program\
13 | $([MSBuild]::EnsureTrailingSlash('$(DSPGameDir)'))
14 | $([MSBuild]::EnsureTrailingSlash('$(SteamDir)'))
15 | $(DSPGameDir)BepInEx\core\
16 | $(DSPGameDir)DSPGAME_Data\Managed\
17 | $(DSPGameDir)BepInEx\plugins\CommonAPI\
18 | $(DSPGameDir)BepInEx\DumpedAssemblies\
19 | $(MSBuildThisFileDirectory)\
20 | 0
21 |
22 |
23 |
24 | false
25 | false
26 |
27 | $(PluginOutputDirectory)
28 | $(MSBuildThisFileDirectory)\..\Staging\plugins\
29 | $(OutputPath)
30 | net472
31 | 8.0
32 | true
33 | true
34 | $(DefaultItemExcludes);*.binlog
35 | _UNLOCK_DEBUG
36 |
37 | portable
38 | true
39 |
40 | $(AssemblyVersion)
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/CommonAPI/NebulaCompatPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using BepInEx;
4 | using CommonAPI.Nebula;
5 | using CommonAPI.Systems;
6 | using NebulaAPI;
7 | using NebulaAPI.Interfaces;
8 |
9 | namespace CommonAPI
10 | {
11 | [BepInPlugin(GUID, NAME, CommonAPIPlugin.VERSION)]
12 | [BepInDependency(NebulaModAPI.API_GUID)]
13 | [BepInDependency(CommonAPIPlugin.GUID)]
14 | public class NebulaCompatPlugin : BaseUnityPlugin, IMultiplayerMod
15 | {
16 | public const string ID = "common-api-nebula-compat";
17 | public const string GUID = "dsp.common-tools." + ID;
18 | public const string NAME = "Common API Nebula Compatibility";
19 |
20 |
21 | private void Start()
22 | {
23 | //Moved Custom Star and Planet Systems behavior here for easier compatibility with Nebula
24 | if (CommonAPIPlugin.IsSubmoduleLoaded(nameof(PlanetExtensionSystem)))
25 | {
26 | NebulaModAPI.OnPlanetLoadRequest += planetId =>
27 | {
28 | NebulaModAPI.MultiplayerSession.Network.SendPacket(new PlanetSystemLoadRequest(planetId));
29 | };
30 | }
31 |
32 | if (CommonAPIPlugin.IsSubmoduleLoaded(nameof(StarExtensionSystem)))
33 | {
34 | NebulaModAPI.OnStarLoadRequest += starIndex =>
35 | {
36 | NebulaModAPI.MultiplayerSession.Network.SendPacket(new StarExtensionLoadRequest(starIndex));
37 | };
38 | }
39 |
40 | NebulaModAPI.RegisterPackets(Assembly.GetExecutingAssembly());
41 | CommonAPIPlugin.onIntoOtherSave = CheckNebulaInIntoOtherSave;
42 | PlanetExtensionSystem.onInitNewPlanet = HandleNebulaPacket;
43 |
44 | Logger.LogInfo("Common API Nebula Compatibility ready!");
45 | }
46 |
47 | public static void CheckNebulaInIntoOtherSave()
48 | {
49 | if (NebulaModAPI.IsMultiplayerActive && !NebulaModAPI.MultiplayerSession.LocalPlayer.IsHost)
50 | {
51 | foreach (var kv in CommonAPIPlugin.registries)
52 | {
53 | kv.Value.InitUnitMigrationMap();
54 | }
55 | }
56 | }
57 |
58 | public static void HandleNebulaPacket(PlanetData planet)
59 | {
60 | if (!NebulaModAPI.IsMultiplayerActive || NebulaModAPI.MultiplayerSession.LocalPlayer.IsHost) return;
61 | if (!PlanetExtensionSystem.pendingData.TryGetValue(planet.id, out byte[] bytes)) return;
62 | PlanetExtensionSystem.pendingData.Remove(planet.id);
63 |
64 | using IReaderProvider p = NebulaModAPI.GetBinaryReader(bytes);
65 |
66 | for (int i = 1; i < PlanetExtensionSystem.registry.data.Count; i++)
67 | {
68 | PlanetExtensionStorage extension = PlanetExtensionSystem.extensions[i];
69 | extension.GetExtension(planet.factory).Import(p.BinaryReader);
70 | }
71 | }
72 |
73 | public bool CheckVersion(string hostVersion, string clientVersion)
74 | {
75 | return hostVersion.Equals(clientVersion);
76 | }
77 |
78 | public string Version => CommonAPIPlugin.VERSION;
79 | }
80 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/UISignalPickerExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using CommonAPI.Systems.UI;
4 | using UnityEngine;
5 | using Object = UnityEngine.Object;
6 |
7 | namespace CommonAPI.Systems
8 | {
9 | public class UISignalPickerExtension
10 | {
11 | public static Func currentFilter;
12 |
13 | public static List> extensions = new List>();
14 |
15 | private static UIShowSignalTipExtension tipHandler;
16 |
17 | public static UISignalPicker PreparePicker()
18 | {
19 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
20 | if (UIRoot.instance == null)
21 | {
22 | throw new PickerNotReadyException();
23 | }
24 |
25 | UISignalPicker signalPicker = UIRoot.instance.uiGame.signalPicker;
26 | if (!signalPicker.inited || signalPicker.active)
27 | {
28 | throw new PickerNotReadyException();
29 | }
30 |
31 | return signalPicker;
32 | }
33 |
34 | internal static UIShowSignalTipExtension GetTipExtension()
35 | {
36 | if (tipHandler == null)
37 | {
38 | tipHandler = new UIShowSignalTipExtension();
39 | }
40 |
41 | return tipHandler;
42 | }
43 |
44 | ///
45 | /// Open UIRecipePicker with custom filters
46 | ///
47 | /// position on screen
48 | /// callback to call, when user selects an item
49 | /// Filter function
50 | public static void Popup(Vector2 pos, Action _onReturn, Func filter)
51 | {
52 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
53 | try
54 | {
55 | extensions.Clear();
56 | extensions.Add(GetTipExtension());
57 |
58 | UISignalPicker signalPicker = PreparePicker();
59 | if (signalPicker == null)
60 | {
61 | _onReturn?.Invoke(0);
62 | }
63 |
64 | currentFilter = filter;
65 |
66 | signalPicker.onReturn = _onReturn;
67 | signalPicker._Open();
68 | signalPicker.pickerTrans.anchoredPosition = pos;
69 | }
70 | catch (PickerNotReadyException)
71 | {
72 | _onReturn?.Invoke(0);
73 | }
74 | }
75 |
76 | public static void Popup(Vector2 pos, IPickerExtension extension)
77 | {
78 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
79 | try
80 | {
81 | extensions.Clear();
82 | extensions.Add(GetTipExtension());
83 | extensions.Add(extension);
84 | UISignalPicker signalPicker = PreparePicker();
85 |
86 | extension.OnPopup(signalPicker);
87 |
88 | signalPicker._Open();
89 | signalPicker.pickerTrans.anchoredPosition = pos;
90 |
91 | extension.PostPopup(signalPicker);
92 | }
93 | catch (PickerNotReadyException) { }
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/Networks/NetworksSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace CommonAPI
6 | {
7 | public class NetworksSystem : BaseSubmodule
8 | {
9 | public static List handlers = new List();
10 |
11 | internal static NetworksSystem Instance => CommonAPIPlugin.GetModuleInstance();
12 |
13 |
14 | internal override void Load()
15 | {
16 | AddHandler(new PowerNetworkHandler());
17 | }
18 |
19 | public static void AddHandler(NetworkHandler handler)
20 | {
21 | handlers.Add(handler);
22 | }
23 |
24 | public static bool IsConnectedToNetwork(PlanetFactory factory, int objId)
25 | {
26 | Instance.ThrowIfNotLoaded();
27 | try
28 | {
29 | NetworkHandler handler = GetNetworkHandler(factory, objId);
30 | return handler != null;
31 | }
32 | catch (InvalidOperationException)
33 | {
34 | return false;
35 | }
36 | }
37 |
38 | public static bool IsConnectedToSameNetwork(PlanetFactory factory, int firstId, int secondId)
39 | {
40 | Instance.ThrowIfNotLoaded();
41 | try
42 | {
43 | NetworkHandler handler = GetCommonNetwork(factory, firstId, secondId);
44 | return handler != null;
45 | }
46 | catch (InvalidOperationException)
47 | {
48 | return false;
49 | }
50 | }
51 |
52 | public static NetworkHandler GetNetworkHandler(PlanetFactory factory, int objId)
53 | {
54 | Instance.ThrowIfNotLoaded();
55 | if (objId == 0) return null;
56 |
57 | int protoId = objId > 0 ? factory.entityPool[objId].protoId : factory.prebuildPool[-objId].protoId;
58 | ItemProto itemProto = LDB.items.Select(protoId);
59 |
60 | if (itemProto == null) return null;
61 | try
62 | {
63 | return handlers.First(handler => handler.IsRelatedTo(itemProto)).Prepare(factory);
64 | }
65 | catch (InvalidOperationException)
66 | {
67 | return null;
68 | }
69 | }
70 |
71 | public static NetworkHandler GetCommonNetwork(PlanetFactory factory, int firstId, int secondId)
72 | {
73 | Instance.ThrowIfNotLoaded();
74 | if (firstId == 0 || secondId == 0) return null;
75 |
76 | int firstProtoId = firstId > 0 ? factory.entityPool[firstId].protoId : factory.prebuildPool[-firstId].protoId;
77 | int secondProtoId = secondId > 0 ? factory.entityPool[secondId].protoId : factory.prebuildPool[-secondId].protoId;
78 | ItemProto firstItemProto = LDB.items.Select(firstProtoId);
79 | ItemProto secondItemProto = LDB.items.Select(secondProtoId);
80 |
81 | if (firstItemProto == null || secondItemProto == null) return null;
82 |
83 | try
84 | {
85 | return handlers.First(handler => handler.IsRelatedTo(firstItemProto) && handler.IsRelatedTo(secondItemProto)).Prepare(factory);
86 | }
87 | catch (InvalidOperationException)
88 | {
89 | return null;
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/Patches/ResourcesPatch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CommonAPI.Systems;
3 | using HarmonyLib;
4 | using UnityEngine;
5 | using Object = UnityEngine.Object;
6 |
7 | namespace CommonAPI.Patches
8 | {
9 | //Loading custom resources
10 | [HarmonyPatch]
11 | static class ResourcesPatch
12 | {
13 | [HarmonyPatch(typeof(Resources), "Load", typeof(string), typeof(Type))]
14 | [HarmonyPrefix]
15 | public static bool Prefix(ref string path, Type systemTypeInstance, ref Object __result)
16 | {
17 | foreach (ResourceData resource in ProtoRegistry.modResources)
18 | {
19 | if (!path.Contains(resource.keyWord) || !resource.HasAssetBundle()) continue;
20 |
21 | if (resource.bundle.Contains(path + ".prefab") && systemTypeInstance == typeof(GameObject))
22 | {
23 | Object myPrefab = resource.bundle.LoadAsset(path + ".prefab");
24 | CommonAPIPlugin.logger.LogDebug($"Loading registered asset {path}: {(myPrefab != null ? "Success" : "Failure")}");
25 |
26 | if (!ProtoRegistry.modelMats.ContainsKey(path))
27 | {
28 | __result = myPrefab;
29 | return false;
30 | }
31 |
32 | LodMaterials mats = ProtoRegistry.modelMats[path];
33 | if (myPrefab != null && mats.HasLod(0))
34 | {
35 | MeshRenderer[] renderers = ((GameObject) myPrefab).GetComponentsInChildren();
36 | foreach (MeshRenderer renderer in renderers)
37 | {
38 | Material[] newMats = new Material[renderer.sharedMaterials.Length];
39 | for (int i = 0; i < newMats.Length; i++)
40 | {
41 | newMats[i] = mats[0][i];
42 | }
43 |
44 | renderer.sharedMaterials = newMats;
45 | }
46 | }
47 |
48 | __result = myPrefab;
49 | return false;
50 | }
51 |
52 | foreach (string extension in ProtoRegistry.spriteFileExtensions)
53 | {
54 | if (!resource.bundle.Contains(path + extension)) continue;
55 |
56 | Object mySprite = resource.bundle.LoadAsset(path + extension, systemTypeInstance);
57 |
58 | CommonAPIPlugin.logger.LogDebug($"Loading registered asset {path}: {(mySprite != null ? "Success" : "Failure")}");
59 |
60 | __result = mySprite;
61 | return false;
62 | }
63 |
64 | foreach (string extension in ProtoRegistry.audioClipFileExtensions)
65 | {
66 | if (!resource.bundle.Contains(path + extension)) continue;
67 |
68 | Object myAudioClip = resource.bundle.LoadAsset(path + extension, systemTypeInstance);
69 |
70 | CommonAPIPlugin.logger.LogDebug($"Loading registered asset {path}: {(myAudioClip != null ? "Success" : "Failure")}");
71 |
72 | __result = myAudioClip;
73 | return false;
74 | }
75 | }
76 |
77 | return true;
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/StarExtensionSystem/Patches/StarExtensionHooks.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CommonAPI.Systems;
3 | using HarmonyLib;
4 |
5 | namespace CommonAPI.Patches
6 | {
7 | [HarmonyPatch]
8 | public static class StarExtensionHooks
9 | {
10 | [HarmonyPatch(typeof(GameData), "OnDraw")]
11 | [HarmonyPostfix]
12 | public static void DrawCall(GameData __instance, int frame)
13 | {
14 | // PerformanceMonitor.BeginSample(ECpuWorkEntry.DrawCall);
15 | StarExtensionSystem.DrawUpdate();
16 | //PerformanceMonitor.EndSample(ECpuWorkEntry.DrawCall);
17 | }
18 |
19 | //Single thread update calls
20 | /* [HarmonyPatch(typeof(GameData), "GameTick")]
21 | [HarmonyPrefix]
22 | public static void PreUpdateST(GameData __instance, long time)
23 | {
24 | if (GameMain.multithreadSystem.multithreadSystemEnable)
25 | {
26 | PerformanceMonitor.BeginSample(ECpuWorkEntry.DysonSphere);
27 | StarExtensionSystem.PreUpdateOnlySinglethread();
28 | PerformanceMonitor.EndSample(ECpuWorkEntry.DysonSphere);
29 | return;
30 | }
31 |
32 | PerformanceMonitor.BeginSample(ECpuWorkEntry.DysonSphere);
33 | for (int i = 0; i < GameMain.galaxy.starCount; i++)
34 | {
35 | StarData star = GameMain.galaxy.stars[i];
36 | if (star == null) continue;
37 |
38 | StarExtensionSystem.PreUpdate(star);
39 | }
40 | PerformanceMonitor.EndSample(ECpuWorkEntry.DysonSphere);
41 | }*/
42 | /*
43 | [HarmonyPatch(typeof(TrashSystem), "GameTick")]
44 | [HarmonyPostfix]
45 | public static void UpdateST(TrashSystem __instance, long time)
46 | {
47 | if (GameMain.multithreadSystem.multithreadSystemEnable)
48 | {
49 | PerformanceMonitor.EndSample(ECpuWorkEntry.Trash);
50 | PerformanceMonitor.BeginSample(ECpuWorkEntry.DysonSphere);
51 | StarExtensionSystem.UpdateOnlySinglethread();
52 | PerformanceMonitor.EndSample(ECpuWorkEntry.DysonSphere);
53 | PerformanceMonitor.BeginSample(ECpuWorkEntry.Trash);
54 | return;
55 | }
56 |
57 | PerformanceMonitor.EndSample(ECpuWorkEntry.Trash);
58 | PerformanceMonitor.BeginSample(ECpuWorkEntry.DysonSphere);
59 | for (int i = 0; i < GameMain.galaxy.starCount; i++)
60 | {
61 | StarData star = GameMain.galaxy.stars[i];
62 | if (star == null) continue;
63 |
64 | StarExtensionSystem.Update(star);
65 | }
66 | PerformanceMonitor.EndSample(ECpuWorkEntry.DysonSphere);
67 | PerformanceMonitor.BeginSample(ECpuWorkEntry.Trash);
68 | }*/
69 |
70 | //Multi-thread update calls, used only if player system support multithreading
71 |
72 | //TODO improve multi-thread calls
73 |
74 | [HarmonyPatch(typeof(DysonSphere), "RocketGameTick", typeof(int), typeof(int), typeof(int))]
75 | [HarmonyPostfix]
76 | public static void PowerTickMultithread(DysonSphere __instance, int _usedThreadCnt, int _curThreadIdx)
77 | {
78 | StarExtensionSystem.UpdateMultithread(__instance.starData, _usedThreadCnt, _curThreadIdx, 12);
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/UI/CustomMachineUISystem.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CommonAPI.Systems;
3 | using HarmonyLib;
4 | using UnityEngine;
5 |
6 | namespace CommonAPI.Systems
7 | {
8 | public static class CustomMachineUISystem
9 | {
10 | public static List windows = new List();
11 | public static List registeredPrefabs = new List();
12 |
13 | public static int customInspectId;
14 | public static CustomMachineWindow openWindow;
15 |
16 | public static void RegisterWindow(string prefabPath)
17 | {
18 | if (!registeredPrefabs.Contains(prefabPath))
19 | {
20 | registeredPrefabs.Add(prefabPath);
21 | CommonAPIPlugin.logger.LogDebug("Registering machine window, prefab: " + prefabPath);
22 | }
23 | }
24 |
25 | public static void RefreshOpenWindow()
26 | {
27 | if (openWindow != null)
28 | {
29 | openWindow.OnIdChange();
30 | }
31 | }
32 |
33 | internal static void OnCreate(UIGame uiGame)
34 | {
35 | CommonAPIPlugin.logger.LogInfo("Loading custom UI's");
36 | Transform windowsObject = uiGame.canvasGroup.transform.Find("Windows");
37 | if (windowsObject == null) return;
38 |
39 | foreach (var path in registeredPrefabs)
40 | {
41 | GameObject windowPrefab = Resources.Load(path);
42 | if (windowPrefab == null)
43 | {
44 | CommonAPIPlugin.logger.LogError($"Error loading UI prefab: {path}!");
45 | continue;
46 | }
47 | GameObject windowObject = Object.Instantiate(windowPrefab, windowsObject, false);
48 |
49 | CustomMachineWindow machineWindow = windowObject.GetComponent();
50 | machineWindow._Create();
51 | windows.Add(machineWindow);
52 | }
53 |
54 | registeredPrefabs.Clear();
55 | }
56 |
57 | internal static void OnPlayerInspecteeChange(UIGame uiGame, EObjectType objType, int objId)
58 | {
59 | PlanetFactory factory = GameMain.mainPlayer.factory;
60 | int componentId = -1;
61 | int protoId = 0;
62 | if (factory != null && objType == EObjectType.Entity && objId > 0)
63 | {
64 | componentId = factory.entityPool[objId].customType;
65 | protoId = factory.entityPool[objId].protoId;
66 | }
67 |
68 | CustomMachineWindow currentWindow = null;
69 |
70 | foreach (var window in windows)
71 | {
72 | if (window.ShouldOpen(componentId, protoId))
73 | {
74 | currentWindow = window;
75 | break;
76 | }
77 | }
78 |
79 | if (currentWindow == null) return;
80 |
81 | if (objId > 0 && customInspectId != objId)
82 | {
83 | if (currentWindow.DoCloseOtherWindows())
84 | uiGame.ShutAllFunctionWindow();
85 |
86 | if (currentWindow.DoClosePlayerInventory())
87 | uiGame.ShutPlayerInventory();
88 |
89 | currentWindow.Open(objId);
90 | }
91 | else if (objId == 0 && customInspectId > 0)
92 | {
93 | currentWindow.Close();
94 | }
95 |
96 | customInspectId = objId;
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/UIRecipePickerExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace CommonAPI.Systems
5 | {
6 | public class UIRecipePickerExtension
7 | {
8 | public static Func currentFilter;
9 | public static bool showLocked = false;
10 |
11 | public static IPickerExtension currentExtension;
12 |
13 |
14 | public static UIRecipePicker PreparePicker()
15 | {
16 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
17 | if (UIRoot.instance == null)
18 | {
19 | throw new PickerNotReadyException();
20 | }
21 |
22 | UIRecipePicker recipePicker = UIRoot.instance.uiGame.recipePicker;
23 | if (!recipePicker.inited || recipePicker.active)
24 | {
25 | throw new PickerNotReadyException();
26 | }
27 |
28 | return recipePicker;
29 | }
30 |
31 | ///
32 | /// Open UIRecipePicker with custom filters
33 | ///
34 | /// position on screen
35 | /// callback to call, when user selects an item
36 | /// Should locked items be visible
37 | /// Filter function
38 | public static void Popup(Vector2 pos, Action _onReturn, bool showLockedRecipes, Func filter)
39 | {
40 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
41 | try
42 | {
43 | showLocked = showLockedRecipes;
44 | currentExtension = null;
45 | UIRecipePicker recipePicker = PreparePicker();
46 | if (recipePicker == null)
47 | {
48 | _onReturn?.Invoke(null);
49 | }
50 |
51 | currentFilter = filter;
52 |
53 | recipePicker.filter = ERecipeType.None;
54 | recipePicker.onReturn = _onReturn;
55 | recipePicker._Open();
56 | recipePicker.pickerTrans.anchoredPosition = pos;
57 | }
58 | catch (PickerNotReadyException)
59 | {
60 | _onReturn?.Invoke(null);
61 | }
62 | }
63 |
64 | ///
65 | /// Open UIRecipePicker with custom filters
66 | ///
67 | /// position on screen
68 | /// callback to call, when user selects an item
69 | /// Filter function
70 | public static void Popup(Vector2 pos, Action _onReturn, Func filter)
71 | {
72 | Popup(pos, _onReturn, false, filter);
73 | }
74 |
75 | public static void Popup(Vector2 pos, IPickerExtension extension)
76 | {
77 | PickerExtensionsSystem.Instance.ThrowIfNotLoaded();
78 | try
79 | {
80 | // ReSharper disable once SuspiciousTypeConversion.Global
81 | showLocked = extension is ShowLocked;
82 | currentExtension = extension;
83 | UIRecipePicker recipePicker = PreparePicker();
84 |
85 | extension.OnPopup(recipePicker);
86 |
87 | recipePicker._Open();
88 | recipePicker.pickerTrans.anchoredPosition = pos;
89 |
90 | extension.PostPopup(recipePicker);
91 | }
92 | catch (PickerNotReadyException) { }
93 | }
94 | }
95 | }
--------------------------------------------------------------------------------
/.github/workflows/workflow.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | env:
10 | BundleBepInEx : false
11 | BepInExVersion : 5
12 | BepInExArch : x64
13 | BepInExRuntime : IL2CPP
14 | PluginName : CommonAPI-CommonAPI
15 | GithubRelease : true
16 | ThunderstoreRelease: true
17 | PublishNuget: true
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | with:
22 | submodules: true
23 | fetch-depth: 0 # can't shallowly clone due to git versioning
24 |
25 | - name: Get version of the project
26 | id: get-version
27 | uses: 'euberdeveloper/ga-project-version@main'
28 | with:
29 | path: 'version.json'
30 |
31 | - name: Check Tag
32 | id: check-tag
33 | uses: actions-ecosystem/action-regex-match@v2
34 | with:
35 | text: ${{ steps.get-version.outputs.version }}
36 | regex: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
37 |
38 | - name: Fail if invalid
39 | if: steps.check-tag.outputs.match == ''
40 | uses: Actions/github-script@v3
41 | with:
42 | script: |
43 | core.setFailed('Invalid tag')
44 |
45 | - uses: actions/setup-dotnet@v1
46 |
47 | - name: BepInEx 6
48 | run: |
49 | bepinexurl = $(curl -vs https://builds.bepinex.dev/projects/bepinex_be 2>&1 | grep -Po '(?<=href=")(\/projects\/bepinex_be\/(.*)\/BepInEx_Unity${{env.BepInExRuntime}}_${{env.BepInExArch}}(.*))(?=")' | head -1)"
50 | wget $bepinexurl > bepinex.zip
51 | if: env.BundleBepInEx == 'true' && env.BepInExVersion == '6'
52 |
53 | - name: BepInEx 5
54 | shell: pwsh
55 | run: |
56 | $webData = Invoke-WebRequest -Uri "https://api.github.com/repos/BepInEx/BepInEx/releases/latest"
57 | $release = ConvertFrom-Json $webData.content
58 | $bepinexurl = $release.assets.browser_download_url -match '${{env.BepInExArch}}'
59 | wget $bepinexurl > bepinex.zip
60 | if: env.BundleBepInEx == 'true' && env.BepInExVersion == '5'
61 |
62 | - name: Extract BepInEx
63 | run: |
64 | mkdir out;
65 | unzip BepInEx* -d out;
66 | if: env.BundleBepInEx == 'true'
67 |
68 | - name: Setup Thunderstore CLI
69 | run: |
70 | dotnet tool install -g tcli
71 |
72 | - name: Build & zip
73 | run: |
74 | dotnet build CommonAPIPublish.sln -c Release /p:ReleaseMode=1
75 | tcli build --config-path Config/thunderstore.toml --package-version ${{ steps.get-version.outputs.version }}
76 |
77 | - name: Publish to Github
78 | uses: ncipollo/release-action@v1
79 | with:
80 | artifacts: "Build/*.zip"
81 | tag: ${{ steps.get-version.outputs.version }}
82 | commit: ${{ github.ref }}
83 | artifactErrorsFailBuild: true
84 | draft: true
85 | allowUpdates: true
86 | if: env.GithubRelease == 'true'
87 |
88 | - name: Publish to Thunderstore
89 | env:
90 | TCLI_AUTH_TOKEN: ${{ secrets.TCLI_AUTH_TOKEN }}
91 | run: |
92 | tcli publish --config-path Config/thunderstore.toml --package-version ${{ steps.get-version.outputs.version }}
93 | if: env.ThunderstoreRelease == 'true'
94 |
95 | - name: Publish to NuGet
96 | run: |
97 | dotnet pack CommonAPI/CommonAPI.csproj /p:ReleaseMode=1 -c Release -o "."
98 | dotnet nuget push *.nupkg -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} --skip-duplicate
99 | if: env.PublishNuget == 'true'
--------------------------------------------------------------------------------
/CommonAPI/Systems/ProtoRegistrySystem/ResourceData.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Reflection;
3 | using JetBrains.Annotations;
4 | using UnityEngine;
5 |
6 | namespace CommonAPI.Systems
7 | {
8 | ///
9 | /// Mod resources definition class. Use this class to load your asset bundles and resolve verta folder paths
10 | ///
11 | [UsedImplicitly]
12 | public class ResourceData
13 | {
14 | public string modId;
15 | public string modPath;
16 | public string keyWord;
17 |
18 | public AssetBundle bundle;
19 | public string vertaFolder;
20 |
21 | ///
22 | /// Create new resource definition
23 | ///
24 | /// Your mod ID
25 | /// Unique Keyword used only by your mods
26 | /// Path to mod's main assembly
27 | public ResourceData(string modId, string keyWord, string modPath)
28 | {
29 | this.modId = modId;
30 | this.modPath = modPath;
31 | this.keyWord = keyWord;
32 | }
33 |
34 | ///
35 | /// Create new resource definition. Path is inferred from what assembly is calling.
36 | ///
37 | /// Your mod ID
38 | /// Unique Keyword used only by your mods
39 | public ResourceData(string modId, string keyWord)
40 | {
41 | this.modId = modId;
42 | this.modPath = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
43 | this.keyWord = keyWord;
44 | }
45 |
46 | ///
47 | /// Does this resource definition have a resolved verta folder
48 | ///
49 | public bool HasVertaFolder()
50 | {
51 | return !vertaFolder.Equals("");
52 | }
53 |
54 | ///
55 | /// Does this resource definition have a asset bundle loaded
56 | ///
57 | public bool HasAssetBundle()
58 | {
59 | return bundle != null;
60 | }
61 |
62 | ///
63 | /// Load asset bundle from mod path.
64 | ///
65 | /// Bundle name
66 | /// Thrown if loading an asset bundle has failed
67 | public void LoadAssetBundle(string bundleName)
68 | {
69 | bundle = AssetBundle.LoadFromFile($"{modPath}/{bundleName}");
70 | if (bundle == null)
71 | {
72 | throw new LoadException($"Failed to load asset bundle at {modPath}/{bundleName}");
73 | }
74 | }
75 |
76 | ///
77 | /// Try to resolve where verta folder is located. Two checked paths are [modPath]/Verta and [modPath]/plugins/Verta
78 | ///
79 | ///
80 | public void ResolveVertaFolder()
81 | {
82 | FileInfo folder = new FileInfo($"{modPath}/Verta/");
83 | FileInfo folder1 = new FileInfo($"{modPath}/plugins/");
84 |
85 | if (Directory.Exists(folder.Directory?.FullName))
86 | {
87 | vertaFolder = modPath;
88 | }
89 | else if (Directory.Exists(folder1.Directory?.FullName))
90 | {
91 | vertaFolder = $"{modPath}/plugins";
92 | }
93 | else
94 | {
95 | vertaFolder = "";
96 | throw new LoadException($"Failed to resolve verta folder at {modPath}");
97 | }
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/CommonAPI/Util/Extensions/ConfigFileExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Reflection;
5 | using BepInEx.Configuration;
6 | using HarmonyLib;
7 |
8 | namespace CommonAPI
9 | {
10 | public static class ConfigFileExtension
11 | {
12 | public static Type configFile;
13 | public static PropertyInfo OrphanedEntriesProp;
14 |
15 | static ConfigFileExtension()
16 | {
17 | configFile = AccessTools.TypeByName("BepInEx.Configuration.ConfigFile");
18 | OrphanedEntriesProp = configFile.GetProperty("OrphanedEntries", AccessTools.all);
19 | }
20 |
21 | ///
22 | /// Migrate BepInEx config file entries from one category to another.
23 | ///
24 | /// target BepInEx config file
25 | /// Section to migrate from
26 | /// Section to migrate to
27 | /// Array of keys to migrate
28 | /// Type of config entries
29 | public static void MigrateConfig(this ConfigFile file, string oldSection, string newSection, string[] keyFilter)
30 | {
31 | Dictionary oldEntries = (Dictionary)OrphanedEntriesProp.GetValue(file);
32 | List keysToRemove = new List();
33 |
34 | foreach (var kv in oldEntries)
35 | {
36 | string key = kv.Key.Key;
37 | if (kv.Key.Section.Equals(oldSection) && ((IList) keyFilter).Contains(key))
38 | {
39 | if (!file.TryGetEntry(newSection, key, out ConfigEntry entry)) continue;
40 |
41 | entry.SetSerializedValue(kv.Value);
42 | keysToRemove.Add(kv.Key);
43 | CommonAPIPlugin.logger.LogInfo($"Migrating config from {oldSection}:{key} to {newSection}:{key}");
44 |
45 | }
46 | }
47 |
48 | foreach (var key in keysToRemove)
49 | {
50 | oldEntries.Remove(key);
51 | }
52 | }
53 |
54 | ///
55 | /// Migrate BepInEx config file entry.
56 | ///
57 | /// target BepInEx config file
58 | /// Section to migrate from
59 | /// Old entry key
60 | /// Section to migrate to
61 | /// New entry key
62 | /// Type of config entry
63 | public static void MigrateConfig(this ConfigFile file, string oldSection, string oldName, string newSection, string newName)
64 | {
65 | Dictionary oldEntries = (Dictionary)OrphanedEntriesProp.GetValue(file);
66 | List keysToRemove = new List();
67 |
68 | foreach (var kv in oldEntries)
69 | {
70 | ConfigDefinition config = kv.Key;
71 | if (config.Section.Equals(oldSection) && config.Key.Equals(oldName))
72 | {
73 | if (!file.TryGetEntry(newSection, newName, out ConfigEntry entry)) continue;
74 |
75 | entry.SetSerializedValue(kv.Value);
76 | keysToRemove.Add(config);
77 | CommonAPIPlugin.logger.LogInfo($"Migrating config from {oldSection}:{oldName} to {newSection}:{newName}");
78 |
79 | }
80 | }
81 |
82 | foreach (var key in keysToRemove)
83 | {
84 | oldEntries.Remove(key);
85 | }
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/Config/README.md:
--------------------------------------------------------------------------------
1 | # CommonAPI
2 | A modding library for Dyson Sphere Program. Provides multiple features to make adding custom content to DSP easier.
3 |
4 |
5 | # List of features
6 | - Easily register new items, recipes and more using [ProtoRegistry](https://github.com/kremnev8/CommonAPI/tree/master/CommonAPI/Systems/ProtoRegistrySystem) system
7 | - Create new buildings with custom behavior and custom UI using [ComponentSystem](https://github.com/kremnev8/CommonAPI/tree/master/CommonAPI/Systems/ComponentSystem)
8 | - Register new recipe types. This allows to create new machine types without writing almost any code.
9 | - Register and use custom tabs.
10 | - Register new KeyBinds that players can rebind
11 | - Easily create new systems that exist in each Planet or Star. An example of such system is [ComponentSystem](https://github.com/kremnev8/CommonAPI/tree/master/CommonAPI/Systems/ComponentSystem)
12 | - Picker Extension tool allows to extend behavior of Item and Recipe pickers. For example use any filter defined by a function.
13 | - Support translation for at least for English, Chinese and Franch by using String Protos
14 |
15 | Full list of modules and other utilities can be found [here](https://github.com/kremnev8/CommonAPI/wiki).
16 | More will come in the future. If want write your own module and add it to the list you can open a Pull Request. Contrubitions are welcome.
17 |
18 | # Installation
19 | ### With Mod Manager
20 |
21 | Simply open the mod manager (if you don't have it install it [here](https://dsp.thunderstore.io/package/ebkr/r2modman/)), select **CommonAPI by CommonAPI**, then **Download**.
22 |
23 | If prompted to download with dependencies, select `Yes`.
24 | Then just click **Start modded**, and the game will run with the mod installed.
25 |
26 | ### Manually
27 | Install BepInEx from [here](https://dsp.thunderstore.io/package/xiaoye97/BepInEx/)
28 | Install LDBTool from [here](https://dsp.thunderstore.io/package/xiaoye97/LDBTool/)
29 | Install DSPModSave from [here](https://dsp.thunderstore.io/package/CommonAPI/DSPModSave/)
30 |
31 | Unzip folder `patchers` into `Dyson Sphere Program/BepInEx/patchers/CommonAPI/` (Create folder named `CommonAPI`)
32 | Unzip folder `plugins` into `Dyson Sphere Program/BepInEx/plugins/CommonAPI/`. (Create folder named `CommonAPI`)
33 |
34 | ## Feedback and Bug Report
35 | Feel free to contact me via Discord (Kremnev8#3756) for any feedback, bug-reports or suggestions.
36 |
37 | # How develop mods using CommonAPI
38 | All features are written as self-contained modules (Inspired by [R2API](https://github.com/risk-of-thunder/R2API)). By default NO modules are loaded. To use a module at the top of your BepInEx plugin class add an attribute `CommonAPISubmoduleDependency`. That will ensure that specified modules are loaded. Make sure you don't ask to load modules that you are not using.
39 |
40 | ## How to setup development environment
41 | 1. Download and install [CommonAPI](https://dsp.thunderstore.io/package/CommonAPI/CommonAPI/) and its dependencies
42 | 2. Create development environment. You can find how to do that [here](https://docs.bepinex.dev/master/articles/dev_guide/plugin_tutorial/index.html#sidetoggle)
43 | 3. Add LDBTool, DSPModSave and CommonAPI assemblies to your references. You can use NuGet to get them. You can find them by typing `DysonSphereProgram.Modding` into nuget package search.
44 | 4. You also likely will need a Unity Project. You can find instructions on setting that up [here](https://github.com/kremnev8/DSP-Mods/wiki/Setting-up-development-environment)
45 |
46 | ### Usage Example
47 | ```csharp
48 | [BepInPlugin(GUID, NAME, VERSION)]
49 |
50 | [BepInDependency(CommonAPIPlugin.GUID)]
51 | [CommonAPISubmoduleDependency(nameof(ProtoRegistry), nameof(CustomDescSystem))]
52 | public class MyPlugin : BaseUnityPlugin
53 | {
54 | public const string MODID = "myplugin";
55 | public const string GUID = "org.myname.plugin." + MODID;
56 | public const string NAME = "My Plugin";
57 |
58 | void Awake()
59 | {
60 | //Make use of modules here
61 | }
62 | }
63 | ```
64 |
65 | This library is still under development.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CommonAPI
2 | A modding library for Dyson Sphere Program. Provides multiple features to make adding custom content to DSP easier.
3 |
4 |
5 | # List of features
6 | - Easily register new items, recipes and more using [ProtoRegistry](https://github.com/kremnev8/CommonAPI/tree/master/CommonAPI/Systems/ProtoRegistrySystem) system
7 | - Create new buildings with custom behavior and custom UI using [ComponentSystem](https://github.com/kremnev8/CommonAPI/tree/master/CommonAPI/Systems/ComponentSystem)
8 | - Register new recipe types. This allows to create new machine types without writing almost any code.
9 | - Register and use custom tabs.
10 | - Register new KeyBinds that players can rebind
11 | - Easily create new systems that exist in each Planet or Star. An example of such system is [ComponentSystem](https://github.com/kremnev8/CommonAPI/tree/master/CommonAPI/Systems/ComponentSystem)
12 | - Picker Extension tool allows to extend behavior of Item and Recipe pickers. For example use any filter defined by a function.
13 | - Support translation for at least for English, Chinese and Franch by using String Protos
14 |
15 | Full list of modules and other utilities can be found [here](https://github.com/kremnev8/CommonAPI/wiki).
16 | More will come in the future. If want write your own module and add it to the list you can open a Pull Request. Contrubitions are welcome.
17 |
18 | # Installation
19 | ### With Mod Manager
20 |
21 | Simply open the mod manager (if you don't have it install it [here](https://dsp.thunderstore.io/package/ebkr/r2modman/)), select **CommonAPI by CommonAPI**, then **Download**.
22 |
23 | If prompted to download with dependencies, select `Yes`.
24 | Then just click **Start modded**, and the game will run with the mod installed.
25 |
26 | ### Manually
27 | Install BepInEx from [here](https://dsp.thunderstore.io/package/xiaoye97/BepInEx/)
28 | Install LDBTool from [here](https://dsp.thunderstore.io/package/xiaoye97/LDBTool/)
29 | Install DSPModSave from [here](https://dsp.thunderstore.io/package/CommonAPI/DSPModSave/)
30 |
31 | Unzip folder `patchers` into `Dyson Sphere Program/BepInEx/patchers/CommonAPI/` (Create folder named `CommonAPI`)
32 | Unzip folder `plugins` into `Dyson Sphere Program/BepInEx/plugins/CommonAPI/`. (Create folder named `CommonAPI`)
33 |
34 | ## Feedback and Bug Report
35 | Feel free to contact me via Discord (Kremnev8#3756) for any feedback, bug-reports or suggestions.
36 |
37 | # How develop mods using CommonAPI
38 | All features are written as self-contained modules (Inspired by [R2API](https://github.com/risk-of-thunder/R2API)). By default NO modules are loaded. To use a module at the top of your BepInEx plugin class add an attribute `CommonAPISubmoduleDependency`. That will ensure that specified modules are loaded. Make sure you don't ask to load modules that you are not using.
39 |
40 | ## How to setup development environment
41 | 1. Download and install [CommonAPI](https://dsp.thunderstore.io/package/CommonAPI/CommonAPI/) and its dependencies
42 | 2. Create development environment. You can find how to do that [here](https://docs.bepinex.dev/master/articles/dev_guide/plugin_tutorial/index.html#sidetoggle)
43 | 3. Add LDBTool, DSPModSave and CommonAPI assemblies to your references. You can use NuGet to get them. You can find them by typing `DysonSphereProgram.Modding` into nuget package search.
44 | 4. You also likely will need a Unity Project. You can find instructions on setting that up [here](https://github.com/kremnev8/DSP-Mods/wiki/Setting-up-development-environment)
45 |
46 | ### Usage Example
47 | ```csharp
48 | [BepInPlugin(GUID, NAME, VERSION)]
49 |
50 | [BepInDependency(CommonAPIPlugin.GUID)]
51 | [CommonAPISubmoduleDependency(nameof(ProtoRegistry), nameof(CustomDescSystem))]
52 | public class MyPlugin : BaseUnityPlugin
53 | {
54 | public const string MODID = "myplugin";
55 | public const string GUID = "org.myname.plugin." + MODID;
56 | public const string NAME = "My Plugin";
57 |
58 | void Awake()
59 | {
60 | //Make use of modules here
61 | }
62 | }
63 | ```
64 |
65 | This library is still under development. Used by many of my mods.
66 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/ComponentTypePool.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace CommonAPI.Systems
5 | {
6 | public class ComponentTypePool : Pool, IPoolable
7 | {
8 | public int id;
9 |
10 | public const float DT = 0.016666668f;
11 |
12 | private PlanetFactory factory;
13 | private int PoolTypeId;
14 |
15 | private FactoryComponent lastAddedComponent;
16 | private PrebuildData lastAddedData;
17 |
18 |
19 |
20 | public ComponentTypePool(PlanetFactory factory, int type)
21 | {
22 | this.factory = factory;
23 | PoolTypeId = type;
24 | this._cachedInitUpdate = _internalInitUpdate;
25 | this._cachedInitPowerUpdate = _internalInitPowerUpdate;
26 | }
27 |
28 | public ComponentTypePool()
29 | {
30 | }
31 |
32 | public int AddComponent(int entityId, PrebuildData data = default)
33 | {
34 | int num = AddPoolItem(new object[] {entityId, data});
35 | return num;
36 | }
37 |
38 | protected override FactoryComponent GetNewInstance()
39 | {
40 | return ComponentExtension.componentRegistry.GetNew(PoolTypeId);
41 | }
42 |
43 | public void OnPostComponentAdded()
44 | {
45 | if (lastAddedComponent == null) return;
46 |
47 | lastAddedComponent.OnAdded(lastAddedData, factory);
48 | lastAddedComponent = null;
49 | }
50 |
51 | protected override void InitPoolItem(FactoryComponent item, object[] data)
52 | {
53 | int entityId = (int) data[0];
54 |
55 | int pcId = factory.entityPool[entityId].powerConId;
56 |
57 | item.entityId = entityId;
58 | item.pcId = pcId;
59 | factory.entityPool[entityId].customId = item.id;
60 | factory.entityPool[entityId].customType = PoolTypeId;
61 | lastAddedComponent = item;
62 | lastAddedData = (PrebuildData)data[1];
63 | }
64 |
65 | protected override void RemovePoolItem(FactoryComponent item)
66 | {
67 | item.OnRemoved(factory);
68 |
69 | base.RemovePoolItem(item);
70 | }
71 |
72 | private Action _cachedInitUpdate;
73 | protected override Action InitUpdate() => _cachedInitUpdate;
74 | private void _internalInitUpdate(FactoryComponent item)
75 | {
76 | PowerSystem powerSystem = factory.powerSystem;
77 | PowerConsumerComponent[] consumerPool = powerSystem.consumerPool;
78 | float[] networkServes = powerSystem.networkServes;
79 | AnimData[] entityAnimPool = factory.entityAnimPool;
80 | SignData[] entitySignPool = factory.entitySignPool;
81 | int[][] entityNeeds = factory.entityNeeds;
82 |
83 | int entityId = item.entityId;
84 | float power = networkServes[consumerPool[item.pcId].networkId];
85 |
86 | int animationDelta = item.InternalUpdate(power, factory);
87 | item.UpdateAnimation(ref entityAnimPool[entityId], animationDelta, power);
88 | entityAnimPool[entityId].power = power;
89 | item.UpdateSigns(ref entitySignPool[entityId], animationDelta, power, factory);
90 | entityNeeds[entityId] = item.UpdateNeeds();
91 | }
92 |
93 | private Action _cachedInitPowerUpdate;
94 | public Action InitPowerUpdate() => _cachedInitPowerUpdate;
95 | private void _internalInitPowerUpdate(FactoryComponent item)
96 | {
97 | PowerConsumerComponent[] consumerPool = factory.powerSystem.consumerPool;
98 | item.UpdatePowerState(ref consumerPool[item.pcId]);
99 | }
100 |
101 | public int GetId()
102 | {
103 | return id;
104 | }
105 |
106 | public void SetId(int id)
107 | {
108 | this.id = id;
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/CommonAPI/Systems/ComponentSystem/UI/CustomMachineWindow.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine.UI;
2 |
3 | namespace CommonAPI.Systems
4 | {
5 | public abstract class CustomMachineWindow : ManualBehaviour
6 | {
7 | public abstract bool ShouldOpen(int componentId, int protoId);
8 | public abstract bool DoClosePlayerInventory();
9 | public abstract bool DoCloseOtherWindows();
10 | protected abstract void OnMachineChanged();
11 |
12 | public int customId { get; protected set; }
13 |
14 | public int entityId { get; protected set; }
15 |
16 | public PlanetFactory factory;
17 |
18 | public PowerSystem powerSystem;
19 |
20 | public FactoryComponent component;
21 |
22 | public Text titleText;
23 | public UIPowerIndicator powerIndicator;
24 |
25 | public override void _OnCreate()
26 | {
27 | powerIndicator.Init(this);
28 | }
29 |
30 | public void Open(int newEntityId)
31 | {
32 | entityId = newEntityId;
33 | if (GameMain.localPlanet != null && GameMain.localPlanet.factory != null)
34 | {
35 | factory = GameMain.localPlanet.factory;
36 | powerSystem = factory.powerSystem;
37 | GameMain.mainPlayer.SetHandItems(0, 0);
38 |
39 | customId = entityId > 0 ? factory.entityPool[entityId].customId : 0;
40 |
41 | OnIdChange();
42 | }
43 | transform.SetAsLastSibling();
44 | CustomMachineUISystem.openWindow = this;
45 | _Open();
46 | }
47 |
48 | public void Close()
49 | {
50 | entityId = 0;
51 | customId = 0;
52 | _Close();
53 |
54 | if (entityId != 0)
55 | {
56 | PlayerAction_Inspect actionInspect = GameMain.mainPlayer.controller.actionInspect;
57 | if (actionInspect.inspectId > 0 && actionInspect.inspectType == EObjectType.Entity &&
58 | factory.entityPool[actionInspect.inspectId].id == entityId)
59 | {
60 | actionInspect.InspectNothing();
61 | }
62 | }
63 |
64 | factory = null;
65 | powerSystem = null;
66 |
67 | CustomMachineUISystem.customInspectId = 0;
68 | CustomMachineUISystem.openWindow = null;
69 | }
70 |
71 | internal void OnIdChange()
72 | {
73 | if (entityId == 0 || factory == null)
74 | {
75 | Close();
76 | return;
77 | }
78 |
79 | EntityData entity = factory.entityPool[entityId];
80 |
81 | if (entity.id != entityId || !ShouldOpen(entity.customType, entity.protoId))
82 | {
83 | Close();
84 | return;
85 | }
86 |
87 | if (customId > 0)
88 | {
89 | component = ComponentExtension.GetComponent(factory, entity.customType, customId);
90 | }
91 |
92 | OnMachineChanged();
93 | }
94 |
95 | public void OnUpdateUI()
96 | {
97 | if (entityId == 0 || factory == null)
98 | {
99 | Close();
100 | return;
101 | }
102 |
103 | EntityData entity = factory.entityPool[entityId];
104 |
105 | if (entity.id != entityId || !ShouldOpen(entity.customType, entity.protoId))
106 | {
107 | Close();
108 | return;
109 | }
110 |
111 | if (customId > 0)
112 | {
113 | component = ComponentExtension.GetComponent(factory, entity.customType, customId);
114 | }
115 |
116 | if (component != null)
117 | {
118 | ItemProto itemProto = LDB.items.Select(factory.entityPool[component.entityId].protoId);
119 | titleText.text = itemProto.name;
120 |
121 | powerIndicator.OnUpdate(component.pcId);
122 | }
123 |
124 | _OnUpdate();
125 | }
126 | }
127 | }
--------------------------------------------------------------------------------
/CommonAPITests/Data/EntityDataTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using CommonAPI;
4 | using NUnit.Framework;
5 | using static NUnit.Framework.Assert;
6 |
7 | namespace CommonAPITests
8 | {
9 | [TestFixture]
10 | public class EntityDataTest
11 | {
12 | public EntityData data;
13 | public EntityData data2;
14 |
15 | [SetUp]
16 | public void Setup()
17 | {
18 | data = new EntityData
19 | {
20 | customData = new Dictionary()
21 | };
22 | data2 = new EntityData();
23 | EntityDataExtensions.propertySerializers.Clear();
24 | }
25 |
26 | [Test]
27 | public void TestSerializerWarnProperties()
28 | {
29 | False(data.HasProperty("Test"));
30 |
31 | Throws(typeof(ArgumentException), () =>
32 | {
33 | data.SetProperty("Test", 5);
34 | });
35 |
36 | EntityDataExtensions.DefineProperty("Test", new IntArrayPropertySerializer());
37 |
38 | Throws(typeof(ArgumentException), () =>
39 | {
40 | data.SetProperty("Test", 5);
41 | });
42 |
43 | EntityDataExtensions.DefineProperty("Test1", new IntPropertySerializer());
44 |
45 | DoesNotThrow(() =>
46 | {
47 | data.SetProperty("Test1", 5);
48 | });
49 | }
50 |
51 | [Test]
52 | public void TestProperties()
53 | {
54 | EntityDataExtensions.DefineProperty("Test", new IntPropertySerializer());
55 | EntityDataExtensions.DefineProperty("Hello", new IntPropertySerializer());
56 |
57 | False(data.HasProperty("Test"));
58 |
59 | data.SetProperty("Test", 5);
60 | data.SetProperty("Test", 7);
61 |
62 | True(data.HasProperty("Test"));
63 |
64 | AreEqual(7, data.GetProperty("Test"));
65 | AreEqual(0, data.GetProperty("Hello"));
66 |
67 | AreEqual(7, data.GetOrAddProperty("Test"));
68 | AreEqual(0, data.GetOrAddProperty("Hello"));
69 | }
70 |
71 | [Test]
72 | public void TestPropertiesWNullData()
73 | {
74 | data.customData = null;
75 | EntityDataExtensions.DefineProperty("Test", new IntPropertySerializer());
76 | EntityDataExtensions.DefineProperty("Hello", new IntPropertySerializer());
77 |
78 | False(data.HasProperty("Test"));
79 |
80 | data.customData = null;
81 | data.SetProperty("Test", 5);
82 | data.SetProperty("Test", 7);
83 |
84 | True(data.HasProperty("Test"));
85 |
86 | AreEqual(7, data.GetProperty("Test"));
87 | data.customData = null;
88 | AreEqual(0, data.GetProperty("Hello"));
89 |
90 | data.customData = null;
91 | AreEqual(0, data.GetOrAddProperty("Test"));
92 | AreEqual(0, data.GetOrAddProperty("Hello"));
93 |
94 | data.customData = null;
95 | DoesNotThrow(() =>
96 | {
97 | Util.GetSerializationSetup(w =>
98 | {
99 | EntityDataExtensions.ExportData(ref data, w);
100 | }, r =>
101 | {
102 | EntityDataExtensions.ImportData(ref data, r);
103 | });
104 | });
105 | }
106 |
107 | [Test]
108 | public void TestSerialization()
109 | {
110 | EntityDataExtensions.DefineProperty("Test", new IntArrayPropertySerializer());
111 | EntityDataExtensions.DefineProperty("Test", new IntPropertySerializer());
112 | EntityDataExtensions.DefineProperty("Test1", new IntArrayPropertySerializer());
113 |
114 | data.SetProperty("Test", 5);
115 | data.SetProperty("Test1", new[]{1,2,3});
116 |
117 | Util.GetSerializationSetup(w =>
118 | {
119 | EntityDataExtensions.ExportData(ref data, w);
120 | }, r =>
121 | {
122 | EntityDataExtensions.ImportData(ref data2, r);
123 | });
124 |
125 | AreEqual(5, data2.GetProperty("Test"));
126 | AreEqual(new[]{1,2,3}, data2.GetProperty("Test1"));
127 | }
128 | }
129 | }
--------------------------------------------------------------------------------
/Staging/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### v1.6.7
2 | - Updated to work with game version 0.10.33.26934 or higher
3 | - Fixed known issues for KeyBindSystem (Thanks [soarqin](https://github.com/soarqin))
4 |
5 | **Note:** Version v1.6.7 was **NOT** sufficiently tested. Some functionality might not work. Report an issue if that's the case.
6 |
7 |
8 | Changelog
9 |
10 | ### v1.6.6
11 | - Fixed custom languages not loading
12 |
13 | ### v1.6.5
14 | - Fixed issues when running with Nebula Multiplayer Mod API version 2.0.0 or higher
15 |
16 | ### v1.6.4
17 | - Fixed UINumberEntryExtension breaking layout and functionality of the signal picker.
18 | - Fixed picker extension translation entries not being added
19 | - Fixed NRE issues when adding TechProtos via ProtoRegistry
20 |
21 | ### v1.6.3
22 | - Added `RegisterKeyBindWithReturn()` method to `CustomKeyBindSystem`
23 |
24 | ### v1.6.2
25 | - Add ability to change text fonts
26 |
27 | ### v1.6.1
28 | - Fix errors when adding custom protos
29 | - Fix warnings about Common API not being built for 0.10.28.20729
30 |
31 | ### v1.6.0
32 | - Updated to work with game version 0.10.28.20729 or higher
33 | - Added Localization Module to support custom localizations.
34 | - ProtoRegistry methods related to StringProto are deprecated in favor of Localization Module
35 | - Internal restructure of the submodule system
36 |
37 | ### v1.5.7
38 | - Fix modded items not appearing on the production graphs.
39 | ### v1.5.6
40 | - Remove game exe name targeting
41 | ### v1.5.5
42 | - Update for Dyson Sphere Program update
43 | ### v1.5.4
44 | - Fixed errors when loading a save with one or more mods that add buildings (For example Better Machines) removed
45 | ### v1.5.3
46 | - Fix errors when model index is much bigger than maximum used by game.
47 | ### v1.5.2
48 | - Added UINumberPickerExtension for picking signal together with a value.
49 | ### v1.5.1
50 | - Testing release, no changes
51 | ### v1.5.0
52 | - Updated to work with game version 0.9.25.11985 or higher
53 | ### v1.4.9
54 | - @Raptor: Prevent creation of delegates every tick using alternate logic for Pool, which should improve performance of Various Facility.
55 | ### v1.4.8
56 | - Add checks to container export. Any mod issues should be logged and contained.
57 | - Fix Registry exporting data of empty items
58 | ### v1.4.7
59 | - Add public method to make other mods compatibility easier. Internal refactor.
60 | ### v1.4.6
61 | - Fix dynamic KeyBind ID assignment and migration being broken. Playes might lose some of previously rebound keybinds.
62 | ### v1.4.5
63 | - Fix issues adding multiple techologies with the same pretech
64 | - KeyBinds now dynamically assign ID's. To all modders using Custom KeyBinds: please stop assigning ID's when calling `RegisterKeyBind()`
65 | - FactoryComponent now has a method `UpdateNeeds()` that allows to set entityNeeds.
66 | ### v1.4.4
67 | - Add extension methods for customId and customType fields on EntityData class
68 | ### v1.4.3
69 | - Fixed `GetTabId` being impossible to call
70 | - Improved appearance of mod created tabs
71 | ### v1.4.2
72 | - Fix NRE in UISingalTip
73 | ### v1.4.1
74 | - Added UIWindowResize class, made by Raptor
75 | - Added ability to specify iconPath and name for recipes manually
76 | ### v1.4.0
77 | - Fix lava ocean type being displayed as missing item
78 | - Allow submodules have dependencies
79 | - Add AssemblerRecipeSystem
80 | - Refactor PickerExtensionSystem
81 | - Allow adding Signal Proto using ProtoRegistry
82 | ### v1.3.4
83 | - Fix missing items appearing instead of no item id 0
84 | ### v1.3.3
85 | - Fix missing items being broken. Also make it possible to delete them
86 | ### v1.3.2
87 | - Change StartModLoad function behavior
88 | ### v1.3.1
89 | - Now Machines added by mods will be automatically removed from save game if mod is uninstalled.
90 | - Corrected Game version CommonAPI is built for.
91 | ### v1.3.0
92 | - Add ability to register Audio using ProtoRegistry
93 | - Updated LDBTool to 2.0.1. Please make sure you are using 2.0.0 or higher.
94 | ### v1.2.2
95 | - Added plugin catergories on Thunderstore page.
96 | ### v1.2.1
97 | - Added ability to load modules manually. Useful for testing with ScriptEngine.
98 | ### v1.2.0
99 | - Migrated to CommonAPI-DSPModSave package.
100 | ### v1.1.0
101 | - Renamed CustomPlanetSystem to PlanetExtensionSystem
102 | - Renamed CustomStarSystem to StarExtensionSystem
103 | - Add show locked item and recipes feature to PickerExtensionModule
104 | - Improved Icon Generator
105 | ### v1.0.1
106 | - Fix issues selecting recipes in Assembler UI
107 | ### v1.0.0
108 | - Initial Release
109 |
--------------------------------------------------------------------------------
/CommonAPI/Systems/PickerExtensionSystem/Patches/UIItemPicker_Patch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection.Emit;
4 | using CommonAPI.Systems;
5 | using HarmonyLib;
6 | using UnityEngine;
7 |
8 | namespace CommonAPI.Patches
9 | {
10 |
11 | [HarmonyPatch]
12 | public class UIItemPicker_Patch
13 | {
14 | [HarmonyPatch(typeof(UIItemPicker), "RefreshIcons")]
15 | [HarmonyTranspiler]
16 | public static IEnumerable AddItemFilter(IEnumerable instructions)
17 | {
18 | CodeMatcher matcher = new CodeMatcher(instructions)
19 | .MatchForward(true,
20 | new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ItemProto), nameof(ItemProto.GridIndex))),
21 | new CodeMatch(OpCodes.Ldc_I4)
22 | ).Advance(1);
23 | Label label = (Label) matcher.Instruction.operand;
24 |
25 | matcher.Advance(-2)
26 | .InsertAndAdvance(Transpilers.EmitDelegate>(proto => UIItemPickerExtension.currentFilter == null || UIItemPickerExtension.currentFilter.Invoke(proto)))
27 | .InsertAndAdvance(new CodeInstruction(OpCodes.Brfalse, label))
28 | .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_1))
29 | .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_3))
30 | .InsertAndAdvance(new CodeInstruction(OpCodes.Ldelem_Ref));
31 |
32 | matcher.MatchForward(true,
33 | new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(Proto), nameof(Proto.ID))),
34 | new CodeMatch(OpCodes.Callvirt))
35 | .SetInstruction(Transpilers.EmitDelegate>(CheckItem));
36 |
37 |
38 | return matcher.InstructionEnumeration();
39 | }
40 |
41 | public static bool CheckItem(GameHistoryData history,int itemId)
42 | {
43 | if (UIItemPickerExtension.showLocked) return true;
44 | return history.ItemUnlocked(itemId);
45 | }
46 |
47 | [HarmonyPatch(typeof(UIItemPicker), "Popup", typeof(Vector2), typeof(Action))]
48 | [HarmonyPrefix]
49 | public static void IgnoreFilter(UIItemPicker __instance)
50 | {
51 | UIItemPickerExtension.currentFilter = null;
52 | UIItemPickerExtension.currentExtension = null;
53 | UIItemPickerExtension.showLocked = false;
54 | }
55 |
56 | [HarmonyPatch(typeof(UIItemPicker), "OnBoxMouseDown")]
57 | [HarmonyPrefix]
58 | public static bool OnBoxMouseDown(UIItemPicker __instance)
59 | {
60 | if (UIItemPickerExtension.currentExtension == null) return true;
61 |
62 | if (UIItemPickerExtension.currentExtension is IMouseHandlerExtension mouseHandler)
63 | {
64 | return mouseHandler.OnBoxMouseDown(__instance);
65 | }
66 | return true;
67 | }
68 |
69 | [HarmonyPatch(typeof(UIItemPicker), "TestMouseIndex")]
70 | [HarmonyPostfix]
71 | public static void TestMouseIndex(UIItemPicker __instance)
72 | {
73 | if (UIItemPickerExtension.currentExtension == null) return;
74 |
75 | if (UIItemPickerExtension.currentExtension is IMouseHandlerExtension mouseHandler)
76 | {
77 | mouseHandler.TestMouseIndex(__instance);
78 | }
79 | }
80 |
81 | [HarmonyPatch(typeof(UIItemPicker), "_OnOpen")]
82 | [HarmonyPostfix]
83 | public static void Open(UIItemPicker __instance)
84 | {
85 | if (UIItemPickerExtension.currentExtension == null) return;
86 |
87 | UIItemPickerExtension.currentExtension.Open(__instance);
88 | }
89 |
90 | [HarmonyPatch(typeof(UIItemPicker), "_OnClose")]
91 | [HarmonyPostfix]
92 | public static void Close(UIItemPicker __instance)
93 | {
94 | if (UIItemPickerExtension.currentExtension == null) return;
95 | UIItemPickerExtension.currentExtension.Close(__instance);
96 | }
97 |
98 | [HarmonyPatch(typeof(UIItemPicker), "_OnUpdate")]
99 | [HarmonyPostfix]
100 | public static void Update(UIItemPicker __instance)
101 | {
102 | if (UIItemPickerExtension.currentExtension == null) return;
103 |
104 | if (UIItemPickerExtension.currentExtension is IUpdatePickerExtension mouseHandler)
105 | {
106 | mouseHandler.OnUpdate(__instance);
107 | }
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------