Decompiled source of SprayFactory v0.1.1
BepInEx/plugins/SprayFactory/SprayFactory.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using CommonAPI; using CommonAPI.Systems.ModLocalization; using HarmonyLib; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; using crecheng.DSPModSave; using xiaoye97; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Spray Factory")] [assembly: AssemblyProduct("Spray Factory")] [assembly: AssemblyCompany("Comonad")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.1.1.0")] namespace SprayFactory; internal static class FactoryBuildMenu { internal static void Place(ItemProto item, ItemProto coater) { HashSet<int> hashSet = new HashSet<int>(from i in ((ProtoSet<ItemProto>)(object)LDB.items).dataArray where ((Proto)i).ID != ((Proto)item).ID select i.BuildIndex); ItemProto[,] array = (ItemProto[,])AccessTools.Field(typeof(UIBuildMenu), "protos").GetValue(null); int num = coater.BuildIndex / 100; int[] array2 = (from c in new int[2] { num, 4 }.Concat(Enumerable.Range(1, 9)).Distinct() where c >= 1 && c <= 9 select c).ToArray(); int[] array5; if (Chainloader.PluginInfos.TryGetValue("Gnimaerd.DSP.plugin.BuildBarTool", out var value)) { Type type = ((object)value.Instance).GetType(); ItemProto[,] array3 = (ItemProto[,])AccessTools.Field(type, "protos").GetValue(null); int[,] array4 = (int[,])AccessTools.Field(type, "protoIds").GetValue(null); int num2 = coater.BuildIndex % 100; if (num2 > 20) { num2 -= 20; } IEnumerable<int> enumerable = from n in new int[1] { num2 }.Concat(Enumerable.Range(1, 10)).Distinct() where n >= 1 && n <= 10 select n; array5 = array2; for (int num3 = 0; num3 < array5.Length; num3++) { int num4 = array5[num3]; foreach (int item2 in enumerable) { int num5 = num4 * 100 + 20 + item2; if (!hashSet.Contains(num5) && array3[num4, item2] == null && array4[num4, item2] == 0 && (bool)AccessTools.Method(AccessTools.TypeByName("BuildBarTool.BuildBarTool"), "SetBuildBar", new Type[4] { typeof(int), typeof(int), typeof(int), typeof(bool) }, (Type[])null).Invoke(null, new object[4] { num4, item2, ((Proto)item).ID, true })) { item.BuildIndex = num5; AccessTools.Method(type, "LoadFromBuildIndex", (Type[])null, (Type[])null).Invoke(null, null); Plugin.Log.LogInfo((object)("Factory build menu: category=" + num4 + " row=upper slot=" + item2)); return; } } } } UIButton[] array6 = UIRoot.instance?.uiGame?.buildMenu?.childButtons; int num6 = ((array6 == null) ? 10 : Math.Min(10, array6.Length - 1)); array5 = array2; for (int num3 = 0; num3 < array5.Length; num3++) { int num7 = array5[num3]; for (int num8 = 1; num8 <= num6; num8++) { int num9 = num7 * 100 + num8; if (!hashSet.Contains(num9) && (array[num7, num8] == null || ((Proto)array[num7, num8]).ID == ((Proto)item).ID) && (array6 == null || !((Object)(object)array6[num8] == (Object)null))) { item.BuildIndex = num9; LDBTool.SetBuildBar(num7, num8, ((Proto)item).ID); Plugin.Log.LogInfo((object)("Factory build menu: category=" + num7 + " row=lower slot=" + num8)); return; } } } throw new InvalidOperationException("No free factory build menu slot."); } } internal static class FactoryEffects { private sealed class Batch { internal readonly List<uint> Ids = new List<uint>(); internal Material Material; internal ComputeBuffer IdBuffer; internal ComputeBuffer Args; internal int Capacity; internal void Free() { ComputeBuffer idBuffer = IdBuffer; if (idBuffer != null) { idBuffer.Release(); } ComputeBuffer args = Args; if (args != null) { args.Release(); } if ((Object)(object)Material != (Object)null) { Object.Destroy((Object)(object)Material); } } } private sealed class Group { internal Batch Liquid; internal Batch Spray; } private static readonly Dictionary<int, Group> groups = new Dictionary<int, Group>(); private static readonly Plane[] planes = (Plane[])(object)new Plane[6]; private static readonly uint[] args = new uint[5]; private static readonly FieldInfo stateBuffer = AccessTools.Field(typeof(LabRenderer), "stateBuffer"); private static int liquidSlot = -1; private static int spraySlot = -1; internal static void Draw(PlanetFactory factory, Camera camera) { FactoryModel val = ((factory == null) ? null : factory.planet?.factoryModel); if (!((Object)(object)val == (Object)null) && !((Object)(object)camera == (Object)null) && val.gpuiManager != null && !val.disableFactoryEntities && val.gpuiManager.renderEntity) { Draw(factory, camera, val.gpuiManager.GetObjectRenderer(Prototypes.ModelId), val.entityAnimBuffer); } } private static Batch CreateBatch(Material original, Color color, bool spray) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown Material val = new Material(original); color.a = 1f; string[] array = new string[3] { "_Color1", "_Color2", "_Color4" }; foreach (string text in array) { if (val.HasProperty(text)) { val.SetColor(text, color); } } if (spray) { val.SetColor("_TintColor", new Color(1f, 1f, 1f, 0.5f)); val.SetFloat("_SprayBrightness", 0.5f); val.SetFloat("_SprayBrightnessBg", 0.05f); } else { val.SetFloat("_EmissionSwitch", 1f); val.SetFloat("_EmissionMultiplier", 0.25f); } return new Batch { Material = val, Args = new ComputeBuffer(5, 4, (ComputeBufferType)256) }; } private static Group GetGroup(int item, PrefabDesc source) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (groups.TryGetValue(item, out var value)) { return value; } Color color = RecipeColors.ForItem(item); value = new Group { Liquid = CreateBatch(source.lodMaterials[0][liquidSlot], color, spray: false), Spray = CreateBatch(source.lodMaterials[0][spraySlot], color, spray: true) }; groups.Add(item, value); return value; } internal static int Draw(PlanetFactory factory, Camera camera, ObjectRenderer renderer, ComputeBuffer animations) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) if (factory?.cargoTraffic == null || (Object)(object)camera == (Object)null || renderer == null || animations == null) { return 0; } PrefabDesc prefabDesc = ((ProtoSet<ItemProto>)(object)LDB.items).Select(2313).prefabDesc; if (liquidSlot < 0 || spraySlot < 0) { for (int i = 0; i < prefabDesc.lodMaterials[0].Length; i++) { Material obj = prefabDesc.lodMaterials[0][i]; string text = ((obj != null) ? ((Object)obj).name : null); if (text != null) { if (text.IndexOf("water", StringComparison.OrdinalIgnoreCase) >= 0) { liquidSlot = i; } if (text.IndexOf("effect", StringComparison.OrdinalIgnoreCase) >= 0) { spraySlot = i; } } } } if (liquidSlot < 0 || spraySlot < 0) { return 0; } foreach (Group value in groups.Values) { value.Liquid.Ids.Clear(); value.Spray.Ids.Clear(); } GeometryUtility.CalculateFrustumPlanes(camera, planes); CargoTraffic cargoTraffic = factory.cargoTraffic; int num = 0; for (int j = 1; j < cargoTraffic.spraycoaterCursor; j++) { SpraycoaterComponent val = cargoTraffic.spraycoaterPool[j]; if (val.id != j || !FactoryRuntime.IsFactory(factory, val.entityId) || !FactoryStore.TryGet(factory.planetId, val.entityId, out var state)) { continue; } EntityData val2 = factory.entityPool[val.entityId]; if (val2.modelId <= 0 || val2.modelId >= renderer.instCursor || renderer.instPool[val2.modelId].objId != val2.id) { continue; } Vector3 val3 = val2.pos - ((Component)camera).transform.position; if (!(((Vector3)(ref val3)).sqrMagnitude > 10000f) && GeometryUtility.TestPlanesAABB(planes, new Bounds(val2.pos, Vector3.one * 6f))) { int recipeId; int num2; lock (state.Sync) { recipeId = state.RecipeId; num2 = ((state.SprayTicks > 0) ? state.SprayItemId : 0); } RecipeProto val4 = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(recipeId); if (val4 != null && val4.Results.Length != 0) { GetGroup(val4.Results[0], prefabDesc).Liquid.Ids.Add((uint)val2.modelId); num++; } if (num2 > 0) { GetGroup(num2, prefabDesc).Spray.Ids.Add((uint)val2.modelId); } } } BatchRenderer batch = renderer.lodBatches[0]; ComputeBuffer states = (ComputeBuffer)((renderer is LabRenderer) ? /*isinst with value type is only supported in some contexts*/: null); foreach (Group value2 in groups.Values) { Render(value2.Liquid, liquidSlot, batch, animations, states, camera); Render(value2.Spray, spraySlot, batch, animations, states, camera); } return num; } private static void Render(Batch group, int slot, BatchRenderer batch, ComputeBuffer animations, ComputeBuffer states, Camera camera) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) if (group.Ids.Count == 0) { return; } if (group.Capacity < group.Ids.Count) { ComputeBuffer idBuffer = group.IdBuffer; if (idBuffer != null) { idBuffer.Release(); } group.Capacity = Mathf.NextPowerOfTwo(group.Ids.Count); group.IdBuffer = new ComputeBuffer(group.Capacity, 4); } group.IdBuffer.SetData<uint>(group.Ids); args[0] = batch.mesh.GetIndexCount(slot); args[1] = (uint)group.Ids.Count; args[2] = batch.mesh.GetIndexStart(slot); args[3] = batch.mesh.GetBaseVertex(slot); args[4] = 0u; group.Args.SetData((Array)args); group.Material.SetBuffer("_InstBuffer", batch.instBuffer); group.Material.SetBuffer("_IdBuffer", group.IdBuffer); group.Material.SetBuffer("_AnimBuffer", animations); if (states != null) { group.Material.SetBuffer("_StateBuffer", states); } VertaBuffer vertaBuffer = batch.vertaBuffer; if (vertaBuffer != null) { vertaBuffer.SetToAnimMaterial(group.Material); } Graphics.DrawMeshInstancedIndirect(batch.mesh, slot, group.Material, new Bounds(Vector3.zero, Vector3.one * 10000f), group.Args, 0, (MaterialPropertyBlock)null, (ShadowCastingMode)0, false, 0, camera, (LightProbeUsage)1); } internal static void Clear() { foreach (Group value in groups.Values) { value.Liquid.Free(); value.Spray.Free(); } groups.Clear(); liquidSlot = (spraySlot = -1); } } internal static class FactoryIcon { private static Sprite sprite; private static Texture2D texture; internal static void Apply() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sprite == (Object)null) { Sprite iconSprite = ((ProtoSet<ItemProto>)(object)LDB.items).Select(2313).iconSprite; Rect textureRect = iconSprite.textureRect; RenderTexture temporary = RenderTexture.GetTemporary(80, 80, 0, (RenderTextureFormat)0); RenderTexture active = RenderTexture.active; try { Graphics.Blit((Texture)(object)iconSprite.texture, temporary, new Vector2(((Rect)(ref textureRect)).width / (float)((Texture)iconSprite.texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)iconSprite.texture).height), new Vector2(((Rect)(ref textureRect)).x / (float)((Texture)iconSprite.texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)iconSprite.texture).height)); RenderTexture.active = temporary; texture = new Texture2D(80, 80, (TextureFormat)5, false) { name = "spray-factory-icon" }; texture.ReadPixels(new Rect(0f, 0f, 80f, 80f), 0, 0); Color[] pixels = texture.GetPixels(); for (int i = 0; i < pixels.Length; i++) { Color val = pixels[i]; float num = ((val.a > 0f) ? ((Color)(ref val)).grayscale : 0f); pixels[i] = new Color(num, num, num, val.a); } texture.SetPixels(pixels); texture.Apply(); Texture2D obj = texture; Rect val2 = new Rect(0f, 0f, 80f, 80f); Vector2 pivot = iconSprite.pivot; Rect rect = iconSprite.rect; sprite = Sprite.Create(obj, val2, pivot / ((Rect)(ref rect)).size, iconSprite.pixelsPerUnit); ((Object)sprite).name = "spray-factory-icon"; } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); } } AccessTools.Field(typeof(ItemProto), "_iconSprite").SetValue(((ProtoSet<ItemProto>)(object)LDB.items).Select(Prototypes.ItemId), sprite); ((ProtoSet<ModelProto>)(object)LDB.models).Select(Prototypes.ModelId).OverrideIconSprite(sprite); } internal static void Clear() { if ((Object)(object)sprite != (Object)null) { Object.Destroy((Object)(object)sprite); } if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } sprite = null; texture = null; } } internal static class FactoryParameters { internal static bool IsFactory(PlanetFactory factory, int id) { if (id <= 0) { if (factory != null && id < 0 && -id < factory.prebuildPool.Length && factory.prebuildPool[-id].id == -id) { return factory.prebuildPool[-id].protoId == Prototypes.ItemId; } return false; } return FactoryRuntime.IsFactory(factory, id); } internal static int[] Encode(int recipe, bool accelerate) { return new int[4] { 1048576, 1, recipe, accelerate ? 1 : 0 }; } internal static bool Decode(int[] data, out int recipe, out bool accelerate) { recipe = 0; accelerate = false; if (data == null || data.Length < 4 || data[0] != 1048576 || data[1] != 1) { return false; } recipe = data[2]; accelerate = data[3] != 0; return true; } internal static void Read(PlanetFactory factory, int id, out int recipe, out bool accelerate) { recipe = 0; accelerate = false; FactoryState state; if (id < 0) { recipe = factory.prebuildPool[-id].recipeId; if (Decode(factory.prebuildPool[-id].parameters, out var recipe2, out accelerate)) { recipe = recipe2; } } else if (FactoryStore.TryGet(factory.planetId, id, out state)) { lock (state.Sync) { recipe = state.RecipeId; accelerate = state.ForceAccMode; } } } internal static bool Allowed(PlanetFactory factory, int recipe) { if (recipe != 0) { if (((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(recipe) != null) { GameHistoryData obj = factory.gameData?.history ?? GameMain.history; if (obj == null) { return false; } return obj.RecipeUnlocked(recipe); } return false; } return true; } internal static void Apply(PlanetFactory factory, int id, int recipe, bool accelerate) { if (id < 0) { factory.prebuildPool[-id].recipeId = recipe; factory.prebuildPool[-id].parameters = Encode(recipe, accelerate); factory.prebuildPool[-id].paramCount = 4; return; } FactoryState factoryState = FactoryStore.Get(factory.planetId, id); lock (factoryState.Sync) { factoryState.ChangeRecipe(recipe); factoryState.ForceAccMode = accelerate; } FactoryRuntime.UpdateSign(factory, id, ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(recipe), working: false); } } [HarmonyPatch(typeof(BuildingParameters), "CopyFromFactoryObject")] internal static class CopyFactoryParameters { private static bool Prefix(ref BuildingParameters __instance, int objectId, PlanetFactory factory, ref bool __result) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if (!FactoryParameters.IsFactory(factory, objectId)) { return true; } ((BuildingParameters)(ref __instance)).SetEmpty(); __instance.type = (BuildingType)99; __instance.itemId = Prototypes.ItemId; __instance.modelIndex = ((objectId > 0) ? factory.entityPool[objectId].modelIndex : factory.prebuildPool[-objectId].modelIndex); Vector3 val = ((objectId > 0) ? factory.entityPool[objectId].pos : factory.prebuildPool[-objectId].pos); Quaternion val2 = ((objectId > 0) ? factory.entityPool[objectId].rot : factory.prebuildPool[-objectId].rot); Quaternion val3 = Quaternion.Inverse(Maths.SphericalRotation(val, 0f)) * val2; __instance.yaw = Mathf.Round(((Quaternion)(ref val3)).eulerAngles.y / 3f) * 3f; FactoryParameters.Read(factory, objectId, out var recipe, out var accelerate); __instance.recipeId = recipe; RecipeProto obj = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(recipe); __instance.recipeType = (ERecipeType)((obj != null) ? ((int)obj.Type) : 0); __instance.mode0 = (accelerate ? 1 : 0); __instance.parameters = FactoryParameters.Encode(recipe, accelerate); __result = true; return false; } } [HarmonyPatch(typeof(BuildingParameters), "ToParamsArray")] internal static class EncodeFactoryParameters { private static bool Prefix(ref BuildingParameters __instance, ref int[] _parameters, ref int _paramCount) { if (__instance.itemId != Prototypes.ItemId) { return true; } _parameters = FactoryParameters.Encode(__instance.recipeId, __instance.mode0 != 0); _paramCount = 4; return false; } } [HarmonyPatch(typeof(BuildingParameters), "FromParamsArray")] internal static class DecodeFactoryParameters { private static bool Prefix(ref BuildingParameters __instance, int[] _parameters) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (__instance.itemId != Prototypes.ItemId) { return true; } if (FactoryParameters.Decode(_parameters, out var recipe, out var accelerate)) { __instance.recipeId = recipe; RecipeProto obj = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(recipe); __instance.recipeType = (ERecipeType)((obj != null) ? ((int)obj.Type) : 0); __instance.mode0 = (accelerate ? 1 : 0); __instance.parameters = (int[])_parameters.Clone(); } return false; } } [HarmonyPatch(typeof(BuildingParameters), "CanPasteToFactoryObject")] internal static class CanPasteFactoryParameters { private static bool Prefix(ref BuildingParameters __instance, int objectId, PlanetFactory factory, ref bool __result) { if (__instance.itemId != Prototypes.ItemId && !FactoryParameters.IsFactory(factory, objectId)) { return true; } __result = __instance.itemId == Prototypes.ItemId && FactoryParameters.IsFactory(factory, objectId) && FactoryParameters.Allowed(factory, __instance.recipeId); return false; } } [HarmonyPatch(typeof(BuildingParameters), "PasteToFactoryObject")] internal static class PasteFactoryParameters { private static bool Prefix(ref BuildingParameters __instance, int objectId, PlanetFactory factory, ref bool __result) { if (__instance.itemId != Prototypes.ItemId && !FactoryParameters.IsFactory(factory, objectId)) { return true; } __result = __instance.itemId == Prototypes.ItemId && FactoryParameters.IsFactory(factory, objectId) && FactoryParameters.Allowed(factory, __instance.recipeId); if (__result) { FactoryParameters.Apply(factory, objectId, __instance.recipeId, __instance.mode0 != 0); } return false; } } [HarmonyPatch(typeof(BuildingParameters), "ApplyPrebuildParametersToEntity")] internal static class RestoreFactoryParameters { private static bool Prefix(int entityId, int recipeId, int[] parameters, PlanetFactory factory) { if (!FactoryRuntime.IsFactory(factory, entityId)) { return true; } bool accelerate = false; if (FactoryParameters.Decode(parameters, out var recipe, out accelerate)) { recipeId = recipe; } if (FactoryParameters.Allowed(factory, recipeId)) { FactoryParameters.Apply(factory, entityId, recipeId, accelerate); } return false; } } [HarmonyPatch(typeof(BuildTool_Addon), "DeterminePreviews")] internal static class FactoryAddonPreview { private static void Postfix(BuildTool_Addon __instance) { if (((Proto)(__instance.handItem?)).ID != Prototypes.ItemId) { return; } List<BuildPreview> list = ((BuildTool)__instance).actionBuild?.templatePreviews; if (list == null || list.Count == 0 || ((Proto)(list[0].item?)).ID != Prototypes.ItemId) { return; } BuildPreview obj = list[0]; bool accelerate = false; int num = obj.recipeId; if (FactoryParameters.Decode(obj.parameters, out var recipe, out accelerate)) { num = recipe; } foreach (BuildPreview buildPreview in ((BuildTool)__instance).buildPreviews) { if (((Proto)(buildPreview.item?)).ID == Prototypes.ItemId) { buildPreview.recipeId = num; buildPreview.SetParameters(4, FactoryParameters.Encode(num, accelerate)); } } } } internal static class FactoryPower { internal static float Ratio(PowerSystem system, int consumerId) { if (system == null || consumerId <= 0 || consumerId >= system.consumerPool.Length || system.consumerPool[consumerId].id != consumerId) { return 0f; } int networkId = system.consumerPool[consumerId].networkId; if (networkId <= 0 || networkId >= system.netPool.Length || system.netPool[networkId] == null) { return 0f; } return Mathf.Clamp01((float)system.netPool[networkId].consumerRatio); } internal static void Restore(PlanetFactory factory) { CargoTraffic cargoTraffic = factory.cargoTraffic; PowerSystem powerSystem = factory.powerSystem; if (cargoTraffic == null || powerSystem == null) { return; } for (int i = 1; i < cargoTraffic.spraycoaterCursor; i++) { ref SpraycoaterComponent reference = ref cargoTraffic.spraycoaterPool[i]; if (reference.id == i && FactoryRuntime.IsFactory(factory, reference.entityId)) { int num = factory.entityPool[reference.entityId].powerConId; if (num <= 0 || num >= powerSystem.consumerPool.Length || powerSystem.consumerPool[num].id != num || powerSystem.consumerPool[num].entityId != reference.entityId) { num = powerSystem.NewConsumerComponent(reference.entityId, 5000L, 167L); } reference.pcId = num; ref PowerConsumerComponent reference2 = ref powerSystem.consumerPool[num]; reference2.workEnergyPerTick = 5000L; reference2.idleEnergyPerTick = 167L; ((PowerConsumerComponent)(ref reference2)).SetRequiredEnergy(false); } } } } [HarmonyPatch(typeof(PlanetFactory), "Import")] internal static class RestoreFactoryPower { private static void Postfix(PlanetFactory __instance) { FactoryPower.Restore(__instance); } } internal static class FactoryRecipePicker { private static UIRecipePicker owned; private static UIWindowDrag drag; private static Text title; private static Vector2 titleSize; private static bool titleRaycast; internal static void Open(RectTransform origin, Action<RecipeProto> onReturn) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) UIRecipePicker recipePicker = UIRoot.instance.uiGame.recipePicker; if (((ManualBehaviour)recipePicker).active) { if ((Object)(object)owned == (Object)(object)recipePicker) { Close(); } } else if (((ManualBehaviour)recipePicker).inited) { title = ((Component)((Component)recipePicker).transform.Find("title-text")).GetComponent<Text>(); titleSize = ((Graphic)title).rectTransform.sizeDelta; titleRaycast = ((Graphic)title).raycastTarget; if ((Object)(object)drag == (Object)null) { drag = ((Component)recipePicker).gameObject.AddComponent<UIWindowDrag>(); ((Behaviour)drag).enabled = false; drag.dragTrigger = ((Component)title).gameObject.AddComponent<EventTrigger>(); drag.dragTrans = (drag.refTrans = recipePicker.pickerTrans); UIWindowDrag component = ((Component)UIRoot.instance.uiGame.assemblerWindow).GetComponent<UIWindowDrag>(); drag.screenRect = component.screenRect; drag.dragThreshold = component.dragThreshold; drag.damping = component.damping; drag.spring = component.spring; drag.hasPopupAudio = false; } RectTransform rectTransform = ((Graphic)title).rectTransform; Rect rect = recipePicker.pickerTrans.rect; rectTransform.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width - ((Graphic)title).rectTransform.anchoredPosition.x - 50f); ((Graphic)title).raycastTarget = true; owned = recipePicker; ((Behaviour)drag).enabled = true; UIRecipePicker.Popup(Vector2.zero, onReturn, (ERecipeType)0); Align(recipePicker.pickerTrans, origin, drag.screenRect); } } private static void Align(RectTransform target, RectTransform origin, RectTransform screen) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) Rect rect = origin.rect; float xMin = ((Rect)(ref rect)).xMin; rect = origin.rect; Vector3 val = ((Transform)origin).TransformPoint(new Vector3(xMin, ((Rect)(ref rect)).yMax, 0f)); Vector3 position = ((Transform)target).position; rect = target.rect; float xMin2 = ((Rect)(ref rect)).xMin; rect = target.rect; ((Transform)target).position = position + (val - ((Transform)target).TransformPoint(new Vector3(xMin2, ((Rect)(ref rect)).yMax, 0f))); Vector3[] array = (Vector3[])(object)new Vector3[4]; target.GetWorldCorners(array); Vector3 val2 = ((Transform)screen).InverseTransformPoint(array[0]); Vector3 val3 = ((Transform)screen).InverseTransformPoint(array[2]); float x = val2.x; rect = screen.rect; float num; if (!(x < ((Rect)(ref rect)).xMin)) { rect = screen.rect; num = Mathf.Min(0f, ((Rect)(ref rect)).xMax - val3.x); } else { rect = screen.rect; num = ((Rect)(ref rect)).xMin - val2.x; } float num2 = num; float y = val3.y; rect = screen.rect; float num3; if (!(y > ((Rect)(ref rect)).yMax)) { rect = screen.rect; num3 = Mathf.Max(0f, ((Rect)(ref rect)).yMin - val2.y); } else { rect = screen.rect; num3 = ((Rect)(ref rect)).yMax - val3.y; } float num4 = num3; ((Transform)target).position = ((Transform)target).position + ((Transform)screen).TransformVector(new Vector3(num2, num4, 0f)); } internal static void Close() { if (!((Object)(object)owned == (Object)null)) { if (((ManualBehaviour)owned).active) { UIRecipePicker.Close(); } else { Release(owned); } } } internal static void Release(UIRecipePicker picker) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)owned != (Object)(object)picker)) { ((Behaviour)drag).enabled = false; ((Graphic)title).rectTransform.sizeDelta = titleSize; ((Graphic)title).raycastTarget = titleRaycast; owned = null; } } } [HarmonyPatch(typeof(UIRecipePicker), "_OnClose")] internal static class RecipePickerClosePatch { private static void Postfix(UIRecipePicker __instance) { FactoryRecipePicker.Release(__instance); } } public static class FactoryRuntime { public static bool IsFactory(PlanetFactory factory, int entity) { if (factory != null && entity > 0 && entity < factory.entityPool.Length && factory.entityPool[entity].id == entity) { return factory.entityPool[entity].protoId == Prototypes.ItemId; } return false; } public static int OutputStackLimit() { return Math.Max(1, Math.Min(255, GameMain.history?.stationPilerLevel ?? 1)); } public static void SetPower(ref SpraycoaterComponent component, PowerConsumerComponent[] consumers) { if (component.incCapacity != 1048576) { ((SpraycoaterComponent)(ref component)).SetPCState(consumers); } else if (component.pcId > 0 && component.pcId < consumers.Length && consumers[component.pcId].id == component.pcId) { ((PowerConsumerComponent)(ref consumers[component.pcId])).SetRequiredEnergy(component.incUsed); } } public static void UpdateSign(PlanetFactory factory, int entity, RecipeProto recipe, bool working) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (factory.entitySignPool != null && entity > 0 && entity < factory.entitySignPool.Length) { ref SignData reference = ref factory.entitySignPool[entity]; if (reference.w <= 0f) { EntityData val = factory.entityPool[entity]; PrefabDesc prefabDesc = ((ProtoSet<ItemProto>)(object)LDB.items).Select(Prototypes.ItemId).prefabDesc; ((SignData)(ref reference)).Reset(val.pos, val.rot, prefabDesc.signHeight, prefabDesc.signSize); } reference.iconId0 = (uint)(((Proto)(recipe?)).ID ?? 0); reference.iconType = ((recipe != null) ? 2u : 0u); reference.signType = ((recipe == null) ? 4u : ((!working) ? 6u : 0u)); } } public static void Tick(ref SpraycoaterComponent component, CargoTraffic traffic, AnimData[] animations, int[] consumeRegister) { PlanetFactory factory = traffic.factory; FactoryState factoryState = FactoryStore.Get(factory.planetId, component.entityId); lock (factoryState.Sync) { if (factoryState.SprayTicks > 0) { factoryState.SprayTicks--; } RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(factoryState.RecipeId); bool flag = val != null && GameMain.history != null && GameMain.history.RecipeUnlocked(((Proto)val).ID); float num = FactoryPower.Ratio(factory.powerSystem, component.pcId); if (flag && num >= 0.1f) { Receive(traffic, component.incBeltId, factoryState, val); } bool flag2 = false; component.incUsed = flag && factoryState.CanWork(val); if (flag && num >= 0.1f) { int[] productRegister = GameMain.statistics.production.factoryStatPool[factory.index].productRegister; flag2 = factoryState.Tick(val, delegate(int id, int count) { lock (consumeRegister) { consumeRegister[id] += count; } }, delegate(int id, int count) { lock (productRegister) { productRegister[id] += count; } }, num); } if (!flag) { factoryState.Status = ((val == null) ? "未选择配方" : "配方尚未解锁"); } else if (num < 0.1f) { factoryState.Status = "未供电"; } else if (flag2 && num < 0.999f) { factoryState.Status = "供电不足"; } UpdateSign(factory, component.entityId, val, flag2); if (num < 0.5f && factory.entitySignPool != null) { int num2 = ((component.pcId > 0 && component.pcId < factory.powerSystem.consumerPool.Length) ? factory.powerSystem.consumerPool[component.pcId].networkId : 0); factory.entitySignPool[component.entityId].signType = ((num2 == 0) ? 1u : ((num < 0.1f) ? 2u : 3u)); } if (num >= 0.1f) { Send(traffic, component.cargoBeltId, factoryState); } if (animations != null) { ref AnimData reference = ref animations[component.entityId]; UpdateAnimation(ref reference, factoryState, val); reference.power = num; } } } public static void UpdateAnimation(ref AnimData animation, FactoryState state, RecipeProto recipe) { float num = 0f; float num2 = 0f; if (recipe != null) { for (int i = 0; i < recipe.Items.Length; i++) { num += (float)FactoryState.InputLimit(recipe.ItemCounts[i]); if (state.Input.TryGetValue(recipe.Items[i], out var value)) { num2 += (float)value.Count; } if (state.Pending.TryGetValue(recipe.Items[i], out var value2)) { num2 += (float)value2.Count; } } } animation.state = ((recipe == null && state.SprayTicks == 0) ? 1u : 41u); if (state.SprayTicks > 0) { animation.state += (uint)(100 + state.SprayTicks * 1000); } animation.time = ((recipe == null) ? 0f : Mathf.Lerp(0.35f, 0.9f, (num > 0f) ? Mathf.Clamp01(num2 / num) : 0f)); animation.power = 1f; } public static void Receive(CargoTraffic traffic, int belt, FactoryState state, RecipeProto recipe) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (belt <= 0 || belt >= traffic.beltPool.Length || traffic.beltPool[belt].id != belt) { return; } BeltComponent val = traffic.beltPool[belt]; CargoPath cargoPath = traffic.GetCargoPath(val.segPathId); if (cargoPath == null) { return; } lock (cargoPath.buffer) { int num = val.segIndex + val.segPivotOffset; int cargoIdAtIndex = cargoPath.GetCargoIdAtIndex(num - 2, 5); if (cargoIdAtIndex < 0) { return; } ref Cargo reference = ref traffic.container.cargoPool[cargoIdAtIndex]; if (reference.stack <= 0) { return; } int num2 = Math.Min(state.Acceptable(recipe, reference.item), reference.stack); if (num2 <= 0) { return; } if (num2 < reference.stack) { int num3 = reference.inc * num2 / reference.stack; FactoryState.Buffer(state.Input, reference.item).Add(num2, num3); reference.stack -= (byte)num2; reference.inc -= (byte)num3; } else { byte count = default(byte); byte inc = default(byte); int num4 = cargoPath.TryPickItem(num - 2, 5, (int)reference.item, ref count, ref inc); if (num4 > 0) { FactoryState.Buffer(state.Input, num4).Add(count, inc); } } } } public static void Send(CargoTraffic traffic, int belt, FactoryState state) { if (belt <= 0 || belt >= traffic.beltPool.Length || traffic.beltPool[belt].id != belt) { return; } int stack = OutputStackLimit(); KeyValuePair<int, ItemBuffer>[] array = (from x in state.Output where x.Value.Count >= stack orderby x.Key select x).ToArray(); if (array.Length != 0) { int num = (state.OutputCursor & 0x7FFFFFFF) % array.Length; KeyValuePair<int, ItemBuffer> keyValuePair = array[num]; int num2 = (int)((keyValuePair.Value.Count != 0) ? ((long)keyValuePair.Value.Inc * (long)stack / keyValuePair.Value.Count) : 0); if (num2 <= 255 && traffic.TryInsertItem(belt, 0, keyValuePair.Key, (byte)stack, (byte)Math.Min(255, num2))) { keyValuePair.Value.Take(stack); state.SprayTicks = 45; state.SprayItemId = keyValuePair.Key; state.OutputCursor = (num + 1) % array.Length; } } } public static void ReturnItems(Player player, int entity, FactoryState state) { lock (state.Sync) { Dictionary<int, ItemBuffer>[] array = new Dictionary<int, ItemBuffer>[3] { state.Input, state.Output, state.Pending }; for (int i = 0; i < array.Length; i++) { foreach (KeyValuePair<int, ItemBuffer> item in array[i]) { player.TryAddItemToPackage(item.Key, item.Value.Count, item.Value.Inc, true, entity, false); item.Value.Count = (item.Value.Inc = 0); } } state.Input.Clear(); state.Output.Clear(); state.Pending.Clear(); state.Progress = (state.Duration = 0); state.PowerProgress = 0.0; state.SprayTicks = (state.SprayItemId = 0); } } } [HarmonyPatch(typeof(SpraycoaterComponent), "InternalUpdate")] internal static class ProductionPatch { private static bool Prefix(ref SpraycoaterComponent __instance, CargoTraffic _traffic, AnimData[] _animPool, int[] consumeRegister) { if (!FactoryRuntime.IsFactory(_traffic.factory, __instance.entityId)) { return true; } FactoryRuntime.Tick(ref __instance, _traffic, _animPool, consumeRegister); return false; } } [HarmonyPatch(typeof(CargoTraffic), "SpraycoaterGameTick")] internal static class PowerPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo source = AccessTools.Method(typeof(SpraycoaterComponent), "SetPCState", (Type[])null, (Type[])null); MethodInfo target = AccessTools.Method(typeof(FactoryRuntime), "SetPower", (Type[])null, (Type[])null); int replaced = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, source)) { instruction.opcode = OpCodes.Call; instruction.operand = target; replaced++; } yield return instruction; } if (replaced != 1) { throw new InvalidOperationException("Spraycoater power update call was not found exactly once."); } } } [HarmonyPatch(typeof(CargoTraffic), "TakeBackItems_Spraycoater")] internal static class ReturnPatch { private static bool Prefix(CargoTraffic __instance, Player player, int spraycoaterId) { int entityId = __instance.spraycoaterPool[spraycoaterId].entityId; if (!FactoryRuntime.IsFactory(__instance.factory, entityId)) { return true; } if (FactoryStore.TryGet(__instance.factory.planetId, entityId, out var state)) { FactoryRuntime.ReturnItems(player, entityId, state); lock (state.Sync) { state.Progress = (state.Duration = 0); } } return false; } } [HarmonyPatch(typeof(CargoTraffic), "ClearItems_Spraycoater")] internal static class ClearPatch { private static bool Prefix(CargoTraffic __instance, int spraycoaterId) { int entityId = __instance.spraycoaterPool[spraycoaterId].entityId; if (!FactoryRuntime.IsFactory(__instance.factory, entityId)) { return true; } if (FactoryStore.TryGet(__instance.factory.planetId, entityId, out var state)) { lock (state.Sync) { state.Input.Clear(); state.Output.Clear(); state.Pending.Clear(); state.Progress = (state.Duration = 0); state.PowerProgress = 0.0; } } return false; } } [HarmonyPatch(typeof(CargoTraffic), "RemoveSpraycoaterComponent")] internal static class RemovePatch { private static void Prefix(CargoTraffic __instance, int id) { int entityId = __instance.spraycoaterPool[id].entityId; if (FactoryRuntime.IsFactory(__instance.factory, entityId) && FactoryStore.Remove(__instance.factory.planetId, entityId, out var state) && GameMain.mainPlayer != null) { FactoryRuntime.ReturnItems(GameMain.mainPlayer, entityId, state); } } } public sealed class ItemBuffer { public int Count; public int Inc; public void Add(int count, int inc) { checked { Count += count; Inc += inc; } } public int Take(int count) { if (count < 0 || count > Count) { throw new ArgumentOutOfRangeException("count"); } int num = (int)((Count != 0) ? ((long)Inc * (long)count / Count) : 0); Count -= count; Inc -= num; return num; } } public sealed class FactoryState { public readonly object Sync = new object(); public readonly Dictionary<int, ItemBuffer> Input = new Dictionary<int, ItemBuffer>(); public readonly Dictionary<int, ItemBuffer> Output = new Dictionary<int, ItemBuffer>(); public readonly Dictionary<int, ItemBuffer> Pending = new Dictionary<int, ItemBuffer>(); public int RecipeId; public int Progress; public int Duration; public double PowerProgress; public double ExtraProgress; public int OutputCursor; public bool ForceAccMode; public bool BatchAccMode; public int SprayTicks; public int SprayItemId; public string Status = "未选择配方"; public double BatchBonus; public static ItemBuffer Buffer(Dictionary<int, ItemBuffer> buffers, int item) { if (!buffers.TryGetValue(item, out var value)) { value = (buffers[item] = new ItemBuffer()); } return value; } public static int InputLimit(int recipeCount) { return checked(recipeCount * 2); } public static int ManualInputRounds(ERecipeType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)type != 1) { return 20; } return 50; } public static int ManualInputLimit(int recipeCount, ERecipeType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return checked(recipeCount * ManualInputRounds(type)); } public static int OutputLimit(int recipeCount, int batches = 1) { return Math.Max(200, checked(Math.Max(recipeCount * 20, FactoryRuntime.OutputStackLimit() + recipeCount * batches - 1))); } public int Acceptable(RecipeProto recipe, int item) { if (recipe == null) { return 0; } int num = Array.IndexOf(recipe.Items, item); if (num >= 0) { return Math.Max(0, InputLimit(recipe.ItemCounts[num]) - Buffer(Input, item).Count); } return 0; } public void ChangeRecipe(int recipeId) { if (recipeId == RecipeId) { return; } foreach (KeyValuePair<int, ItemBuffer> item in Pending) { Buffer(Input, item.Key).Add(item.Value.Count, item.Value.Inc); } Pending.Clear(); Progress = (Duration = 0); ExtraProgress = 0.0; RecipeId = recipeId; PowerProgress = 0.0; SprayTicks = (SprayItemId = 0); } public bool CanWork(RecipeProto recipe) { if (recipe != null) { int level; double bonus; if (Pending.Count <= 0 && Duration <= 0) { return TryPlan(recipe, out level, out bonus); } return true; } return false; } private bool TryPlan(RecipeProto recipe, out int level, out double bonus) { level = 0; bonus = 0.0; for (int i = 0; i < recipe.Items.Length; i++) { if (Buffer(Input, recipe.Items[i]).Count < recipe.ItemCounts[i]) { Status = "缺少原料"; return false; } } level = ((recipe.Items.Length != 0) ? 10 : 0); for (int j = 0; j < recipe.Items.Length; j++) { ItemBuffer itemBuffer = Buffer(Input, recipe.Items[j]); level = Math.Min(level, (itemBuffer.Count != 0) ? (itemBuffer.Inc / itemBuffer.Count) : 0); } level = Math.Max(0, Math.Min(level, Cargo.accTableMilli.Length - 1)); bonus = ((recipe.productive && !ForceAccMode) ? Cargo.incTableMilli[Math.Min(level, Cargo.incTableMilli.Length - 1)] : 0.0); int num = 1 + (int)(ExtraProgress + bonus); for (int k = 0; k < recipe.Results.Length; k++) { if (Buffer(Output, recipe.Results[k]).Count + (long)recipe.ResultCounts[k] * (long)num > OutputLimit(recipe.ResultCounts[k], num)) { Status = "产物缓存已满"; return false; } } return true; } public bool Tick(RecipeProto recipe, Action<int, int> consume, Action<int, int> produce, float power = 1f) { if (recipe == null) { Status = "未选择配方"; return false; } if (power < 0.1f) { Status = "未供电"; return false; } if (Pending.Count == 0 && Duration == 0) { if (!TryPlan(recipe, out var level, out var bonus)) { return false; } bool flag = recipe.productive && !ForceAccMode; for (int i = 0; i < recipe.Items.Length; i++) { ItemBuffer itemBuffer = Buffer(Input, recipe.Items[i]); int count = recipe.ItemCounts[i]; Buffer(Pending, recipe.Items[i]).Add(count, itemBuffer.Take(count)); } Duration = Math.Max(1, recipe.TimeSpend); if (!flag) { Duration = Math.Max(1, (int)Math.Ceiling((double)Duration / (1.0 + Cargo.accTableMilli[level]))); } BatchBonus = bonus; BatchAccMode = !flag; } Status = "生产中"; PowerProgress += Math.Max(0f, Math.Min(1f, power)); if (PowerProgress < 1.0) { return true; } PowerProgress -= 1.0; if (++Progress < Duration) { return true; } ExtraProgress += BatchBonus; int num = 1 + (int)ExtraProgress; ExtraProgress -= (int)ExtraProgress; for (int j = 0; j < recipe.Results.Length; j++) { int num2 = checked(recipe.ResultCounts[j] * num); Buffer(Output, recipe.Results[j]).Add(num2, 0); produce?.Invoke(recipe.Results[j], num2); } foreach (KeyValuePair<int, ItemBuffer> item in Pending) { consume?.Invoke(item.Key, item.Value.Count); } Pending.Clear(); Progress = (Duration = 0); return true; } public void Write(BinaryWriter w) { w.Write(RecipeId); w.Write(Progress); w.Write(Duration); w.Write(ExtraProgress); w.Write(BatchBonus); w.Write(OutputCursor); WriteBuffers(w, Input); WriteBuffers(w, Output); WriteBuffers(w, Pending); w.Write(ForceAccMode); w.Write(BatchAccMode); } public static FactoryState Read(BinaryReader r, int version = 2) { FactoryState factoryState = new FactoryState { RecipeId = r.ReadInt32(), Progress = r.ReadInt32(), Duration = r.ReadInt32(), ExtraProgress = r.ReadDouble(), BatchBonus = r.ReadDouble(), OutputCursor = r.ReadInt32() }; if (factoryState.Progress < 0 || factoryState.Duration < 0 || factoryState.Progress > factoryState.Duration || double.IsNaN(factoryState.ExtraProgress) || double.IsInfinity(factoryState.ExtraProgress) || factoryState.ExtraProgress < 0.0 || factoryState.ExtraProgress >= 1.0 || double.IsNaN(factoryState.BatchBonus) || double.IsInfinity(factoryState.BatchBonus) || factoryState.BatchBonus < 0.0 || factoryState.BatchBonus > 10.0) { throw new InvalidDataException("Invalid factory progress."); } ReadBuffers(r, factoryState.Input); ReadBuffers(r, factoryState.Output); ReadBuffers(r, factoryState.Pending); if (version >= 2) { factoryState.ForceAccMode = r.ReadBoolean(); factoryState.BatchAccMode = r.ReadBoolean(); } return factoryState; } private static void WriteBuffers(BinaryWriter w, Dictionary<int, ItemBuffer> buffers) { KeyValuePair<int, ItemBuffer>[] array = (from x in buffers where x.Value.Count > 0 orderby x.Key select x).ToArray(); w.Write(array.Length); KeyValuePair<int, ItemBuffer>[] array2 = array; for (int num = 0; num < array2.Length; num++) { KeyValuePair<int, ItemBuffer> keyValuePair = array2[num]; w.Write(keyValuePair.Key); w.Write(keyValuePair.Value.Count); w.Write(keyValuePair.Value.Inc); } } private static void ReadBuffers(BinaryReader r, Dictionary<int, ItemBuffer> buffers) { int num = r.ReadInt32(); if (num < 0 || num > 12000) { throw new InvalidDataException("Invalid factory buffer size."); } for (int i = 0; i < num; i++) { int num2 = r.ReadInt32(); int num3 = r.ReadInt32(); int num4 = r.ReadInt32(); if (num2 <= 0 || num3 < 0 || num4 < 0 || buffers.ContainsKey(num2)) { throw new InvalidDataException("Invalid factory buffer entry."); } buffers.Add(num2, new ItemBuffer { Count = num3, Inc = num4 }); } } } public static class FactoryStore { private static readonly ConcurrentDictionary<long, FactoryState> states = new ConcurrentDictionary<long, FactoryState>(); public static long Key(int planet, int entity) { return ((long)planet << 32) | (uint)entity; } public static FactoryState Get(int planet, int entity) { return states.GetOrAdd(Key(planet, entity), (long _) => new FactoryState()); } public static bool Remove(int planet, int entity, out FactoryState state) { return states.TryRemove(Key(planet, entity), out state); } public static bool TryGet(int planet, int entity, out FactoryState state) { return states.TryGetValue(Key(planet, entity), out state); } public static void Clear() { states.Clear(); } public static void Export(BinaryWriter w) { w.Write(2); KeyValuePair<long, FactoryState>[] array = states.OrderBy((KeyValuePair<long, FactoryState> x) => x.Key).ToArray(); w.Write(array.Length); KeyValuePair<long, FactoryState>[] array2 = array; for (int num = 0; num < array2.Length; num++) { KeyValuePair<long, FactoryState> keyValuePair = array2[num]; w.Write(keyValuePair.Key); lock (keyValuePair.Value.Sync) { keyValuePair.Value.Write(w); } } } public static void Import(BinaryReader r) { int num = r.ReadInt32(); if (num != 1 && num != 2) { throw new InvalidDataException("Unsupported Spray Factory save version."); } int num2 = r.ReadInt32(); if (num2 < 0 || num2 > 1000000) { throw new InvalidDataException("Invalid factory count."); } Dictionary<long, FactoryState> dictionary = new Dictionary<long, FactoryState>(); for (int i = 0; i < num2; i++) { dictionary.Add(r.ReadInt64(), FactoryState.Read(r, num)); } states.Clear(); foreach (KeyValuePair<long, FactoryState> item in dictionary) { states[item.Key] = item.Value; } } } internal static class FactoryRates { internal static void Calculate(FactoryState state, RecipeProto recipe, out float cycles, out float multiplier) { int val = ((recipe.Items.Length != 0) ? (Cargo.accTableMilli.Length - 1) : 0); Dictionary<int, ItemBuffer> dictionary = ((state.Pending.Count > 0) ? state.Pending : state.Input); int[] items = recipe.Items; foreach (int key in items) { ItemBuffer value; int val2 = ((dictionary.TryGetValue(key, out value) && value.Count > 0) ? (value.Inc / value.Count) : 0); val = Math.Min(val, val2); } val = Math.Max(0, Math.Min(val, Cargo.accTableMilli.Length - 1)); bool flag = recipe.productive && !state.ForceAccMode; int num = Math.Max(1, recipe.TimeSpend); if (!flag) { num = Math.Max(1, (int)Math.Ceiling((double)num / (1.0 + Cargo.accTableMilli[val]))); } cycles = 3600f / (float)num; multiplier = (flag ? (1f + (float)Cargo.incTableMilli[Math.Min(val, Cargo.incTableMilli.Length - 1)]) : 1f); } } [HarmonyPatch(typeof(ProductionExtraInfoCalculator), "CalculateFactory")] internal static class FactoryStatistics { private static void Postfix(ProductionExtraInfoCalculator __instance, GameData gameData, PlanetFactory factory) { ProductionStatistics productionStatistics = __instance.productionStatistics; object obj; if (productionStatistics == null) { obj = null; } else { FactoryProductionStat[] factoryStatPool = productionStatistics.factoryStatPool; obj = ((factoryStatPool != null) ? factoryStatPool[factory.index] : null); } FactoryProductionStat val = (FactoryProductionStat)obj; if (val != null && factory.cargoTraffic != null) { Add(factory, gameData.history, val); } } internal static void Add(PlanetFactory factory, GameHistoryData history, FactoryProductionStat stat) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) CargoTraffic cargoTraffic = factory.cargoTraffic; for (int i = 1; i < cargoTraffic.spraycoaterCursor; i++) { SpraycoaterComponent val = cargoTraffic.spraycoaterPool[i]; if (val.id != i || !FactoryRuntime.IsFactory(factory, val.entityId) || !FactoryStore.TryGet(factory.planetId, val.entityId, out var state)) { continue; } lock (state.Sync) { RecipeProto val2 = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(state.RecipeId); if (val2 != null && history.RecipeUnlocked(((Proto)val2).ID)) { FactoryRates.Calculate(state, val2, out var cycles, out var multiplier); for (int j = 0; j < val2.Items.Length; j++) { stat.AddRefConsumeSpeed(val2.Items[j], cycles * (float)val2.ItemCounts[j]); } for (int k = 0; k < val2.Results.Length; k++) { stat.AddRefProductSpeed(val2.Results[k], cycles * multiplier * (float)val2.ResultCounts[k]); } } AddStorage(stat, state.Input); AddStorage(stat, state.Output); AddStorage(stat, state.Pending); } } } private static void AddStorage(FactoryProductionStat stat, Dictionary<int, ItemBuffer> buffers) { foreach (KeyValuePair<int, ItemBuffer> buffer in buffers) { if (buffer.Value.Count > 0) { stat.AddStorageCount(buffer.Key, buffer.Value.Count); stat.AddDetailedStorageCount(buffer.Key, (EDetailedStorageCountType)3, buffer.Value.Count); } } } } internal static class FactoryWindow { private sealed class ProductSlot { internal RectTransform Root; internal UIButton Button; internal Image Icon; internal Image Progress; internal Image ExtraProgress; internal Text Count; } private static UISpraycoaterWindow owner; private static UIAssemblerWindow view; private static readonly Dictionary<GameObject, bool> hidden = new Dictionary<GameObject, bool>(); private static Vector2 originalSize; private static Vector2 originalPosition; private static Vector2 screenSize; private static Vector2? savedTopLeft; private static bool initialLayout; private static UIWindowDrag windowDrag; private static readonly Vector3[] windowCorners = (Vector3[])(object)new Vector3[4]; private static StorageComponent serving; private static int servingRecipe; private static Vector2 originalIncPosition; private static Vector2 originalTipPosition; private static Vector2 originalSpeedPosition; private static Vector2 originalServingPosition; private static readonly List<ProductSlot> extraProducts = new List<ProductSlot>(); private static readonly StringBuilder powerServed = new StringBuilder(" W %", 20); internal static bool Matches(UISpraycoaterWindow window) { if (window.factory != null && window.traffic != null && window.spraycoaterId > 0) { return FactoryRuntime.IsFactory(window.factory, window.traffic.spraycoaterPool[window.spraycoaterId].entityId); } return false; } internal static void Show(UISpraycoaterWindow window) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Expected O, but got Unknown //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Expected O, but got Unknown if ((Object)(object)owner == (Object)(object)window && (Object)(object)view != (Object)null) { return; } Hide(); owner = window; originalSize = ((RectTransform)((Component)owner).transform).sizeDelta; originalPosition = ((RectTransform)((Component)owner).transform).anchoredPosition; initialLayout = true; foreach (Transform item in ((Component)owner).transform) { Transform val = item; hidden[((Component)val).gameObject] = ((Component)val).gameObject.activeSelf; ((Component)val).gameObject.SetActive(false); } view = Object.Instantiate<UIAssemblerWindow>(UIRoot.instance.uiGame.assemblerWindow, ((Component)owner).transform, false); ((Object)view).name = "spray-factory-panel"; ((Behaviour)view).enabled = false; Transform obj = ((Transform)view.produceGroup).Find("lithography"); if (obj != null) { ((Component)obj).gameObject.SetActive(false); } originalIncPosition = view.incInfoGroup.anchoredPosition; originalTipPosition = ((Graphic)view.transferTipText).rectTransform.anchoredPosition; originalSpeedPosition = view.speedGroup.anchoredPosition; originalServingPosition = view.servingGroup.anchoredPosition; RectTransform val2 = (RectTransform)((Component)view).transform; Vector2 anchorMin = (val2.anchorMax = val2.pivot); val2.anchorMin = anchorMin; val2.anchoredPosition = Vector2.zero; ((Transform)val2).localScale = Vector3.one; Button[] componentsInChildren = ((Component)view).GetComponentsInChildren<Button>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].onClick = new ButtonClickedEvent(); } SetText(view.titleText, "喷涂工厂"); Bind(view.recipeButton.button, SelectRecipe); Bind(view.resetButton.button, delegate { WithState(delegate(FactoryState state) { state.ChangeRecipe(0); }); }); Bind(view.productButton0.button, delegate { TakeOutput(0); }); Bind(view.productButton1.button, delegate { TakeOutput(1); }); Bind(view.incSwitchButton, delegate { WithState(delegate(FactoryState state) { state.ForceAccMode = !state.ForceAccMode; }); }); ((Component)view.copyButton).gameObject.SetActive(false); ((Component)view.pasteButton).gameObject.SetActive(false); Bind(((Component)((Component)view).transform.Find("panel-bg/btn-box/close-wnd-btn")).GetComponent<Button>(), delegate { UIRoot.instance.uiGame.ShutSpraycoaterWindow(); }); ((Component)view.menuButton).gameObject.SetActive(false); ((Component)view.alarmSwitchButton).gameObject.SetActive(false); ((Component)view.alarmSwitchText).gameObject.SetActive(false); InitializeGrid(view.playerInventory); InitializeGrid(view.servingBox); view.servingBox.beforeManualChange += SyncInputs; UIWindowDrag component = ((Component)view).GetComponent<UIWindowDrag>(); component.dragTrans = (RectTransform)((Component)owner).transform; component.refTrans = component.dragTrans; windowDrag = component; ((Component)view).gameObject.SetActive(true); } private static Vector3 TopLeft(RectTransform rect) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) Rect rect2 = rect.rect; float xMin = ((Rect)(ref rect2)).xMin; rect2 = rect.rect; return ((Transform)rect).TransformPoint(new Vector3(xMin, ((Rect)(ref rect2)).yMax, 0f)); } private static void ResizeWindow(Vector2 size) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)((Component)owner).transform; RectTransform screenRect = windowDrag.screenRect; Rect rect; if (!initialLayout && val.sizeDelta == size) { Vector2 val2 = screenSize; rect = screenRect.rect; if (val2 == ((Rect)(ref rect)).size) { return; } } Vector3 val3 = TopLeft(val); view.windowTrans.sizeDelta = size; val.sizeDelta = size; if (initialLayout && !savedTopLeft.HasValue) { Vector3 position = ((Transform)val).position; rect = screenRect.rect; Vector3 val4 = ((Transform)screenRect).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)); rect = val.rect; ((Transform)val).position = position + (val4 - ((Transform)val).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center))); } else { ((Transform)val).position = ((Transform)val).position + ((initialLayout ? ((Transform)screenRect).TransformPoint(Vector2.op_Implicit(savedTopLeft.Value)) : val3) - TopLeft(val)); } initialLayout = false; rect = screenRect.rect; screenSize = ((Rect)(ref rect)).size; val.GetWorldCorners(windowCorners); Vector3 val5 = ((Transform)screenRect).InverseTransformPoint(windowCorners[0]); Vector3 val6 = ((Transform)screenRect).InverseTransformPoint(windowCorners[2]); rect = screenRect.rect; float num = ((Rect)(ref rect)).xMin + 12f; rect = screenRect.rect; float num2 = ((Rect)(ref rect)).xMax - 12f; rect = screenRect.rect; float num3 = ((Rect)(ref rect)).yMin + 12f; rect = screenRect.rect; float num4 = ((Rect)(ref rect)).yMax - 12f; float num5 = ((val6.x - val5.x > num2 - num) ? (num - val5.x) : ((val5.x < num) ? (num - val5.x) : Mathf.Min(0f, num2 - val6.x))); float num6 = ((val6.y - val5.y > num4 - num3) ? (num4 - val6.y) : ((val6.y > num4) ? (num4 - val6.y) : Mathf.Max(0f, num3 - val5.y))); ((Transform)val).position = ((Transform)val).position + ((Transform)screenRect).TransformVector(new Vector3(num5, num6, 0f)); } private static void SetText(Text label, string text) { Localizer component = ((Component)label).GetComponent<Localizer>(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } label.text = text; } private static void InitializeGrid(UIStorageGrid grid) { foreach (Component item in from c in ((Component)grid).GetComponentsInChildren<Component>(true) where (Object)(object)c != (Object)null && ((object)c).GetType().Name == "UICancelFilterTip" select c) { Object.DestroyImmediate((Object)(object)item.gameObject); } Text[] componentsInChildren = ((Component)grid).GetComponentsInChildren<Text>(true); foreach (Text val in componentsInChildren) { if ((Object)(object)val != (Object)(object)grid.prefabNumText && (Object)(object)((Component)val).transform.parent == (Object)(object)grid.rectTrans && ((Object)val).name == ((Object)grid.prefabNumText).name + "(Clone)") { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } ((ManualBehaviour)grid)._Create(); foreach (Component item2 in from c in ((Component)grid).GetComponentsInChildren<Component>(true) where (Object)(object)c != (Object)null && ((object)c).GetType().Name == "UICancelFilterTip" select c) { item2.gameObject.SetActive(false); } } private static void RefreshPower() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) SpraycoaterComponent val = owner.traffic.spraycoaterPool[owner.spraycoaterId]; PowerSystem powerSystem = owner.factory.powerSystem; float num = FactoryPower.Ratio(powerSystem, val.pcId); ((Component)view.powerIcon).gameObject.SetActive(true); if (num < 0.1f) { view.powerText.text = Localization.Translate("未供电"); ((Graphic)view.powerIcon).color = Color.clear; ((Graphic)view.powerText).color = view.powerOffColor; return; } long num2 = (long)((double)((float)(powerSystem.consumerPool[val.pcId].requiredEnergy * 60) * num) + 0.5); StringBuilderUtility.WriteKMG(powerServed, 8, num2, false, '\u2009', ' '); StringBuilderUtility.WriteUInt(powerServed, 12, 3, (uint)(num * 100f), 1, ' '); view.powerText.text = powerServed.ToString(); ((Graphic)view.powerIcon).color = ((num >= 0.999f) ? view.powerNormalIconColor : view.powerLowIconColor); ((Graphic)view.powerText).color = ((num >= 0.999f) ? view.powerNormalColor : view.powerLowColor); } private static void Bind(Button button, Action action) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) button.onClick = new ButtonClickedEvent(); ((UnityEvent)button.onClick).AddListener((UnityAction)delegate { action(); }); UIButton component = ((Component)button).GetComponent<UIButton>(); if ((Object)(object)component != (Object)null) { component.tips = default(TipSettings); } } private static T CloneProductField<T>(RectTransform root, T original) where T : Component { List<string> list = new List<string>(); Transform val = ((Component)original).transform; while ((Object)(object)val != (Object)(object)view.productGroup) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return ((Component)((Transform)root).Find(string.Join("/", list))).GetComponent<T>(); } private static void EnsureProductSlots(int count) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) while (extraProducts.Count < Math.Max(0, count - 2)) { int index = extraProducts.Count + 2; RectTransform val = Object.Instantiate<RectTransform>(view.productGroup, ((Transform)view.productGroup).parent, false); ((Object)val).name = "product-slot-" + index; val.sizeDelta = new Vector2(64f, 64f); val.anchoredPosition = view.productGroup.anchoredPosition + new Vector2((float)(64 * (index % 3)), (float)(-64 * (index / 3))); ((Component)CloneProductField<UIButton>(val, view.productButton1)).gameObject.SetActive(false); ((Component)CloneProductField<Text>(val, view.productCountText1)).gameObject.SetActive(false); ((Component)CloneProductField<Image>(val, view.productProgress1)).gameObject.SetActive(false); ((Component)CloneProductField<Image>(val, view.extraProductProgress1)).gameObject.SetActive(false); if (((Component)view.resetButton).transform.IsChildOf((Transform)(object)view.productGroup)) { ((Component)CloneProductField<UIButton>(val, view.resetButton)).gameObject.SetActive(false); } ProductSlot productSlot = new ProductSlot { Root = val, Button = CloneProductField<UIButton>(val, view.productButton0), Icon = CloneProductField<Image>(val, view.productIcon0), Count = CloneProductField<Text>(val, view.productCountText0), Progress = CloneProductField<Image>(val, view.productProgress0), ExtraProgress = CloneProductField<Image>(val, view.extraProductProgress0) }; Bind(productSlot.Button.button, delegate { TakeOutput(index); }); extraProducts.Add(productSlot); } for (int num = 0; num < extraProducts.Count; num++) { ((Component)extraProducts[num].Root).gameObject.SetActive(num + 2 < count); } } private static void WithState(Action<FactoryState> action) { if ((Object)(object)owner == (Object)null || !Matches(owner)) { return; } int entityId = owner.traffic.spraycoaterPool[owner.spraycoaterId].entityId; FactoryState factoryState = FactoryStore.Get(owner.factory.planetId, entityId); lock (factoryState.Sync) { int recipeId = factoryState.RecipeId; action(factoryState); if (recipeId != factoryState.RecipeId) { FactoryRuntime.UpdateSign(owner.factory, entityId, ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(factoryState.RecipeId), working: false); } } } private static void SelectRecipe() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown if ((Object)(object)owner == (Object)null) { return; } int planet = owner.factory.planetId; int entity = owner.traffic.spraycoaterPool[owner.spraycoaterId].entityId; FactoryRecipePicker.Open((RectTransform)((Component)owner).transform, delegate(RecipeProto recipe) { if (recipe != null && !((Object)(object)owner == (Object)null) && Matches(owner) && owner.factory.planetId == planet && owner.traffic.spraycoaterPool[owner.spraycoaterId].entityId == entity) { WithState(delegate(FactoryState state) { state.ChangeRecipe(((Proto)recipe).ID); }); } }); } private static void TakeOutput(int index) { WithState(delegate(FactoryState state) { RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(state.RecipeId); if (GameMain.mainPlayer != null && val != null && index < val.Results.Length) { int num = val.Results[index]; ItemBuffer itemBuffer = FactoryState.Buffer(state.Output, num); GameMain.mainPlayer.TryAddItemToPackage(num, itemBuffer.Count, itemBuffer.Inc, true, owner.traffic.spraycoaterPool[owner.spraycoaterId].entityId, false); itemBuffer.Count = (itemBuffer.Inc = 0); } }); } private static void FreeServing() { if (serving != null) { serving.onStorageChange -= ApplyInputs; ((ManualBehaviour)view.servingBox)._Free(); serving.Free(); serving = null; servingRecipe = 0; } } private static void ApplyInputs() { WithState(delegate(FactoryState state) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (serving != null && state.RecipeId == servingRecipe) { GRID[] grids = serving.grids; foreach (GRID val in grids) { ItemBuffer itemBuffer = FactoryState.Buffer(state.Input, val.filter); itemBuffer.Count = val.count; itemBuffer.Inc = val.inc; } } }); } private static void SyncInputs() { WithState(delegate(FactoryState state) { RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(state.RecipeId); if (serving != null && val != null && state.RecipeId == servingRecipe) { for (int i = 0; i < val.Items.Length; i++) { ItemBuffer itemBuffer = FactoryState.Buffer(state.Input, val.Items[i]); serving.grids[i].count = itemBuffer.Count; serving.grids[i].inc = itemBuffer.Inc; } view.servingBox.OnStorageContentChanged(); } }); } internal static void Refresh(UISpraycoaterWindow window) { Show(window); WithState(delegate(FactoryState state) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Expected O, but got Unknown //IL_0459: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_08f3: Unknown result type (might be due to invalid IL or missing references) //IL_0915: Unknown result type (might be due to invalid IL or missing references) //IL_091a: Unknown result type (might be due to invalid IL or missing references) //IL_076a: Unknown result type (might be due to invalid IL or missing references) //IL_0797: Unknown result type (might be due to invalid IL or missing references) //IL_07bb: Unknown result type (might be due to invalid IL or missing references) //IL_0974: Unknown result type (might be due to invalid IL or missing references) //IL_0814: Unknown result type (might be due to invalid IL or missing references) //IL_0820: Unknown result type (might be due to invalid IL or missing references) //IL_06fd: Unknown result type (might be due to invalid IL or missing references) RecipeProto val = ((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(state.RecipeId); bool flag = val != null; bool flag2 = flag && (!val.productive || state.ForceAccMode); int num = (flag ? (64 * Math.Max((val.Items.Length - 1) / 3, (val.Results.Length - 1) / 3)) : 0); view.incInfoGroup.anchoredPosition = originalIncPosition - Vector2.up * (float)num; if (!((Component)view.transferTipText).transform.IsChildOf((Transform)(object)view.incInfoGroup) && !((Component)view.transferTipText).transform.IsChildOf((Transform)(object)view.playerInventoryGroup)) { ((Graphic)view.transferTipText).rectTransform.anchoredPosition = originalTipPosition - Vector2.up * (float)num; } ((Component)view.recipeGroup).gameObject.SetActive(!flag); ((Component)view.produceGroup).gameObject.SetActive(flag); ((Component)view.incInfoGroup).gameObject.SetActive(flag); RefreshPower(); view.stateText.text = state.Status; ((Graphic)view.stateText).color = ((state.Status == "生产中") ? view.workNormalColor : view.workStoppedColor); ((Selectable)view.resetButton.button).interactable = flag; ((Selectable)view.incSwitchButton).interactable = flag && val.productive; ((Graphic)view.incSwitchButtonImage).color = (flag2 ? view.incButtonColor2 : view.incButtonColor1); ((Graphic)view.incSwitchButtonThumb).rectTransform.anchoredPosition = new Vector2((float)(flag2 ? 10 : (-10)), 0f); view.incEffectTypeText.text = (flag2 ? "加速生产" : "额外产出"); ((Graphic)view.incEffectTypeText).color = (flag2 ? view.incTextColor2 : view.incTextColor1); view.incEffectValueText2.text = "+0.0 %"; SetText(view.transferTipText, "自动进料:2 轮 满 " + FactoryRuntime.OutputStackLimit() + " 层输出"); if (servingRecipe != state.RecipeId) { FreeServing(); if (flag && val.Items.Length != 0) { serving = new StorageComponent(val.Items.Length) { type = (EStorageType)9 }; servingRecipe = state.RecipeId; for (int i = 0; i < val.Items.Length; i++) { serving.SetFilterDirect(i, val.Items[i], FactoryState.ManualInputLimit(val.ItemCounts[i], val.Type)); } serving.onStorageChange += ApplyInputs; view.servingBox.colCount = Math.Min(3, val.Items.Length); view.servingBox.lackParam = FactoryState.ManualInputRounds(val.Type); ((ManualBehaviour)view.servingBox)._Init((object)serving); ((ManualBehaviour)view.servingBox)._Open(); } } ((Component)view.servingGroup).gameObject.SetActive(serving != null); SyncInputs(); if (flag) { FactoryRates.Calculate(state, val, out var cycles, out var multiplier); view.speedText.text = (cycles * (float)val.ResultCounts[0] * multiplier).ToString("0.0") + Localization.Translate("每分钟"); view.incEffectValueText.text = "+" + ((flag2 ? Math.Max(0f, cycles * (float)val.TimeSpend / 3600f - 1f) : (multiplier - 1f)) * 100f).ToString("0.0") + " %"; ((Graphic)view.incEffectValueText).color = ((Graphic)view.incEffectTypeText).color; float num2 = ((state.Duration > 0) ? ((float)state.Progress / (float)state.Duration) : 0f); Image productProgress = view.productProgress0; float fillAmount = (view.productProgress1.fillAmount = num2); productProgress.fillAmount = fillAmount; float num4 = Mathf.Clamp01((float)(state.ExtraProgress + (state.BatchAccMode ? 0.0 : (state.BatchBonus * (double)num2)))); Image extraProductProgress = view.extraProductProgress0; fillAmount = (view.extraProductProgress1.fillAmount = num4); extraProductProgress.fillAmount = fillAmount; EnsureProductSlots(val.Results.Length); for (int j = 0; j < Math.Max(2, val.Results.Length); j++) { bool flag3 = j < val.Results.Length; UIButton val2 = (UIButton)(j switch { 1 => view.productButton1, 0 => view.productButton0, _ => extraProducts[j - 2].Button, }); Image val3 = (Image)(j switch { 1 => view.productIcon1, 0 => view.productIcon0, _ => extraProducts[j - 2].Icon, }); Text val4 = (Text)(j switch { 1 => view.productCountText1, 0 => view.productCountText0, _ => extraProducts[j - 2].Count, }); Image val5 = (Image)(j switch { 1 => view.productProgress1, 0 => view.productProgress0, _ => extraProducts[j - 2].Progress, }); object obj = j switch { 1 => view.extraProductProgress1, 0 => view.extraProductProgress0, _ => extraProducts[j - 2].ExtraProgress, }; ((Component)val2).gameObject.SetActive(flag3); ((Component)val3).gameObject.SetActive(flag3); ((Component)val4).gameObject.SetActive(flag3); ((Component)val5).gameObject.SetActive(flag3); ((Component)obj).gameObject.SetActive(flag3); val5.fillAmount = num2; ((Image)obj).fillAmount = num4; if (flag3) { int num6 = val.Results[j]; ItemBuffer itemBuffer = FactoryState.Buffer(state.Output, num6); ItemProto obj2 = ((ProtoSet<ItemProto>)(object)LDB.items).Select(num6); val3.sprite = ((obj2 != null) ? obj2.iconSprite : null); val4.text = itemBuffer.Count.ToString(); ((Selectable)val2.button).interactable = itemBuffer.Count > 0; val2.tips.itemId = num6; val2.tips.type = (ItemTipType)0; val2.tips.corner = 2; val2.tips.delay = 0.2f; } } int num7 = Math.Min(3, val.Results.Length) * 64; view.productGroup.sizeDelta = new Vector2((float)Math.Min(num7, 128), 64f); view.speedGroup.anchoredPosition = new Vector2((float)(num7 + 16), originalSpeedPosition.y - (float)num * 0.5f); view.servingGroup.anchoredPosition = new Vector2((float)(num7 + 96), originalServingPosition.y); int num8 = (int)(num2 * (float)view.speedArrows.Length) % view.speedArrows.Length; for (int k = 0; k < view.speedArrows.Length; k++) { ((Graphic)view.speedArrows[k]).color = ((state.Status == "生产中" && k == num8) ? view.marqueeOnColor : view.marqueeOffColor); } } Player mainPlayer = GameMain.mainPlayer; if (flag && mainPlayer != null && !((ManualBehaviour)view.playerInventory).inited) { view.playerInventory.colCount = mainPlayer.GetPackageColumnCount(); ((ManualBehaviour)view.playerInventory)._Init((object)mainPlayer.package); ((ManualBehaviour)view.playerInventory)._Open(); } if (!flag && ((ManualBehaviour)view.playerInventory).inited) { ((ManualBehaviour)view.playerInventory)._Free(); } ((Component)view.playerInventoryGroup).gameObject.SetActive(flag && mainPlayer != null); view.playerInventoryGroup.anchoredPosition = new Vector2(0f, (float)(-220 - num)); float num9 = ((mainPlayer != null) ? ((float)(80 + mainPlayer.GetPackageColumnCount() * 50)) : ((RectTransform)((Component)UIRoot.instance.uiGame.assemblerWindow).transform).sizeDelta.x); ResizeWindow(new Vector2(num9, (float)((((ManualBehaviour)view.playerInventory).active ? (view.playerInventory.rowCount * 50 + 220) : 270) + (flag ? 40 : 0) + num))); }); if (GameMain.mainPlayer != null) { if (((ManualBehaviour)view.servingBox).active) { ((ManualBehaviour)view.servingBox)._Update(); } if (((ManualBehaviour)view.playerInventory).active) { ((ManualBehaviour)view.playerInventory)._Update(); } } } internal static void Hide() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) FactoryRecipePicker.Close(); if ((Object)(object)view != (Object)null) { savedTopLeft = Vector2.op_Implicit(((Transform)windowDrag.screenRect).InverseTransformPoint(TopLeft((RectTransform)((Component)owner).transform))); FreeServing(); ((ManualBehaviour)view.servingBox)._Destroy(); ((ManualBehaviour)view.playerInventory)._Destroy(); ((Component)view).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)view).gameObject); view = null; windowDrag = null; extraProducts.Clear(); } if ((Object)(object)owner != (Object)null) { RectTransform val = (RectTransform)((Component)owner).transform; val.sizeDelta = originalSize; val.anchoredPosition = originalPosition; } foreach (KeyValuePair<GameObject, bool> item in hidden) { if ((Object)(object)item.Key != (Object)null) { item.Key.SetActive(item.Value); } } hidden.Clear(); owner = null; } } [HarmonyPatch(typeof(UISpraycoaterWindow), "_OnUpdate")] internal static class WindowUpdatePatch { private static bool Prefix(UISpraycoaterWindow __instance) { if (FactoryWindow.Matches(__instance)) { FactoryWindow.Refresh(__instance); return false; } FactoryWindow.Hide(); return true; } } [HarmonyPatch(typeof(UISpraycoaterWindow), "_OnClose")] internal static class WindowClosePatch { private static void Prefix() { FactoryWindow.Hide(); } } [BepInPlugin("com.komonad.dsp.sprayfactory", "Spray Factory", "0.1.1")] [BepInDependency("dsp.common-api.CommonAPI", "1.6.7")] [BepInDependency("me.xiaoye97.plugin.Dyson.LDBTool", "3.0.3")] [BepInDependency("crecheng.DSPModSave", "1.2.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [CommonAPISubmoduleDependency(new string[] { "ProtoRegistry", "LocalizationModule" })] public sealed class Plugin : BaseUnityPlugin, IModCanSave { public const string Guid = "com.komonad.dsp.sprayfactory"; internal static ManualLogSource Log; private Harmony harmony; private void Awake() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; LocalizationModule.RegisterTranslation("SprayFactory.Name", "Spray Factory", "喷涂工厂", ""); LocalizationModule.RegisterTranslation("SprayFactory.Description", "A belt-fed recipe factory. The upper belt supplies materials; products enter the continuous lower belt. Working power: 300 kW.", "传送带配方工厂。上层传送带供料,产物送入下层贯穿传送带。工作功耗:300 kW。", ""); LDBTool.PreAddDataAction = (Action)Delegate.Combine(LDBTool.PreAddDataAction, new Action(Prototypes.Register)); LDBTool.PostAddDataAction = (Action)Delegate.Combine(LDBTool.PostAddDataAction, new Action(Prototypes.Finish)); harmony = new Harmony("com.komonad.dsp.sprayfactory"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Spray Factory loaded."); } private void OnDestroy() { FactoryIcon.Clear(); RecipeColors.Clear(); FactoryEffects.Clear(); FactoryWindow.Hide(); LDBTool.PreAddDataAction = (Action)Delegate.Remove(LDBTool.PreAddDataAction, new Action(Prototypes.Register)); LDBTool.PostAddDataAction = (Action)Delegate.Remove(LDBTool.PostAddDataAction, new Action(Prototypes.Finish)); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } private void LateUpdate() { if (Prototypes.Ready) { PlanetFactory factory = GameMain.localPlanet?.factory; Camera main = GameCamera.main; FactoryEffects.Draw(factory, main); } } public void Export(BinaryWriter writer) { FactoryStore.Export(writer); } public void Import(BinaryReader reader) { FactoryStore.Import(reader); } public void IntoOthe