using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Zen;
using Zen.Lib;
using Zen.Lib.Config;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ZenBreeding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZenBreeding")]
[assembly: AssemblyCopyright("Copyright \ufffd 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.5.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ZenBreeding
{
[HarmonyPatch]
internal static class Breeding
{
internal enum SterilizeType
{
None,
All,
BabiesOnly
}
private static readonly int ZDOVarSterile = StringExtensionMethods.GetStableHashCode("ZenBreeding_Sterile");
private const string LaidEgg = "Zen_LaidEgg";
private const int LaidEggStackID = 100;
private static readonly Sprite FertileIcon = AssetIO.LoadSpriteFromResource((BaseUnityPlugin)(object)ZenMod<Plugin>.Instance, "heart.png");
private static bool IsSterile(this ZNetView? nview)
{
if (Object.op_Implicit((Object)(object)nview) && nview.IsValid())
{
return nview.GetZDO().GetBool(ZDOVarSterile, false);
}
return false;
}
private static bool IsLaid(this EggGrow egg)
{
return egg.m_item.m_itemData.IsLaidEgg();
}
private static bool IsLaidEgg(this ItemData egg)
{
return egg.m_customData.ContainsKey("Zen_LaidEgg");
}
internal static void InitPrefabs()
{
if (Configs.Sterilization.Value == SterilizeType.All)
{
CollectionExtensions.Do<GameObject>((IEnumerable<GameObject>)ZNetScene.instance.m_prefabs, (Action<GameObject>)RemoveProcreate);
}
}
private static void RemoveProcreate(GameObject prefab)
{
Procreation val = default(Procreation);
if (!Configs.BreedingAllowed.Value.Contains(((Object)prefab).name, true) && prefab.TryGetComponent<Procreation>(ref val))
{
Object.Destroy((Object)(object)val);
Logging<Plugin>.Message((object)("Sterilized prefab: " + ((Object)prefab).name), 0);
}
}
private static bool CanBreed(Character c)
{
return CanBreed(GameObjectExt.GetPrefabName(((Component)c).gameObject));
}
private static bool CanBreed(EggGrow egg)
{
return CanBreed(GameObjectExt.GetPrefabName(((Component)egg).gameObject));
}
private static bool CanBreed(ItemDrop item)
{
return CanBreed(ItemDataExt.GetPrefabName(item));
}
private static bool CanBreed(string prefabName)
{
if (Configs.Sterilization.Value != 0)
{
return Configs.BreedingAllowed.Value.Contains(prefabName, true);
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Procreation), "ReadyForProcreation")]
private static void Procreation_ReadyForProcreation(Procreation __instance, ref bool __result)
{
if (__instance.m_nview.IsValid())
{
__result = __result && !__instance.m_nview.IsSterile();
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Procreation), "MakePregnant")]
private static void Procreation_MakePregnant(Procreation __instance, ref bool __runOriginal)
{
if (__instance.m_nview.IsValid())
{
__runOriginal = !__instance.m_nview.IsSterile();
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(EggGrow), "GrowUpdate")]
private static IEnumerable<CodeInstruction> EggGrow_GrowUpdate_Transpiler(IEnumerable<CodeInstruction> codes)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Expected O, but got Unknown
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Expected O, but got Unknown
Func<Character, EggGrow, bool> func = EggGrow_Intercept;
CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[3]
{
CodeMatch.op_Implicit(OpCodes.Ldloc_1),
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Object), "op_Implicit", (Type[])null, (Type[])null), (string)null),
CodeMatch.op_Implicit(OpCodes.Brfalse)
};
return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward(array).ThrowIfInvalid("Unable to match IL").Advance(1)
.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
{
new CodeInstruction(OpCodes.Ldarg_0, (object)null)
})
.Set(OpCodes.Call, (object)func.Method)
.InstructionEnumeration();
}
private static bool EggGrow_Intercept(Character? hatchling, EggGrow egg)
{
if (!Object.op_Implicit((Object)(object)hatchling))
{
return false;
}
if (CanBreed(egg))
{
return true;
}
if (egg.IsLaid())
{
Sterilize(hatchling);
}
return true;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Growup), "GrowUpdate")]
private static IEnumerable<CodeInstruction> GrowUp_GrowUpdate_Transpiler(IEnumerable<CodeInstruction> codes)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Expected O, but got Unknown
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
Func<Character, Character, bool> func = GrowUp_Intercept;
CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[6]
{
CodeMatch.op_Implicit(OpCodes.Ldloc_1),
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Object), "op_Implicit", (Type[])null, (Type[])null), (string)null),
CodeMatch.op_Implicit(OpCodes.Brfalse),
CodeMatch.op_Implicit(OpCodes.Ldloc_2),
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Object), "op_Implicit", (Type[])null, (Type[])null), (string)null),
CodeMatch.op_Implicit(OpCodes.Brfalse)
};
return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward(array).ThrowIfInvalid("Unable to match IL").Advance(1)
.SetAndAdvance(OpCodes.Nop, (object)null)
.SetAndAdvance(OpCodes.Nop, (object)null)
.Advance(1)
.Set(OpCodes.Call, (object)func.Method)
.InstructionEnumeration();
}
private static bool GrowUp_Intercept(Character young, Character mature)
{
if (!Object.op_Implicit((Object)(object)young) || !Object.op_Implicit((Object)(object)mature))
{
return false;
}
if (CanBreed(mature))
{
return true;
}
if (young.m_nview.IsSterile())
{
Sterilize(mature);
}
return true;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Procreation), "Procreate")]
private static IEnumerable<CodeInstruction> Procreation_Procreate_Transpiler(IEnumerable<CodeInstruction> codes)
{
MethodInfo methodInfo = AccessTools.Method(typeof(Character), "SetLevel", (Type[])null, (Type[])null);
Action<Character, int> action = Procreate_SetLevel_Intercept;
MethodInfo methodInfo2 = AccessTools.Method(typeof(ItemDrop), "SetQuality", (Type[])null, (Type[])null);
Action<ItemDrop, int> action2 = Procreate_SetQuality_Intercept;
return Transpilers.MethodReplacer(Transpilers.MethodReplacer(codes, (MethodBase)methodInfo, (MethodBase)action.Method), (MethodBase)methodInfo2, (MethodBase)action2.Method);
}
private static void Procreate_SetLevel_Intercept(Character baby, int level)
{
baby.SetLevel(level);
ProcreateBaby(baby);
}
private static void Procreate_SetQuality_Intercept(ItemDrop item, int quality)
{
item.SetQuality(quality);
ProcreateEgg(item);
}
private static void ProcreateBaby(Character baby)
{
if (!CanBreed(baby))
{
Sterilize(baby);
}
}
private static void ProcreateEgg(ItemDrop egg)
{
SetEggState(egg.m_itemData, isLaid: true, !CanBreed(egg));
}
internal static void SetEggState(ItemData egg, bool isLaid, bool separateStacks)
{
egg.m_worldLevel = (separateStacks ? 100 : Game.m_worldLevel);
if (isLaid)
{
egg.m_customData["Zen_LaidEgg"] = true.ToString();
}
else
{
egg.m_customData.Remove("Zen_LaidEgg");
}
}
private static void Sterilize(Character offspring)
{
//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)
Logging<Plugin>.Info((object)$"Sterilize {((Object)offspring).name} {MathExt.XZY(((Component)offspring).transform.position)}", 0);
if (offspring.m_nview.IsOwner())
{
offspring.m_nview.GetZDO().Set(ZDOVarSterile, true);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Tameable), "GetHoverText")]
private static void Tameable_GetHoverText(Tameable __instance, ref string __result)
{
Procreation val = default(Procreation);
if (__instance.IsTamed() && !__instance.m_nview.IsSterile() && ((Component)__instance).TryGetComponent<Procreation>(ref val) && ((Behaviour)val).enabled)
{
HudExt.UpdateHoverIcons(Hud.instance, (Sprite[])(object)new Sprite[1] { FertileIcon });
if (val.IsPregnant())
{
__result += StringExt.Localize($"\n<color={UIColor.MajorInfo}>$info_pregnant</color>");
}
else
{
__result += StringExt.Localize($"\n<color={UIColor.MinorInfo}>$info_fertile</color>");
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ItemDrop), "GetHoverText")]
private static void ItemDrop_GetHoverText(ItemDrop __instance, ref string __result)
{
if (__instance.m_itemData.IsLaidEgg() && ((Character)Player.m_localPlayer).InGodMode())
{
__result += StringExt.Localize($"\n<color={UIColor.MinorInfo}>$info_sterile</color>");
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(int) })]
private static void ItemDrop_ItemData_GetTooltip(ItemData __instance, ref string __result)
{
if (!__instance.IsLaidEgg())
{
ItemDataExt.SetTooltipExtra(__instance, (string)null);
return;
}
string description = __instance.m_shared.m_description;
ItemDataExt.SetTooltipExtra(__instance, "$info_sterile");
__result = Regex.Replace(__result, "\\$item_newgameplusitem.*\n", string.Empty);
__result = __result.Replace(description, string.Format("{0}\n\n<color={1}>{2}</color>", description, UIColor.Orange, "$info_sterile"));
}
}
internal static class BreedingCommands
{
private const string CmdSterilize = "sterilize";
private const string CmdFertilize = "fertilize";
private static List<ItemData> Inventory
{
get
{
Player localPlayer = Player.m_localPlayer;
return ((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory().GetAllItems() : null) ?? new List<ItemData>();
}
}
private static string Syntax(string command)
{
return command + " <EggPrefabName>";
}
public static void Init()
{
ZenMod<Plugin>.Terminal.CreateCommand("sterilize", "Sterilize egg in your inventory", true, (Action<string[]>)ProcessEgg);
ZenMod<Plugin>.Terminal.CreateCommand("fertilize", "Fertilize egg in you inventory", true, (Action<string[]>)ProcessEgg);
}
private static ItemData[] FindItems(string name)
{
string name2 = name;
return Inventory.Where((ItemData item) => ItemDataExt.GetPrefabName(item).ToLower() == name2.ToLower()).ToArray();
}
private static void ProcessEgg(params string[] args)
{
if (args.Length < 2)
{
Console.instance.Print(Syntax(args[0]));
return;
}
string text = args[0].ToLower().Replace("Zen_".ToLower(), string.Empty);
string text2 = args[1];
ItemData[] array = FindItems(text2);
if (array.Length == 0)
{
Console.instance.Print("No item found: " + text2);
return;
}
bool flag;
if (!(text == "sterilize"))
{
if (!(text == "fertilize"))
{
throw new Exception("Unknown command: " + text);
}
flag = false;
}
else
{
flag = true;
}
bool flag2 = flag;
int num = 0;
ItemData[] array2 = array;
foreach (ItemData val in array2)
{
Breeding.SetEggState(val, flag2, flag2);
num += val.m_stack;
}
Console.instance.Print($"{StringExt.ToProperCase(text, true)} {num} {text2}");
}
}
internal static class Configs
{
public static readonly ConfigEntry<Breeding.SterilizeType> Sterilization;
public static readonly ConfigEntry<StringList> BreedingAllowed;
static Configs()
{
Sterilization = Config.Define<Breeding.SterilizeType>(true, "Breeding", "Sterilize", Breeding.SterilizeType.BabiesOnly, "Prevent exponential reproduction of tamed creatures.\r\n- None: No protection, Vanilla behavior\r\n- All: Remove all reproduction from adults and offspring. No reproduction allowed.\r\n- BabiesOnly: Babies are sterilized. However, wild creatures which are tamed will still be able to produce offspring.\r\nNOTE: Eggs that are discovered or purchased will produce a fertile Hen. That hen can produce eggs.\r\nHowever, any laid eggs will produce a sterile Hen that can not produce eggs.\r\nTIP: When you are in admin/god mode you can glance at the fertility of eggs on the ground.");
BreedingAllowed = Config.Define<StringList>(true, "Breeding", "Allowed Creatures", StringList.Empty, "Comma separated list of prefabs that are allowed to reproduce when sterilization is enabled.\r\nFor example: If you add \"ChickenEgg\" to this list then chicken eggs will grow into fertile chickens that can lay eggs.\r\n[restart required for changes to take effect]");
}
}
[BepInPlugin("ZenDragon.ZenBreeding", "ZenBreeding", "0.5.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
internal class Plugin : ZenMod<Plugin>
{
public const string PluginName = "ZenBreeding";
public const string PluginVersion = "0.5.0";
public const string PluginGUID = "ZenDragon.ZenBreeding";
protected override void Setup()
{
base.ConfigSync += Breeding.InitPrefabs;
BreedingCommands.Init();
}
protected override void TitleScene(bool isFirstBoot)
{
}
protected override void WorldStart()
{
}
protected override void Shutdown()
{
}
}
}