Ive made some improvements to your RemoveAnimalsAI plugin (v1.2.0 update) that adds new features and fixes a few issues. I wanted to share these changes with you in case you'd like to incorporate them. All changes have been tested and are working as expected.
Changelog - v1.2.0 Update:
New Feature:
Added snake hazard disabling (3 new Harmony patches: ShouldStartHazard, StartReposition, OnHazardFailed) - completely freezes snake attacks and movement
Bug Fixes:
Added Harmony instance management with unique ID to prevent conflicts with other plugins
Added proper UnpatchAll() in Unload() for clean plugin removal
Code Quality:
Added type checking to TickAiPatch (if (__instance is BaseAnimalNPC)) - more explicit and safer
Added type checking to InitializeAIPatch (if (__instance is AnimalBrain)) - prevents accidental blocking of other brain types (before when unloading bunch of console errors)
Simplified RunJobPatch logic - removed confusing health check code
Added documentation header and inline comments & organized using statements
Result: Animals and snakes fully frozen, Scientists/NPCs working, no memory leaks, clean plugin unload/*
* RemoveAnimalsAI Plugin
* Version: 1.2.0
* Author: Whipers88 @CobaltStudios
*
* Description:
* Disables AI for all animals (old system and Gen2) and snake hazards while keeping human NPCs fully functional.
*
* Features:
* - Blocks old AI system (BaseAnimalNPC, AnimalBrain, AIThinkManager)
* - Blocks Gen2 AI system (BaseNPC2, FSMComponent, LimitedTurnNavAgent)
* - Disables snake hazard attacks and movement
* - Preserves human NPCs (Scientists, NPCs)
*
* Supported "Animals":
* - Old AI: Bear, Boar, Chicken, Polarbear, Stag, Wolf, Zombie
* - Gen2 AI: Crocodile, Panther, Tiger, Wolf2
* - Snake Hazards
*/
using System;
using System.Collections.Generic;
using Facepunch;
using HarmonyLib;
using Oxide.Core.Plugins;
using Rust.Ai.Gen2;
using static Rust.Ai.Gen2.FSMComponent;
namespace Oxide.Plugins
{
[Info("Remove Animals AI", "Whipers88 @CobaltStudios", "1.2.0")]
[Description("Removing AI for animals and snakes (not for bots)")]
public class RemoveAnimalsAI : RustPlugin
{
static RemoveAnimalsAI _plugin;
private static Harmony _harmony;
// Plugin initialization - clears Gen2 FSM work queue and kills existing Gen2 animals
private void Init()
{
_plugin = this;
_harmony = new Harmony("RemoveAnimalsAI_" + DateTimeOffset.UtcNow.Ticks);
// Clear Gen2 FSM work queue - remove all animal FSM components except Scientists
List<FSMComponent> FSMComponents = Pool.Get<List<FSMComponent>>();
foreach(var fsmComponent in FSMComponent.workQueue.workList)
{
if (fsmComponent._baseEntity is ScientistNPC2)
continue;
FSMComponents.Add(fsmComponent);
}
foreach(var item in FSMComponents)
{
FSMComponent.workQueue.Remove(item);
}
// Kill existing Gen2 animals (they don't restore properly when just patched)
foreach (var entity in BaseNetworkable.serverEntities)
{
if (entity is BaseNPC2 && !(entity is ScientistNPC2))
{
entity.Kill();
}
}
}
// Plugin cleanup
private void Unload()
{
_harmony?.UnpatchAll(_harmony.Id);
_harmony = null;
_plugin = null;
}
// Blocks AI tick updates for animals (old AI system)
[HarmonyPatch(typeof(BaseNpc), nameof(BaseNpc.TickAi)), AutoPatch]
public static class TickAiPatch
{
[HarmonyPrefix]
private static bool Prefix(BaseNpc __instance)
{
// Only block animals, allow Scientists and other NPCs
if (__instance is BaseAnimalNPC)
return false;
return true;
}
}
// Blocks Gen2 navigation steering - only allows Scientists to move
[HarmonyPatch(typeof(LimitedTurnNavAgent), nameof(LimitedTurnNavAgent.TickSteering)), AutoPatch]
public static class TickSteeringPatch
{
[HarmonyPrefix]
private static bool Prefix(LimitedTurnNavAgent __instance)
{
for (int i = LimitedTurnNavAgent.steeringComponents.Count - 1; i >= 0; i--)
{
LimitedTurnNavAgent item = LimitedTurnNavAgent.steeringComponents[i];
if (item.IsUnityNull<LimitedTurnNavAgent>() || !item.baseEntity.IsValid() || !(item.baseEntity is ScientistNPC2))
{
LimitedTurnNavAgent.steeringComponents.RemoveAt(i);
}
else
{
item.Tick();
}
}
return false;
}
}
// Blocks Gen2 FSM AI job execution - only allows Scientists
[HarmonyPatch(typeof(TickFSMWorkQueue), "RunJob"), AutoPatch]
public static class RunJobPatch
{
[HarmonyPrefix]
private static bool Prefix(FSMComponent component)
{
if (component == null)
return false;
// Allow ScientistNPC2 (human NPCs) to process normally
if(component._baseEntity is ScientistNPC2)
return true;
// Block all other FSM components (Gen2 animals)
return false;
}
}
// Blocks animal AI queue processing (old AI system)
[HarmonyPatch(typeof(AIThinkManager), nameof(AIThinkManager.ProcessQueue)), AutoPatch]
public static class ProcessQueuePatch
{
[HarmonyPrefix]
private static bool Prefix(AIThinkManager.QueueType queueType)
{
if (queueType == AIThinkManager.QueueType.Animal)
{
return false;
}
return true;
}
}
// Prevents animal brain initialization (old AI system)
[HarmonyPatch(typeof(AnimalBrain), nameof(AnimalBrain.InitializeAI)), AutoPatch]
public static class InitializeAIPatch
{
[HarmonyPrefix]
private static bool Prefix(BaseAIBrain __instance)
{
// Only block AnimalBrain initialization, allow ScientistBrain and others
if (__instance is AnimalBrain)
return false;
return true;
}
}
// Prevents snake hazard activation
[HarmonyPatch(typeof(SnakeHazard), nameof(SnakeHazard.ShouldStartHazard)), AutoPatch]
public static class SnakeShouldStartHazardPatch
{
[HarmonyPrefix]
private static bool Prefix(ref bool __result)
{
__result = false;
return false; // Block hazard start
}
}
// Blocks snake movement/teleport loop
[HarmonyPatch(typeof(SnakeHazard), nameof(SnakeHazard.StartReposition)), AutoPatch]
public static class SnakeStartRepositionPatch
{
[HarmonyPrefix]
private static bool Prefix()
{
return false; // Block movement/teleport loop
}
}
// Prevents snake attack scheduling
[HarmonyPatch(typeof(SnakeHazard), "OnHazardFailed"), AutoPatch]
public static class SnakeOnHazardFailedPatch
{
[HarmonyPrefix]
private static bool Prefix()
{
return false; // Block attack scheduling
}
}
}
}