Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ForagersGarden v1.0.0
plugins/ForagersGarden/ForagersGarden.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ForagersGarden")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ForagersGarden")] [assembly: AssemblyTitle("ForagersGarden")] [assembly: AssemblyVersion("1.0.0.0")] namespace ForagersGarden; internal static class Icons { private static readonly Dictionary<string, Sprite> Cache = new Dictionary<string, Sprite>(); private static MethodInfo _loadImage; private static bool _tried; private static bool _loadResolved; public static Sprite Get(string fileName) { if (string.IsNullOrEmpty(fileName)) { return null; } EnsureLoaded(); if (!Cache.TryGetValue(fileName.ToLowerInvariant(), out var value)) { return null; } return value; } private static void EnsureLoaded() { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (_tried) { return; } _tried = true; Assembly assembly = typeof(Icons).Assembly; string[] manifestResourceNames = assembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (text == null || !text.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { continue; } string[] array = text.Split(new char[1] { '.' }); string key = ((array.Length >= 2) ? (array[^2] + ".png") : text).ToLowerInvariant(); try { using Stream stream = assembly.GetManifestResourceStream(text); if (stream != null) { byte[] bytes; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); bytes = memoryStream.ToArray(); } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (LoadPng(val, bytes)) { ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; MakeNearBlackTransparent(val); Cache[key] = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Icon " + text + ": " + ex.Message)); } } } private static bool LoadPng(Texture2D tex, byte[] bytes) { if (!_loadResolved) { _loadResolved = true; Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule"); if (type != null) { _loadImage = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(Texture2D), typeof(byte[]) }, null); } if (_loadImage == null) { _loadImage = typeof(Texture2D).GetMethod("LoadImage", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(byte[]) }, null); } } if (_loadImage == null) { return false; } try { if (_loadImage.IsStatic) { return (bool)_loadImage.Invoke(null, new object[2] { tex, bytes }); } return (bool)_loadImage.Invoke(tex, new object[1] { bytes }); } catch (Exception ex) { Plugin.Log.LogWarning((object)("PNG load failed: " + ex.Message)); return false; } } private static void MakeNearBlackTransparent(Texture2D tex) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_001e: 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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) Color32[] pixels = tex.GetPixels32(); bool flag = false; for (int i = 0; i < pixels.Length; i++) { Color32 val = pixels[i]; if (val.a > 0 && val.r <= 6 && val.g <= 6 && val.b <= 6) { val.a = 0; pixels[i] = val; flag = true; } } if (flag) { tex.SetPixels32(pixels); tex.Apply(false, false); } } } internal static class Loc { public static string T(string en, string de) { return en; } } internal static class MushroomCrops { private sealed class Kind { public string Id; public string Item; public string Pickable; public string SporesEn; public string SporesDe; public string IconFile; public Color Tint; public GameObject Spores; public GameObject MushroomCrop; public GameObject SporesCrop; public GameObject SaplingFromSpores; public GameObject SaplingForSpores; } private static readonly Kind[] Kinds = new Kind[3] { new Kind { Id = "sac_mushroom", Item = "Mushroom", Pickable = "Pickable_Mushroom", SporesEn = "Mushroom spores", SporesDe = "Pilzsporen", IconFile = "spores_mushroom.png", Tint = new Color(0.96f, 0.95f, 0.9f) }, new Kind { Id = "sac_mushroom_yellow", Item = "MushroomYellow", Pickable = "Pickable_Mushroom_yellow", SporesEn = "Yellow mushroom spores", SporesDe = "Gelbe Pilzsporen", IconFile = "spores_mushroom_yellow.png", Tint = new Color(1f, 0.78f, 0.3f) }, new Kind { Id = "sac_mushroom_blue", Item = "MushroomBlue", Pickable = "Pickable_Mushroom_blue", SporesEn = "Blue mushroom spores", SporesDe = "Blaue Pilzsporen", IconFile = "spores_mushroom_blue.png", Tint = new Color(0.62f, 0.7f, 1f) } }; private const float GrowTime = 3000f; private const float GrowTimeMax = 4000f; private static GameObject _hide; private static bool _done; private static bool _busy; private static readonly Dictionary<int, GameObject> ByHash = new Dictionary<int, GameObject>(); internal static GameObject PrefabForHash(int hash) { if (!ByHash.TryGetValue(hash, out var value)) { return null; } return value; } internal static void RegisterForScene(ZNetScene scene) { if ((Object)(object)scene == (Object)null || _busy) { return; } _busy = true; try { if (!_done) { Build(scene); } else { NameAll(scene); } AddItemsToDb(ObjectDB.instance); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Forager's Garden mushrooms skipped: " + ex.Message)); } finally { _busy = false; } } private static void Build(ZNetScene scene) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown GameObject val = scene.GetPrefab("TurnipSeeds") ?? scene.GetPrefab("CarrotSeeds"); GameObject prefab = scene.GetPrefab("sapling_carrot"); if ((Object)(object)val == (Object)null || (Object)(object)prefab == (Object)null) { Plugin.Log.LogDebug((object)"Forager's Garden mushrooms: carrot seeds / sapling not found yet."); return; } if ((Object)(object)_hide == (Object)null) { _hide = new GameObject("sac_mushroom_hide"); Object.DontDestroyOnLoad((Object)(object)_hide); _hide.SetActive(false); } for (int i = 0; i < Kinds.Length; i++) { BuildKind(scene, Kinds[i], val, prefab); } _done = true; NameAll(scene); Plugin.Log.LogDebug((object)"Forager's Garden mushrooms registered."); } private static void BuildKind(ZNetScene scene, Kind k, GameObject seeds, GameObject carrotSapling) { //IL_00fa: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = scene.GetPrefab(k.Item); GameObject prefab2 = scene.GetPrefab(k.Pickable); ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null); Pickable val2 = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<Pickable>() : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Plugin.Log.LogDebug((object)("Forager's Garden mushrooms: " + k.Item + " / " + k.Pickable + " not found, skipped.")); return; } k.Spores = Clone(seeds, "SacSpores_" + k.Id); SharedData shared = k.Spores.GetComponent<ItemDrop>().m_itemData.m_shared; shared.m_name = Loc.T(k.SporesEn, k.SporesDe); shared.m_description = Loc.T("Plant them on cultivated ground (Cultivator) and mushrooms grow.", "Auf bestelltem Boden pflanzen (Kultivator), daraus wachsen Pilze."); TintGroundModel(k.Spores, k.Tint); Sprite[] icons = val.m_itemData.m_shared.m_icons; Sprite val3 = Icons.Get(k.IconFile) ?? SporeIcon((icons != null && icons.Length != 0) ? icons[0] : null); if ((Object)(object)val3 != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { val3 }; } k.MushroomCrop = ClonePickable(prefab2, "Pickable_" + k.Id, prefab, 1); k.SporesCrop = ClonePickable(prefab2, "Pickable_" + k.Id + "_spores", k.Spores, 3); string name = val.m_itemData.m_shared.m_name; Sprite icon = (((Object)(object)val3 != (Object)null) ? val3 : ((icons != null && icons.Length != 0) ? icons[0] : null)); Sprite icon2 = ((icons != null && icons.Length != 0) ? icons[0] : null); k.SaplingFromSpores = CloneSapling(carrotSapling, "sapling_" + k.Id, k.MushroomCrop, val2, k.Spores, shared.m_name, icon); k.SaplingForSpores = CloneSapling(carrotSapling, "sapling_seed_" + k.Id, k.SporesCrop, val2, prefab, name, icon2); } private static GameObject Clone(GameObject template, string name) { bool activeSelf = template.activeSelf; template.SetActive(false); GameObject obj = Object.Instantiate<GameObject>(template, _hide.transform); template.SetActive(activeSelf); ((Object)obj).name = name; obj.SetActive(true); return obj; } private static void TintGroundModel(GameObject item, Color tint) { //IL_0049: 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) Renderer[] componentsInChildren = item.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (val is ParticleSystemRenderer) { continue; } Material[] materials = val.materials; foreach (Material val2 in materials) { if (!((Object)(object)val2 == (Object)null)) { if (val2.HasProperty("_Color")) { val2.SetColor("_Color", tint); } if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", Color.black); } } } val.materials = materials; } } private static GameObject ClonePickable(GameObject template, string name, GameObject item, int amount) { GameObject obj = Clone(template, name); Pickable component = obj.GetComponent<Pickable>(); component.m_itemPrefab = item; component.m_amount = amount; component.m_respawnTimeMinutes = 0f; component.m_hideWhenPicked = null; component.m_overrideName = ""; return obj; } private static GameObject CloneSapling(GameObject template, string name, GameObject grown, Pickable visualFrom, GameObject required, string requiredName, Sprite icon) { //IL_0092: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0145: 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_0154: Expected O, but got Unknown GameObject val = Clone(template, name); Plant component = val.GetComponent<Plant>(); Piece component2 = val.GetComponent<Piece>(); string name2 = (component.m_name = (name.StartsWith("sapling_seed") ? (requiredName + " " + Loc.T("(grows spores)", "(wächst zu Sporen)")) : (requiredName + " " + Loc.T("(grows mushrooms)", "(wachsen zu Pilzen)")))); component.m_grownPrefabs = (GameObject[])(object)new GameObject[1] { grown }; component.m_growTime = 3000f; component.m_growTimeMax = 4000f; component.m_needCultivatedGround = true; component.m_biome = (Biome)(component.m_biome | 2); SwapVisuals(component, ((Object)(object)visualFrom != (Object)null) ? visualFrom.m_hideWhenPicked : null); WildCrops.FitViews(component); component2.m_name = name2; component2.m_description = Loc.T("Grows on cultivated ground. Needs 1 " + requiredName + ".", "Wächst auf bestelltem Boden. Braucht 1 " + requiredName + "."); if ((Object)(object)icon != (Object)null) { component2.m_icon = icon; } ItemDrop val2 = (((Object)(object)required != (Object)null) ? required.GetComponent<ItemDrop>() : null); component2.m_resources = (Requirement[])(object)((!((Object)(object)val2 != (Object)null)) ? new Requirement[0] : new Requirement[1] { new Requirement { m_resItem = val2, m_amount = 1, m_recover = false } }); return val; } internal static void SwapVisuals(Plant plant, GameObject mushroom, float youngScale = 0.45f) { //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[4] { "m_healthy", "m_unhealthy", "m_healthyGrown", "m_unhealthyGrown" }; float[] array2 = new float[4] { youngScale, youngScale, 1f, 1f }; for (int i = 0; i < array.Length; i++) { FieldInfo fieldInfo = AccessTools.Field(typeof(Plant), array[i]); GameObject val = (GameObject)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { continue; } for (int num = val.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(num)).gameObject); } Renderer[] components = val.GetComponents<Renderer>(); for (int j = 0; j < components.Length; j++) { Object.DestroyImmediate((Object)(object)components[j]); } MeshFilter[] components2 = val.GetComponents<MeshFilter>(); for (int j = 0; j < components2.Length; j++) { Object.DestroyImmediate((Object)(object)components2[j]); } LODGroup[] components3 = val.GetComponents<LODGroup>(); for (int j = 0; j < components3.Length; j++) { Object.DestroyImmediate((Object)(object)components3[j]); } if (!((Object)(object)mushroom == (Object)null)) { GameObject val2 = Object.Instantiate<GameObject>(mushroom, val.transform, false); val2.transform.localScale = mushroom.transform.localScale * array2[i]; Collider[] componentsInChildren = val2.GetComponentsInChildren<Collider>(true); for (int j = 0; j < componentsInChildren.Length; j++) { Object.DestroyImmediate((Object)(object)componentsInChildren[j]); } val2.SetActive(true); } } } private static Sprite SporeIcon(Sprite source) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: 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_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || (int)SystemInfo.graphicsDeviceType == 4) { return null; } try { Texture2D texture = source.texture; Rect textureRect = source.textureRect; RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0); Graphics.Blit((Texture)(object)texture, temporary); RenderTexture active = RenderTexture.active; RenderTexture.active = temporary; Texture2D val = new Texture2D((int)((Rect)(ref textureRect)).width, (int)((Rect)(ref textureRect)).height, (TextureFormat)4, false); val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, ((Rect)(ref textureRect)).width, ((Rect)(ref textureRect)).height), 0, 0); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Color[] pixels = val.GetPixels(); Color val2 = default(Color); ((Color)(ref val2))..ctor(0.86f, 0.8f, 0.62f); for (int i = 0; i < pixels.Length; i++) { if (!(pixels[i].a < 0.05f)) { Color val3 = Color.Lerp(pixels[i], val2, 0.5f); val3.a = pixels[i].a; pixels[i] = val3; } } int width = ((Texture)val).width; int height = ((Texture)val).height; for (int j = 0; j < 7; j++) { int num = (int)((float)width * (0.58f + 0.07f * (float)(j % 4))); int num2 = (int)((float)height * (0.16f + 0.06f * (float)(j / 3))); for (int k = -1; k <= 1; k++) { for (int l = -1; l <= 1; l++) { int num3 = num + l; int num4 = num2 + k; if (num3 >= 0 && num4 >= 0 && num3 < width && num4 < height) { pixels[num4 * width + num3] = new Color(0.45f, 0.32f, 0.18f, 1f); } } } } val.SetPixels(pixels); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, (float)width, (float)height), new Vector2(0.5f, 0.5f), source.pixelsPerUnit); } catch (Exception ex) { Plugin.Log.LogDebug((object)("Spore icon: " + ex.Message)); return null; } } private static void NameAll(ZNetScene scene) { for (int i = 0; i < Kinds.Length; i++) { Kind kind = Kinds[i]; Name(scene, kind.Spores); Name(scene, kind.MushroomCrop); Name(scene, kind.SporesCrop); Name(scene, kind.SaplingFromSpores); Name(scene, kind.SaplingForSpores); } } private static void Name(ZNetScene scene, GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { ByHash[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; if (scene.m_prefabs != null && !scene.m_prefabs.Contains(prefab)) { scene.m_prefabs.Add(prefab); } FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs"); Dictionary<int, GameObject> dictionary = ((fieldInfo != null) ? (fieldInfo.GetValue(scene) as Dictionary<int, GameObject>) : null); if (dictionary != null) { dictionary[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; } } } internal static void AddItemsToDb(ObjectDB db) { if (!_done || (Object)(object)db == (Object)null || db.m_items == null || (Object)(object)db.GetItemPrefab("Hammer") == (Object)null) { return; } bool flag = false; for (int i = 0; i < Kinds.Length; i++) { GameObject spores = Kinds[i].Spores; if ((Object)(object)spores != (Object)null && !db.m_items.Contains(spores)) { db.m_items.Add(spores); flag = true; } } if (flag) { MethodInfo methodInfo = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(db, null); } } } internal static bool TryRegisterCultivator() { if (!_done || (Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Cultivator"); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); PieceTable val2 = (((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null) ? val.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val2 == (Object)null || val2.m_pieces == null) { return false; } bool enabled = WildCrops.Enabled; bool flag = false; for (int i = 0; i < Kinds.Length; i++) { flag |= Set(val2, Kinds[i].SaplingFromSpores, enabled); flag |= Set(val2, Kinds[i].SaplingForSpores, enabled); } return flag; } private static bool Set(PieceTable table, GameObject sapling, bool on) { if ((Object)(object)sapling == (Object)null) { return false; } if (!on) { return table.m_pieces.Remove(sapling); } if (table.m_pieces.Contains(sapling)) { return false; } table.m_pieces.Add(sapling); return true; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneMushroomPatch { private static void Postfix(ZNetScene __instance) { MushroomCrops.RegisterForScene(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDbMushroomPatch { private static void Postfix(ObjectDB __instance) { MushroomCrops.AddItemsToDb(__instance); } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerMushroomTablePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && ((Character)__instance).IsOwner()) { if ((Object)(object)ZNetScene.instance != (Object)null) { MushroomCrops.RegisterForScene(ZNetScene.instance); } MushroomCrops.AddItemsToDb(ObjectDB.instance); if (MushroomCrops.TryRegisterCultivator()) { QueenHives.RefreshKnown(__instance); } } } } [BepInPlugin("com.morda.foragersgarden", "Forager's Garden", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.morda.foragersgarden"; public const string ModName = "Forager's Garden"; public const string ModVersion = "1.0.0"; public const string ModAuthor = "Morda"; private const string StoreAndCraftGuid = "com.morda.storeandcraft"; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } internal static ConfigEntry<bool> Beehives { get; private set; } internal static ConfigEntry<bool> CultivatorPlants { get; private set; } private void Awake() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Version version = OldStoreAndCraft(); if (version != null) { ((BaseUnityPlugin)this).Logger.LogError((object)("StoreAndCraft " + version?.ToString() + " still contains the beehives and plants of Forager's Garden. Update StoreAndCraft to 1.6.0 or newer. Forager's Garden stays off.")); return; } Beehives = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Beehives", true, "Ice, Royal Jelly and Crystal beehive in the hammer and their queen bee recipes at the workbench. Off = not offered any more (hives already built keep working). The vanilla beehive is untouched."); CultivatorPlants = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "CultivatorPlants", true, "Berry bushes, wild herbs, mushrooms and spores in the Cultivator. Off = not offered any more (plants already planted keep growing). Vanilla crops are untouched."); ((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged; _harmony = new Harmony("com.morda.foragersgarden"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Forager's Garden v1.0.0 by Morda loaded."); } private static Version OldStoreAndCraft() { if (!Chainloader.PluginInfos.TryGetValue("com.morda.storeandcraft", out var value) || value == null || value.Metadata == null) { return null; } Version version = value.Metadata.Version; if (!(version != null) || !(version < new Version(1, 6, 0))) { return null; } return version; } private static void OnSettingChanged(object sender, SettingChangedEventArgs e) { if (e != null) { if ((object)e.ChangedSetting == Beehives) { QueenHives.ApplySetting(); } if ((object)e.ChangedSetting == CultivatorPlants && (WildCrops.TryRegisterCultivator() | MushroomCrops.TryRegisterCultivator()) && (Object)(object)Player.m_localPlayer != (Object)null) { QueenHives.RefreshKnown(Player.m_localPlayer); } } } private void OnDestroy() { ((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(ZNetScene), "GetPrefab", new Type[] { typeof(int) })] internal static class ZNetSceneGetPrefabPatch { private static void Postfix(int hash, ref GameObject __result) { if (!((Object)(object)__result != (Object)null)) { GameObject val = MushroomCrops.PrefabForHash(hash); if ((Object)(object)val == (Object)null) { val = WildCrops.PrefabForHash(hash); } if ((Object)(object)val == (Object)null) { val = QueenHives.PrefabForHash(hash); } if ((Object)(object)val != (Object)null) { __result = val; } } } } internal static class QueenHives { private sealed class Kind { public string QueenId; public string HiveId; public string Output; public string QueenEn; public string QueenDe; public string QueenDescEn; public string QueenDescDe; public string HiveEn; public string HiveDe; public string HiveDescEn; public string HiveDescDe; public Color Tint; public GameObject Queen; public GameObject Hive; public ItemDrop OutputDrop; public ItemDrop QueenBeeDrop; public Recipe Recipe; } private const int MaterialAmount = 10; private const int MaxTexture = 1024; private const float TintMix = 0.9f; private static readonly Kind[] Kinds = new Kind[3] { new Kind { QueenId = "sac_queen_ice", HiveId = "sac_hive_ice", Output = "Ice", QueenEn = "Ice Queen Bee", QueenDe = "Eis-Bienenkönigin", QueenDescEn = "A frozen queen bee, made from a Queen Bee and Ice at the workbench. An Ice Beehive needs her instead of a normal queen.", QueenDescDe = "Eine gefrorene Bienenkönigin, an der Werkbank aus einer Bienenkönigin und Eis hergestellt. Ein Eis-Bienenstock braucht sie statt einer normalen Königin.", HiveEn = "Ice Beehive", HiveDe = "Eis-Bienenstock", HiveDescEn = "A white beehive that makes ice instead of honey. Needs an Ice Queen Bee.", HiveDescDe = "Ein weißer Bienenstock, der Eis statt Honig herstellt. Braucht eine Eis-Bienenkönigin.", Tint = new Color(0.82f, 0.93f, 1f) }, new Kind { QueenId = "sac_queen_jelly", HiveId = "sac_hive_jelly", Output = "RoyalJelly", QueenEn = "Royal Jelly Queen Bee", QueenDe = "Gelée-Royale-Bienenkönigin", QueenDescEn = "A golden queen bee, made from a Queen Bee and Royal Jelly at the workbench. A Royal Jelly Beehive needs her instead of a normal queen.", QueenDescDe = "Eine goldene Bienenkönigin, an der Werkbank aus einer Bienenkönigin und Gelée Royale hergestellt. Ein Gelée-Royale-Bienenstock braucht sie statt einer normalen Königin.", HiveEn = "Royal Jelly Beehive", HiveDe = "Gelée-Royale-Bienenstock", HiveDescEn = "A yellow beehive that makes royal jelly instead of honey. Needs a Royal Jelly Queen Bee.", HiveDescDe = "Ein gelber Bienenstock, der Gelée Royale statt Honig herstellt. Braucht eine Gelée-Royale-Bienenkönigin.", Tint = new Color(1f, 0.84f, 0.28f) }, new Kind { QueenId = "sac_queen_crystal", HiveId = "sac_hive_crystal", Output = "Crystal", QueenEn = "Crystal Queen Bee", QueenDe = "Kristall-Bienenkönigin", QueenDescEn = "A violet queen bee, made from a Queen Bee and Crystal at the workbench. A Crystal Beehive needs her instead of a normal queen.", QueenDescDe = "Eine violette Bienenkönigin, an der Werkbank aus einer Bienenkönigin und Kristall hergestellt. Ein Kristall-Bienenstock braucht sie statt einer normalen Königin.", HiveEn = "Crystal Beehive", HiveDe = "Kristall-Bienenstock", HiveDescEn = "A violet beehive that makes crystal instead of honey. Needs a Crystal Queen Bee.", HiveDescDe = "Ein violetter Bienenstock, der Kristall statt Honig herstellt. Braucht eine Kristall-Bienenkönigin.", Tint = new Color(0.72f, 0.62f, 1f) } }; private static readonly MethodInfo UpdateRegisters = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null); private static readonly MethodInfo UpdateKnownRecipes = AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null); private static readonly MethodInfo UpdateAvailablePieces = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null); private static GameObject _hide; private static CraftingStation _workbench; private static bool _done; private static bool _busy; private static readonly Dictionary<int, GameObject> ByHash = new Dictionary<int, GameObject>(); private static readonly Dictionary<string, Texture2D> TextureCache = new Dictionary<string, Texture2D>(); private static bool NoGraphics => (int)SystemInfo.graphicsDeviceType == 4; internal static bool Enabled { get { if (Plugin.Beehives != null) { return Plugin.Beehives.Value; } return true; } } internal static GameObject PrefabForHash(int hash) { if (!ByHash.TryGetValue(hash, out var value)) { return null; } return value; } internal static void RegisterForScene(ZNetScene scene) { if ((Object)(object)scene == (Object)null || _busy) { return; } _busy = true; try { if (!_done) { Build(scene); } else { NameAll(scene); } AddToDb(ObjectDB.instance); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Forager's Garden queen hives skipped: " + ex.Message)); } finally { _busy = false; } } private static GameObject Find(ZNetScene scene, string name) { GameObject val = scene.GetPrefab(name); if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab(name); } return val; } private static void Build(ZNetScene scene) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown GameObject val = Find(scene, "QueenBee"); GameObject prefab = scene.GetPrefab("piece_beehive"); if ((Object)(object)val == (Object)null || (Object)(object)prefab == (Object)null) { Plugin.Log.LogDebug((object)"Forager's Garden queen hives: QueenBee / piece_beehive not found yet."); return; } if ((Object)(object)_hide == (Object)null) { _hide = new GameObject("sac_queenhive_hide"); Object.DontDestroyOnLoad((Object)(object)_hide); _hide.SetActive(false); } GameObject prefab2 = scene.GetPrefab("piece_workbench"); _workbench = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<CraftingStation>() : null); if ((Object)(object)_workbench == (Object)null) { Plugin.Log.LogWarning((object)"Forager's Garden queen hives: workbench not found, the queens cannot be crafted."); } for (int i = 0; i < Kinds.Length; i++) { try { BuildKind(scene, Kinds[i], val, prefab); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Forager's Garden queen hive " + Kinds[i].HiveId + " skipped: " + ex.Message)); } } _done = true; NameAll(scene); Plugin.Log.LogDebug((object)"Forager's Garden queen hives registered."); } private static void BuildKind(ZNetScene scene, Kind k, GameObject queenBee, GameObject beehive) { //IL_00dc: 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_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) GameObject val = Find(scene, k.Output); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); ItemDrop component = queenBee.GetComponent<ItemDrop>(); if ((Object)(object)val2 == (Object)null || (Object)(object)component == (Object)null) { Plugin.Log.LogDebug((object)("Forager's Garden queen hives: " + k.Output + " / QueenBee item not found, skipped.")); return; } k.OutputDrop = val2; k.QueenBeeDrop = component; k.Queen = Clone(queenBee, k.QueenId); ItemDrop component2 = k.Queen.GetComponent<ItemDrop>(); SharedData shared = component2.m_itemData.m_shared; shared.m_name = Loc.T(k.QueenEn, k.QueenDe); shared.m_description = Loc.T(k.QueenDescEn, k.QueenDescDe); Sprite[] icons = shared.m_icons; Sprite val3 = ((icons != null && icons.Length != 0) ? TintSprite(icons[0], k.Tint) : null); if ((Object)(object)val3 != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { val3 }; } Recolor(k.Queen, k.Tint, null); k.Hive = Clone(beehive, k.HiveId); Beehive component3 = k.Hive.GetComponent<Beehive>(); Piece component4 = k.Hive.GetComponent<Piece>(); if ((Object)(object)component3 == (Object)null || (Object)(object)component4 == (Object)null) { Plugin.Log.LogWarning((object)"Forager's Garden queen hives: piece_beehive lost Beehive/Piece."); Object.Destroy((Object)(object)k.Hive); k.Hive = null; return; } string name = Loc.T(k.HiveEn, k.HiveDe); component3.m_honeyItem = val2; component3.m_name = name; component4.m_name = name; component4.m_description = Loc.T(k.HiveDescEn, k.HiveDescDe); component4.m_resources = HiveResources(component4.m_resources, component2); Sprite val4 = (((Object)(object)component4.m_icon != (Object)null) ? TintSprite(component4.m_icon, k.Tint) : null); if ((Object)(object)val4 != (Object)null) { component4.m_icon = val4; } Recolor(k.Hive, k.Tint, ((Object)(object)component3.m_beeEffect != (Object)null) ? component3.m_beeEffect.transform : null); RecolorBees(component3.m_beeEffect, k.Tint); } private static GameObject Clone(GameObject template, string name) { bool activeSelf = template.activeSelf; template.SetActive(false); GameObject obj = Object.Instantiate<GameObject>(template, _hide.transform); template.SetActive(activeSelf); ((Object)obj).name = name; obj.SetActive(true); return obj; } private static Requirement[] HiveResources(Requirement[] source, ItemDrop queen) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00bf: 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) //IL_00d2: Expected O, but got Unknown //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_002a: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown List<Requirement> list = new List<Requirement>(); bool flag = false; if (source != null) { foreach (Requirement val in source) { if (val != null) { Requirement val2 = new Requirement { m_resItem = val.m_resItem, m_amount = val.m_amount, m_amountPerLevel = val.m_amountPerLevel, m_recover = val.m_recover }; if ((Object)(object)val.m_resItem != (Object)null && Utils.GetPrefabName(((Component)val.m_resItem).gameObject) == "QueenBee") { val2.m_resItem = queen; flag = true; } list.Add(val2); } } } if (!flag) { Plugin.Log.LogDebug((object)"Forager's Garden queen hives: piece_beehive has no Queen Bee requirement, queen added."); list.Add(new Requirement { m_resItem = queen, m_amount = 1, m_amountPerLevel = 0, m_recover = false }); } return list.ToArray(); } private static void Recolor(GameObject root, Color tint, Transform skip) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (NoGraphics) { return; } Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!(val is ParticleSystemRenderer) && (!((Object)(object)skip != (Object)null) || !((Component)val).transform.IsChildOf(skip))) { Material[] materials = val.materials; for (int j = 0; j < materials.Length; j++) { TintMaterial(materials[j], tint); } val.materials = materials; } } } private static bool TintMaterial(Material m, Color tint) { //IL_002f: 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) if ((Object)(object)m == (Object)null) { return false; } Texture val = (m.HasProperty("_MainTex") ? m.mainTexture : null); Texture2D val2 = (((Object)(object)val != (Object)null) ? TintedTexture(val, tint) : null); if ((Object)(object)val2 != (Object)null) { m.mainTexture = (Texture)(object)val2; return true; } if (m.HasProperty("_Color")) { m.SetColor("_Color", tint); } return false; } private static void RecolorBees(GameObject effect, Color tint) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0051: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)effect == (Object)null || NoGraphics) { return; } Recolor(effect, tint, null); ParticleSystem[] componentsInChildren = effect.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val in componentsInChildren) { bool flag = false; ParticleSystemRenderer component = ((Component)val).GetComponent<ParticleSystemRenderer>(); if ((Object)(object)component != (Object)null) { Material[] materials = ((Renderer)component).materials; for (int j = 0; j < materials.Length; j++) { flag |= TintMaterial(materials[j], tint); } ((Renderer)component).materials = materials; } MainModule main = val.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(flag ? Color.white : tint); } } private static void TintPixels(Color32[] px, Color tint) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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) //IL_0087: 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_00eb: Unknown result type (might be due to invalid IL or missing references) float num = tint.r * 255f; float num2 = tint.g * 255f; float num3 = tint.b * 255f; for (int i = 0; i < px.Length; i++) { Color32 val = px[i]; float num4 = (0.299f * (float)(int)val.r + 0.587f * (float)(int)val.g + 0.114f * (float)(int)val.b) / 255f; float num5 = Mathf.Clamp01(0.55f + 0.6f * num4); px[i].r = (byte)Mathf.Clamp(Mathf.Lerp((float)(int)val.r, num * num5, 0.9f), 0f, 255f); px[i].g = (byte)Mathf.Clamp(Mathf.Lerp((float)(int)val.g, num2 * num5, 0.9f), 0f, 255f); px[i].b = (byte)Mathf.Clamp(Mathf.Lerp((float)(int)val.b, num3 * num5, 0.9f), 0f, 255f); } } private static Texture2D TintedTexture(Texture src, Color tint) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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) string key = ((Object)src).GetInstanceID() + "|" + ColorUtility.ToHtmlStringRGB(tint); if (TextureCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } try { float num = Mathf.Min(1f, 1024f / (float)Mathf.Max(src.width, src.height)); int num2 = Mathf.Max(4, (int)((float)src.width * num)); int num3 = Mathf.Max(4, (int)((float)src.height * num)); RenderTexture temporary = RenderTexture.GetTemporary(num2, num3, 0); Graphics.Blit(src, temporary); RenderTexture active = RenderTexture.active; RenderTexture.active = temporary; Texture2D val = new Texture2D(num2, num3, (TextureFormat)4, true); val.ReadPixels(new Rect(0f, 0f, (float)num2, (float)num3), 0, 0); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Color32[] pixels = val.GetPixels32(); TintPixels(pixels, tint); val.SetPixels32(pixels); ((Texture)val).wrapMode = src.wrapMode; ((Texture)val).filterMode = (FilterMode)1; val.Apply(true, true); TextureCache[key] = val; return val; } catch (Exception ex) { Plugin.Log.LogDebug((object)("Queen hive texture: " + ex.Message)); return null; } } private static Sprite TintSprite(Sprite source, Color tint) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00d8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || NoGraphics) { return null; } try { Texture2D texture = source.texture; Rect textureRect = source.textureRect; RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0); Graphics.Blit((Texture)(object)texture, temporary); RenderTexture active = RenderTexture.active; RenderTexture.active = temporary; Texture2D val = new Texture2D((int)((Rect)(ref textureRect)).width, (int)((Rect)(ref textureRect)).height, (TextureFormat)4, false); val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, ((Rect)(ref textureRect)).width, ((Rect)(ref textureRect)).height), 0, 0); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Color32[] pixels = val.GetPixels32(); TintPixels(pixels, tint); val.SetPixels32(pixels); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), source.pixelsPerUnit); } catch (Exception ex) { Plugin.Log.LogDebug((object)("Queen hive icon: " + ex.Message)); return null; } } private static void NameAll(ZNetScene scene) { for (int i = 0; i < Kinds.Length; i++) { Name(scene, Kinds[i].Queen); Name(scene, Kinds[i].Hive); } } private static void Name(ZNetScene scene, GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { ByHash[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; if (scene.m_prefabs != null && !scene.m_prefabs.Contains(prefab)) { scene.m_prefabs.Add(prefab); } FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs"); Dictionary<int, GameObject> dictionary = ((fieldInfo != null) ? (fieldInfo.GetValue(scene) as Dictionary<int, GameObject>) : null); if (dictionary != null) { dictionary[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; } } } private static Recipe MakeRecipe(Kind k) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00af: 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_00be: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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_00e8: Expected O, but got Unknown if ((Object)(object)_workbench == (Object)null || (Object)(object)k.Queen == (Object)null || (Object)(object)k.QueenBeeDrop == (Object)null || (Object)(object)k.OutputDrop == (Object)null) { return null; } Recipe val = ScriptableObject.CreateInstance<Recipe>(); ((Object)val).name = "Recipe_" + k.QueenId; ((Object)val).hideFlags = (HideFlags)61; val.m_item = k.Queen.GetComponent<ItemDrop>(); val.m_amount = 1; val.m_enabled = true; val.m_craftingStation = _workbench; val.m_minStationLevel = 1; val.m_resources = (Requirement[])(object)new Requirement[2] { new Requirement { m_resItem = k.QueenBeeDrop, m_amount = 1, m_amountPerLevel = 0, m_recover = false }, new Requirement { m_resItem = k.OutputDrop, m_amount = 10, m_amountPerLevel = 0, m_recover = false } }; return val; } internal static void AddToDb(ObjectDB db) { if (!_done || (Object)(object)db == (Object)null || db.m_items == null || db.m_recipes == null || (Object)(object)db.GetItemPrefab("Hammer") == (Object)null) { return; } bool flag = false; for (int i = 0; i < Kinds.Length; i++) { GameObject queen = Kinds[i].Queen; if ((Object)(object)queen != (Object)null && !db.m_items.Contains(queen)) { db.m_items.Add(queen); flag = true; } } if (flag && UpdateRegisters != null) { UpdateRegisters.Invoke(db, null); } bool enabled = Enabled; for (int j = 0; j < Kinds.Length; j++) { Kind kind = Kinds[j]; if ((Object)(object)kind.Queen == (Object)null) { continue; } if ((Object)(object)kind.Recipe == (Object)null) { kind.Recipe = MakeRecipe(kind); } if (!((Object)(object)kind.Recipe == (Object)null)) { if (enabled && !db.m_recipes.Contains(kind.Recipe)) { db.m_recipes.Add(kind.Recipe); } else if (!enabled) { db.m_recipes.Remove(kind.Recipe); } } } } internal static void ApplySetting() { if (_done && !((Object)(object)ObjectDB.instance == (Object)null)) { AddToDb(ObjectDB.instance); TryRegisterHammer(); if ((Object)(object)Player.m_localPlayer != (Object)null) { RefreshKnown(Player.m_localPlayer); } } } internal static bool TryRegisterHammer() { if (!_done || (Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer"); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); PieceTable val2 = (((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null) ? val.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val2 == (Object)null || val2.m_pieces == null) { return false; } bool enabled = Enabled; bool result = false; for (int i = 0; i < Kinds.Length; i++) { GameObject hive = Kinds[i].Hive; if (!((Object)(object)hive == (Object)null)) { if (enabled && !val2.m_pieces.Contains(hive)) { val2.m_pieces.Add(hive); result = true; } else if (!enabled && val2.m_pieces.Remove(hive)) { result = true; } } } return result; } internal static void RefreshKnown(Player player) { try { if (UpdateKnownRecipes != null) { UpdateKnownRecipes.Invoke(player, null); } if (UpdateAvailablePieces != null) { UpdateAvailablePieces.Invoke(player, null); } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Queen hives refresh: " + ex.Message)); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneQueenHivePatch { private static void Postfix(ZNetScene __instance) { QueenHives.RegisterForScene(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDbQueenHivePatch { private static void Postfix(ObjectDB __instance) { QueenHives.AddToDb(__instance); } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerQueenHivePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && ((Character)__instance).IsOwner()) { if ((Object)(object)ZNetScene.instance != (Object)null) { QueenHives.RegisterForScene(ZNetScene.instance); } QueenHives.AddToDb(ObjectDB.instance); if (QueenHives.TryRegisterHammer()) { QueenHives.RefreshKnown(__instance); } } } } internal static class WildCrops { private sealed class Kind { public string Id; public string Wild; public bool Bush; public float Radius; public int Cost = 5; public int Yield; public GameObject Crop; public GameObject Sapling; } private const float GrowTime = 12f; private const float GrowTimeMax = 20f; private static readonly Kind[] Kinds = new Kind[7] { new Kind { Id = "raspberry", Wild = "RaspberryBush", Bush = true, Radius = 0.8f }, new Kind { Id = "blueberry", Wild = "BlueberryBush", Bush = true, Radius = 0.8f }, new Kind { Id = "cloudberry", Wild = "CloudberryBush", Bush = true, Radius = 0.8f }, new Kind { Id = "dandelion", Wild = "Pickable_Dandelion", Radius = 0.4f, Cost = 1, Yield = 3 }, new Kind { Id = "thistle", Wild = "Pickable_Thistle", Radius = 0.4f, Cost = 1, Yield = 3 }, new Kind { Id = "fiddlehead", Wild = "Pickable_Fiddlehead", Radius = 0.4f, Cost = 1, Yield = 3 }, new Kind { Id = "smokepuff", Wild = "Pickable_SmokePuff", Radius = 0.4f, Cost = 1, Yield = 3 } }; internal static readonly Dictionary<string, string> GhostReveal = new Dictionary<string, string>(); private static GameObject _hide; private static bool _done; private static bool _busy; private static readonly Dictionary<int, GameObject> ByHash = new Dictionary<int, GameObject>(); private static readonly string[] StageFields = new string[4] { "m_healthy", "m_unhealthy", "m_healthyGrown", "m_unhealthyGrown" }; internal static bool Enabled { get { if (Plugin.CultivatorPlants != null) { return Plugin.CultivatorPlants.Value; } return true; } } internal static GameObject PrefabForHash(int hash) { if (!ByHash.TryGetValue(hash, out var value)) { return null; } return value; } internal static void RegisterForScene(ZNetScene scene) { if ((Object)(object)scene == (Object)null || _busy) { return; } _busy = true; try { if (!_done) { Build(scene); } else { NameAll(scene); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Forager's Garden wild crops skipped: " + ex.Message)); } finally { _busy = false; } } private static void Build(ZNetScene scene) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown GameObject prefab = scene.GetPrefab("sapling_carrot"); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogDebug((object)"Forager's Garden wild crops: carrot sapling not found yet."); return; } if ((Object)(object)_hide == (Object)null) { _hide = new GameObject("sac_wildcrop_hide"); Object.DontDestroyOnLoad((Object)(object)_hide); _hide.SetActive(false); } for (int i = 0; i < Kinds.Length; i++) { try { BuildKind(scene, Kinds[i], prefab); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Forager's Garden wild crop " + Kinds[i].Id + " skipped: " + ex.Message)); } } _done = true; NameAll(scene); Plugin.Log.LogDebug((object)"Forager's Garden wild crops registered."); } private static void BuildKind(ZNetScene scene, Kind k, GameObject carrotSapling) { GameObject prefab = scene.GetPrefab(k.Wild); Pickable val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<Pickable>(true) : null); ItemDrop val2 = (((Object)(object)val != (Object)null && (Object)(object)val.m_itemPrefab != (Object)null) ? val.m_itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null || (Object)(object)prefab.GetComponent<ZNetView>() == (Object)null) { Plugin.Log.LogDebug((object)("Forager's Garden wild crops: " + k.Wild + " has no pickable / item, skipped.")); return; } k.Crop = Clone(prefab, "sac_wild_" + k.Id); k.Crop.GetComponent<ZNetView>().m_persistent = true; Pickable componentInChildren = k.Crop.GetComponentInChildren<Pickable>(true); if ((Object)(object)componentInChildren != (Object)null && k.Yield > 0) { componentInChildren.m_amount = k.Yield; } if ((Object)(object)componentInChildren != (Object)null && componentInChildren.m_respawnTimeMinutes > 0f && ModelStays(k.Crop, componentInChildren)) { componentInChildren.m_defaultPicked = true; componentInChildren.m_respawnTimeInitMin = 0f; componentInChildren.m_respawnTimeInitMax = 0f; } string text = (k.Bush ? "bush" : "wild"); k.Sapling = CloneSapling(carrotSapling, "sapling_sac_" + text + "_" + k.Id, k, val2, prefab); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.m_respawnTimeMinutes > 0f && ModelStays(k.Crop, componentInChildren)) { GhostReveal[((Object)k.Sapling).name] = ((Object)componentInChildren.m_hideWhenPicked).name; } } private static bool ModelStays(GameObject root, Pickable pick) { GameObject val = (((Object)(object)pick != (Object)null) ? pick.m_hideWhenPicked : null); if ((Object)(object)val == (Object)null) { return false; } Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { if (!(val2 is ParticleSystemRenderer) && val2.enabled && ((Component)val2).gameObject.activeSelf && !((Component)val2).transform.IsChildOf(val.transform)) { return true; } } return false; } private static GameObject Clone(GameObject template, string name) { bool activeSelf = template.activeSelf; template.SetActive(false); GameObject obj = Object.Instantiate<GameObject>(template, _hide.transform); template.SetActive(activeSelf); ((Object)obj).name = name; obj.SetActive(true); return obj; } private static GameObject CloneSapling(GameObject template, string name, Kind k, ItemDrop item, GameObject wild) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown GameObject val = Clone(template, name); Plant component = val.GetComponent<Plant>(); Piece component2 = val.GetComponent<Piece>(); string name2 = item.m_itemData.m_shared.m_name; string name3 = (component.m_name = name2 + " " + (k.Bush ? Loc.T("(bush)", "(Strauch)") : Loc.T("(plant)", "(Pflanze)"))); component.m_grownPrefabs = (GameObject[])(object)new GameObject[1] { k.Crop }; component.m_growTime = 12f; component.m_growTimeMax = 20f; component.m_growRadius = k.Radius; component.m_needCultivatedGround = true; component.m_biome = (Biome)895; component.m_minScale = 1f; component.m_maxScale = 1f; GameObject val2 = StaticView(wild); MushroomCrops.SwapVisuals(component, val2, 1f); FitViews(component); Object.Destroy((Object)(object)val2); component2.m_name = name3; component2.m_description = Loc.T("Grows on cultivated ground and keeps growing " + name2 + ". Needs " + k.Cost + " " + name2 + ".", "Wächst auf bestelltem Boden und trägt immer wieder " + name2 + ". Braucht " + k.Cost + " " + name2 + "."); Sprite[] icons = item.m_itemData.m_shared.m_icons; if (icons != null && icons.Length != 0 && (Object)(object)icons[0] != (Object)null) { component2.m_icon = icons[0]; } component2.m_resources = (Requirement[])(object)new Requirement[1] { new Requirement { m_resItem = item, m_amount = k.Cost, m_recover = false } }; return val; } internal static void FitViews(Plant plant) { //IL_0072: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = default(Vector3); for (int i = 0; i < StageFields.Length; i++) { FieldInfo fieldInfo = AccessTools.Field(typeof(Plant), StageFields[i]); GameObject val = (GameObject)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null); if (!((Object)(object)val == (Object)null) && val.transform.childCount != 0) { Transform child = val.transform.GetChild(val.transform.childCount - 1); Vector3 lossyScale = val.transform.lossyScale; ((Vector3)(ref val2))..ctor(Inverse(lossyScale.x), Inverse(lossyScale.y), Inverse(lossyScale.z)); Quaternion val3 = Quaternion.Inverse(val.transform.localRotation); child.localScale = Vector3.Scale(child.localScale, val2); child.localPosition = Vector3.Scale(val3 * child.localPosition, val2); child.localRotation = val3 * child.localRotation; } } } private static float Inverse(float v) { if (!(Mathf.Abs(v) > 0.0001f)) { return 1f; } return 1f / v; } private static GameObject StaticView(GameObject wild) { //IL_0012: 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) GameObject val = Clone(wild, "sac_wild_view"); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; Pickable componentInChildren = val.GetComponentInChildren<Pickable>(true); if ((Object)(object)componentInChildren != (Object)null && componentInChildren.m_respawnTimeMinutes > 0f && ModelStays(val, componentInChildren)) { componentInChildren.m_hideWhenPicked.SetActive(false); } MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && !(val2 is ZNetView)) { Object.DestroyImmediate((Object)(object)val2); } } ZNetView component = val.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } Collider[] componentsInChildren2 = val.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Rigidbody[] componentsInChildren3 = val.GetComponentsInChildren<Rigidbody>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } return val; } private static void NameAll(ZNetScene scene) { for (int i = 0; i < Kinds.Length; i++) { Name(scene, Kinds[i].Crop); Name(scene, Kinds[i].Sapling); } } private static void Name(ZNetScene scene, GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { ByHash[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; if (scene.m_prefabs != null && !scene.m_prefabs.Contains(prefab)) { scene.m_prefabs.Add(prefab); } FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs"); Dictionary<int, GameObject> dictionary = ((fieldInfo != null) ? (fieldInfo.GetValue(scene) as Dictionary<int, GameObject>) : null); if (dictionary != null) { dictionary[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; } } } internal static bool TryRegisterCultivator() { if (!_done || (Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Cultivator"); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); PieceTable val2 = (((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null) ? val.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val2 == (Object)null || val2.m_pieces == null) { return false; } bool enabled = Enabled; bool result = false; for (int i = 0; i < Kinds.Length; i++) { GameObject sapling = Kinds[i].Sapling; if (!((Object)(object)sapling == (Object)null)) { if (enabled && !val2.m_pieces.Contains(sapling)) { val2.m_pieces.Add(sapling); result = true; } else if (!enabled && val2.m_pieces.Remove(sapling)) { result = true; } } } return result; } } [HarmonyPatch(typeof(Player), "SetupPlacementGhost")] internal static class SaplingGhostGrownPatch { private static readonly FieldInfo GhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private static void Postfix(Player __instance) { GameObject val = (GameObject)((GhostField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null || (!((Object)val).name.StartsWith("sapling_sac_") && !((Object)val).name.StartsWith("sapling_seed_sac_"))) { return; } Transform val2 = val.transform.Find("healthy"); Transform val3 = val.transform.Find("healthy_grown"); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { return; } ((Component)val2).gameObject.SetActive(false); ((Component)val3).gameObject.SetActive(true); WildCrops.GhostReveal.TryGetValue(((Object)val).name, out var value); Transform[] componentsInChildren = ((Component)val3).GetComponentsInChildren<Transform>(true); foreach (Transform val4 in componentsInChildren) { ((Component)val4).gameObject.layer = val.layer; if (value != null && ((Object)val4).name == value) { ((Component)val4).gameObject.SetActive(true); } } Renderer[] componentsInChildren2 = ((Component)val3).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].shadowCastingMode = (ShadowCastingMode)0; } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneWildCropsPatch { private static void Postfix(ZNetScene __instance) { WildCrops.RegisterForScene(__instance); } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerWildCropsTablePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && ((Character)__instance).IsOwner()) { if ((Object)(object)ZNetScene.instance != (Object)null) { WildCrops.RegisterForScene(ZNetScene.instance); } if (WildCrops.TryRegisterCultivator()) { QueenHives.RefreshKnown(__instance); } } } }