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.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ShipTurrets")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Plugin that spawns two turrets on the front and rear of the player ship that targets and neutralises enemies instead of players.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShipTurrets")]
[assembly: AssemblyTitle("ShipTurrets")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ShipTurrets
{
public static class PluginInfo
{
public const string PLUGIN_GUID = "ShipTurrets";
public const string PLUGIN_NAME = "ShipTurrets";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace FairGiants
{
[BepInPlugin("com.woah25.FairGiantsSS", "FairGiantsHostOnly", "1.3.0")]
public class FairGiantsMod : BaseUnityPlugin
{
internal static ManualLogSource ModLogger;
internal static ConfigEntry<bool> RandomWander;
internal static ConfigEntry<bool> EnhancedAntiCamp;
internal static ConfigEntry<float> PassiveStealthDecay;
internal static ConfigEntry<PatchApplyLevel> StealthDecaysWhen;
internal static ConfigEntry<float> GiantSpeedMultiplier;
private void Awake()
{
ModLogger = ((BaseUnityPlugin)this).Logger;
InitializeConfig();
Harmony.CreateAndPatchAll(typeof(ForestGiantAIPatch), (string)null);
ModLogger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.Name} v{((BaseUnityPlugin)this).Info.Metadata.Version} is loaded!");
}
private void InitializeConfig()
{
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Expected O, but got Unknown
RandomWander = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "RandomWander", true, "Enable random wandering for giants");
EnhancedAntiCamp = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "EnhancedAntiCamp", true, "Enable enhanced anti-camping behavior");
PassiveStealthDecay = ((BaseUnityPlugin)this).Config.Bind<float>("Stealth", "PassiveStealthDecay", 0.2f, new ConfigDescription("Rate of passive stealth decay", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
StealthDecaysWhen = ((BaseUnityPlugin)this).Config.Bind<PatchApplyLevel>("Stealth", "StealthDecaysWhen", PatchApplyLevel.Always, "When stealth decay should be applied");
GiantSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "GiantSpeedMultiplier", 0.7f, new ConfigDescription("Multiplier for giant's movement speed", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
}
}
public enum PatchApplyLevel
{
Always,
Solo,
Never
}
[HarmonyPatch(typeof(ForestGiantAI))]
public static class ForestGiantAIPatch
{
private static readonly Random random = new Random();
[HarmonyPatch("DoAIInterval")]
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> GiantRoamPatch(IEnumerable<CodeInstruction> instructions)
{
//IL_0002: 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_0037: Expected O, but got Unknown
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Expected O, but got Unknown
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Expected O, but got Unknown
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Expected O, but got Unknown
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Expected O, but got Unknown
return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(EnemyAI), "ChooseFarthestNodeFromPosition", (Type[])null, (Type[])null), (string)null)
}).Advance(3).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[6]
{
new CodeInstruction(OpCodes.Ldarg_0, (object)null),
CodeInstruction.Call(typeof(ForestGiantAIPatch), "LeaveShipPatch", (Type[])null, (Type[])null),
new CodeInstruction(OpCodes.Ldarg_0, (object)null),
new CodeInstruction(OpCodes.Ldloc_1, (object)null),
CodeInstruction.Call(typeof(ForestGiantAIPatch), "ChooseFarNodeFromShip", (Type[])null, (Type[])null),
new CodeInstruction(OpCodes.Stloc_1, (object)null)
})
.InstructionEnumeration();
}
public static Vector3 ChooseFarNodeFromShip(ForestGiantAI ai, Vector3 farPosition)
{
//IL_001f: 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_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: 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_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: 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_010f: Unknown result type (might be due to invalid IL or missing references)
if (!FairGiantsMod.RandomWander.Value)
{
return farPosition;
}
Vector3 ship = StartOfRound.Instance.elevatorTransform.position;
Vector3 entranceTeleportBPos = FindEntrance();
Random localRandom = new Random(GetSeed(((Component)ai).transform.position));
List<(GameObject, float)> source = (from node in ((EnemyAI)ai).allAINodes
select (node, Vector3.Distance(ship, node.transform.position)) into x
where x.Item2 >= 102f && Vector3.Distance(entranceTeleportBPos, x.node.transform.position) > 50f
orderby x.Item2 + (float)localRandom.Next(-12, 12) descending
select x).ToList();
((EnemyAI)ai).nodesTempArray = source.Select<(GameObject, float), GameObject>(((GameObject node, float) x) => x.node).ToArray();
if (((EnemyAI)ai).nodesTempArray.Length == 0)
{
return farPosition;
}
double weight = CalculateWeight(CalculateWeightBase(source.Select<(GameObject, float), float>(((GameObject node, float) x) => x.Item2).ToArray()), ((EnemyAI)ai).nodesTempArray.Length);
return ChooseOptimalPosition(ai, farPosition, localRandom, weight);
}
private static Vector3 FindEntrance()
{
//IL_0020: 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)
GameObject val = GameObject.Find("EntranceTeleportB(Clone)");
if (!((Object)(object)val != (Object)null))
{
return Vector3.zero;
}
return val.transform.position;
}
private static int GetSeed(Vector3 position)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return RoundUpToNearestFive(position.x) + RoundUpToNearestFive(position.z);
}
private static float CalculateWeightBase(float[] distances)
{
return 0.7f * distances.Average() + 0.3f * (distances.First() + distances.Last());
}
private static double CalculateWeight(float weightBase, int nodeCount)
{
return (double)(Mathf.Clamp((weightBase < 152.5f) ? (-0.8f * (weightBase - 100f) + 50f) : (-0.125f * (weightBase - 152.5f) + 8f), 1f, 50f) * (float)Mathf.Clamp(130 - nodeCount, 50, 100)) * 0.0001;
}
private static Vector3 ChooseOptimalPosition(ForestGiantAI ai, Vector3 farPosition, Random localRandom, double weight)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: 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_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: 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_0031: 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_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
Vector3 position = StartOfRound.Instance.elevatorTransform.position;
Vector3 result = farPosition;
for (int i = 1; i < ((EnemyAI)ai).nodesTempArray.Length; i++)
{
if (localRandom.NextDouble() < weight)
{
break;
}
Vector3 position2 = ((EnemyAI)ai).nodesTempArray[i].transform.position;
if (!((EnemyAI)ai).PathIsIntersectedByLineOfSight(position2, false, false, false))
{
((EnemyAI)ai).mostOptimalDistance = Vector3.Distance(position, position2);
result = position2;
if (i >= ((EnemyAI)ai).nodesTempArray.Length - 1)
{
break;
}
}
}
return result;
}
public static void LeaveShipPatch(ForestGiantAI ai)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
if (FairGiantsMod.EnhancedAntiCamp.Value)
{
FairGiantsMod.ModLogger.LogInfo((object)"Roaming Away");
if (ai.roamPlanet == null)
{
ai.roamPlanet = new AISearchRoutine();
}
((EnemyAI)ai).StopSearch(ai.roamPlanet, true);
ai.roamPlanet.searchWidth = 35f;
}
}
[HarmonyPatch("FinishedCurrentSearchRoutine")]
[HarmonyPostfix]
public static void GiantFinishSearch(ForestGiantAI __instance)
{
if (FairGiantsMod.EnhancedAntiCamp.Value)
{
FairGiantsMod.ModLogger.LogDebug((object)"Giant Finished a Search");
if (__instance.roamPlanet != null && __instance.roamPlanet.searchWidth < 200f)
{
__instance.roamPlanet.searchWidth = 200f;
}
}
}
[HarmonyPatch("LookForPlayers")]
[HarmonyPostfix]
public static void AggroPatch(ForestGiantAI __instance)
{
LowerAllAggro(__instance);
}
public static void LowerAllAggro(ForestGiantAI ai)
{
if (((EnemyAI)ai).currentBehaviourStateIndex != 0 || ShouldApplyStealthDecay())
{
for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++)
{
ai.playerStealthMeters[i] = Mathf.Clamp(ai.playerStealthMeters[i] - Time.deltaTime * FairGiantsMod.PassiveStealthDecay.Value, 0f, 1f);
}
}
}
private static bool ShouldApplyStealthDecay()
{
if (FairGiantsMod.StealthDecaysWhen.Value != 0)
{
if (FairGiantsMod.StealthDecaysWhen.Value == PatchApplyLevel.Solo)
{
return StartOfRound.Instance.connectedPlayersAmount <= 0;
}
return false;
}
return true;
}
[HarmonyPatch("DoAIInterval")]
[HarmonyPrefix]
public static void AdjustGiantSpeed(ForestGiantAI __instance)
{
NavMeshAgent agent = ((EnemyAI)__instance).agent;
agent.speed *= FairGiantsMod.GiantSpeedMultiplier.Value;
}
[HarmonyPatch("DoAIInterval")]
[HarmonyPostfix]
public static void HandleOwnership(ForestGiantAI __instance)
{
if (!((EnemyAI)__instance).isEnemyDead && ((NetworkBehaviour)RoundManager.Instance).NetworkManager.IsHost && ((NetworkBehaviour)__instance).OwnerClientId != GameNetworkManager.Instance.localPlayerController.actualClientId)
{
((EnemyAI)__instance).ChangeOwnershipOfEnemy(GameNetworkManager.Instance.localPlayerController.actualClientId);
}
}
private static int RoundUpToNearestFive(float value)
{
return Mathf.CeilToInt(value / 5f) * 5;
}
}
}