You are viewing a potentially older version of this package. View all versions.
CeruleanCutlass-AggroKit-0.1.2 icon

AggroKit

Reusable aggro/threat control tooling for Outward BepInEx mods: per-pair targetability gates, detection veto/redirect, taunt and force-target primitives. Inert until a mod uses it — a library dependency, installed automatically.

Date uploaded a week ago
Version 0.1.2
Download link CeruleanCutlass-AggroKit-0.1.2.zip
Downloads 94
Dependency string CeruleanCutlass-AggroKit-0.1.2

This mod requires the following mods to function

BepInEx-BepInExPack_Outward-5.4.19 icon
BepInEx-BepInExPack_Outward

BepInEx pack for Outward.

Preferred version: 5.4.19
CeruleanCutlass-ForgeKit-0.4.3 icon
CeruleanCutlass-ForgeKit

Dependency-free dev-tooling for Outward BepInEx mods: file-driven dev command loop, self-test harness, on-screen toasts, player-ready lifecycle wait, embedded/override table loaders, and a shared dev-verb pack (movement/combat/skill/status probes).

Preferred version: 0.4.3

README

AggroKit

📖 Full documentation: AggroKit wiki page

Reusable aggro/threat-control tooling for people writing BepInEx 5 mods for Outward: Definitive Edition. It doesn't add anything a player sees on its own — it's a library dependency other mods (CompanionKit, and anything built on top of it) pull in, and other modders are welcome to build on it too.

Requires: BepInEx 5 (Outward's Mono branch — see Compatibility below) + ForgeKit (hard dependency, installed automatically).

What's in it

Piece What it gives you
AggroTools Patch-free primitives for reading/adjusting engine aggro state without a Harmony patch of your own.
TargetableOverrides A per-pair targetability gate — make one specific character untargetable to one specific other character, without touching the game's global targeting rules.
AggroEvents Observability hooks (opt-in, off by default) plus an opt-in squad-self-target guard (also off by default — see BlockSquadSelfTarget).

Installing (for players)

Drop the AggroKit folder into BepInEx/plugins/. It has no effect by itself — install it because another mod you're using declares it as a dependency.

Configuration

BepInEx/config/cobalt.aggrokit.cfg (generated on first launch):

[Dev]
## Poll BepInEx/config/ak_cmd.txt for dev commands (aggrodump/forcetarget/taunt/calm/...).
EnableCommandFile = true

## Whether DumpKey logs an aggro dump of all AI characters near the player.
EnableDumpKey = true

## Key that logs an aggro dump of all AI characters near the player (needs EnableDumpKey=true).
# Default value: F3
DumpKey = F3

[Research]
## Re-arm AggroEvents' purely-observational Harmony taps that record the event buffer. OFF by
## default so these hot AI-tick paths stay un-patched. With EnablePatches on, the detection-side
## control patches and the targetability override gate are installed regardless of this key — they're
## inert until a verb activates them.
EnableObservation = false

[Fixes]
## Master switch for EVERY Harmony patch AggroKit installs. Off = it patches nothing at all, while
## the library calls and the ak_cmd.txt verbs keep working — so AggroKit can be ruled in or out of a
## mod-conflict bisection without uninstalling it. Applied at load; changing it needs a relaunch.
EnablePatches = true

## Opt-in fix for a squad-contagion self-target assignment in AISCombat.SetPreferredTarget.
## DEFAULT OFF: the case is unreachable in vanilla, and the block is a skipping Harmony prefix, which
## also suppresses any other mod's prefix on the same method. Read live — no relaunch needed.
BlockSquadSelfTarget = false

Dev verbs

AggroKit polls BepInEx/config/ak_cmd.txt (write a line, it runs on the next poll — works while the game is paused). [Dev] EnableCommandFile = false turns the channel off.

Verb What it does
aggrodump [radius] Aggro dump of every AI near the player, plus the player's targetability state
aistates [name|nearest] Dump one AI's state machine
aggrolog [n|on|off|clear] The [AGGRO] event buffer
watch <name|nearest|off> Watch an AI's (state, target) changes
forcetarget [name|nearest] Force an AI onto the player, and auto-watch it
feud <A> <B> [nooverride|both] Make any two AIs fight each other
taunt [radius] / calm [radius] Pull every AI in radius onto the player / calm them
untargetable / targetable Toggle the player's QuestNonTargetable
undetectable / detectable Toggle the player's DetectabilityMult
shieldme / unshieldme Toggle incoming-aggro shielding on the player
stealthme [off] Veto AI detection of the player
decoy <name>|off Redirect detections of the player onto another AI
noaggro [off] The player's hits generate no aggro
clearoverrides Clear all targetability overrides
status One glance: player flags, overrides, controls, watches, aggrolog
restore Undo everything — targetable + detectable, all overrides/controls/watches cleared
selftest Zero-interaction environment checks ([SELFTEST] PASS/FAIL … DONE)

The [Dev] DumpKey bind (default F3) runs aggrodump without the channel. Keys are a cross-mod resource in this workspace — AggroKit claims its bind through ForgeKit.Keybinds so a collision with another mod is reported rather than silently firing both.

Using it (for modders)

<!-- your .csproj -->
<ProjectReference Include="path\to\AggroKit\AggroKit.csproj" Private="false" />
[BepInPlugin(GUID, NAME, VERSION)]
[BepInDependency(AggroKit.Plugin.GUID)]
public class Plugin : BaseUnityPlugin
{
    // AggroTools / TargetableOverrides / AggroEvents are static entry points —
    // call them directly once AggroKit has loaded (declare it as a dependency above).
}

Private="false" matters — it stops MSBuild from copying a second AggroKit.dll into your mod's own output folder. The kit ships from its own BepInEx/plugins/AggroKit/ folder; your mod just references it and declares the dependency so BepInEx loads it first.

Compatibility

Outward must be on its Mono Steam beta branch, not the default IL2CPP build — like every BepInEx 5 mod for this game. If your game runs but no BepInEx mods load and there's no crash log, this is almost always why (Properties → Betas → select mono in Steam).

License

Apache License 2.0 — see LICENSE in the repository root. You may use, modify, and redistribute this kit (including in commercial mods) provided you keep the copyright/license notice; see the license text for the full terms.

CHANGELOG

AggroKit changelog

0.1.3 — 2026-08-19

  • Merge branch 'fix/sa-0815-leafkits' into feature/pet-self-feed
  • Static-analysis wave F3c: leaf-kit fixes (A7-1/2/4/8/9/13/14/15/16/20/23/24/25/27)
  • Test debt (F4): model every project in the dependency gate, AggroKit's first tests, UsageSpec corpus coverage
  • Coercion wave: every ForgeKit integration completes cleanly through the TUI seam
  • Forge shell fixes: SSH commands via bash -c (fish login shell); set/cfgdump on every channel mod
  • Forge shell: catalog dump + response protocol + set/cfgdump in ForgeKit; forge CLI/REPL + completion packs; wiki-enriched name db

0.1.2 — 2026-08-11

Prompted by a player report that bisected a vanilla-content bug down to AggroKit. The report did not hold up — AggroKit patches nothing on the path it was blamed for — but answering it took five passes over the decompiled game, because AggroKit was effectively unfalsifiable in the field. This release is about that, plus the one real defect the investigation found.

  • [Fixes] BlockSquadSelfTarget now defaults OFF. It was the mod's only unconditional change to vanilla AI, and it is implemented as a skipping Harmony prefix — which under HarmonyX suppresses every other mod's prefix on AISCombat.SetPreferredTarget as well as the original. The case it guards is unreachable in vanilla (both callers filter to allies, and an ally is never a valid target), so it was paying a cross-mod cost for a benefit that cannot be demonstrated. Still available for anyone who actually hits the fake-combat stall.
  • New [Fixes] EnablePatches master switch (default on). Disables every Harmony patch AggroKit installs while keeping the library primitives and the ak_cmd.txt dev verbs working — so AggroKit can be ruled in or out of a mod-conflict bisection without uninstalling it. Five patch classes previously had no gate at all.
  • AggroKit now says what it patched. A boot-time census of the vanilla methods actually patched (read back from the Harmony instance, not a hand-maintained list) plus the resolved gate values, both also surfaced by the status verb.
  • The self-target block reports when it fires, bounded per session — previously it was silent unless the dev-only ring buffer was enabled, which it never is in a shipped install.
  • HarmonyPriority(Priority.Last) on the three prefixes that can skip the original, so when AggroKit suppresses a method, other mods' patches have already had their say.
  • The IsTargetable postfix — the one patch body doing real work with no try/catch — now routes throws to the same bounded Swallowed reporter as every other patch body.
  • The self-test is now gate-aware: it asserts each patch's installed state matches its config rather than asserting it is installed, so EnablePatches = false no longer reads as a failure. It also cross-checks the census against the gates.
  • Docs: the README, wiki page and Thunderstore description no longer describe an "always-on" fix, and both now document EnablePatches.

Also in this release:

  • AggroKit: trim manifest description to Thunderstore's 250-char limit
  • Merge branch 'main' into fix/sa-0808-kits
  • Static-analysis 2026-08-08 wave D-kits: P2-13/P2-15 + the kit P3 group
  • Static-analysis 2026-08-08 wave 0: nine P1/P2 fixes
  • W4: fixes for everything D1 found, plus the join-race P1
  • AggroKit: fake-null cleanup for the aggro taps and taunt forensics
  • A1: the fake-null accessors, and every Plugin.cs cleared
  • A0 pilot: the fake-null rewrite recipe, proven on one file

0.1.1 — 2026-08-02

  • Logging: answer "why did nothing happen?" without needing LogVerbose on in advance
  • Cleanup: one anchor-collect loop, one ownership side-table
  • Docs sweep: archive, condense, and validate the whole documentation tree