Fought Not Farmed
The basic idea of this mod is to make a mob spawner a thing you actually fight instead of something you torch or farm. A Living Spawner is a stationary, attackable entity that keeps summoning whatever it was originally configured to spawn while a player is nearby, and the encounter is only over once you've fought through all the reinforcements and destroyed the spawner itself.
Before
Spawner block → torch it or farm it
After
Living Spawner → fight through its summons → destroy it
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.244 or newer for Minecraft 1.21.1
- Java 21 on servers and dev machines
- The mod has to be on both the server and connecting clients
No library mods needed. Its not using mixins and its not touching terrain or structure generation.
Installation
- Install NeoForge for 1.21.1.
- Drop
foughtnotfarmed-1.2.1.jarinto the instance'smodsfolder. - Same JAR on the dedicated server and every client.
- Run the game or server once so it generates the config files.
How it works by default
- Every eligible
minecraft:spawnerhas a 100% one-time conversion chance. - If a spawner is encased, it relocates to the nearest loaded air or water position with at least two exposed faces. The behavior, accepted blocks, face count, and search radius are all configurable.
- New structures, old loaded chunks, runtime block placement, and bounded round-robin scans all work.
- The original
SpawnData, weightedSpawnPotentials, entity NBT, delays, spawn count, nearby cap, player range, and spawn range all carry over. - The Living Spawner has 50 health, one-block size, no movement, no knockback, and no pathfinding goals.
- It takes normal melee, projectile, magic, fire, and explosion damage. In-wall, drowning, fall, cactus, cramming, freezing, and similar environmental damage are off by default.
- It pauses when no player is in the configured range and on Peaceful difficulty.
- Drops 15 XP when killed by a player, no item loot by default.
- Mobs it already summoned stay alive after the spawner dies.
- A destroyed Living Spawner comes back at its death position after 30 minutes of loaded server time by default. Respawning, the delay, server-time vs system-time tracking, and health-based delay scaling are all configurable.
- The cage renders using the vanilla spawner block model and shows the current mob preview with whatever modded entity renderer is available.
- Active cages emit vanilla smoke and flame particles. During the configurable warning window they shake and play an alert sound, then briefly scale up and down after a successful spawn cycle.
Compatibility with other mods and datapacks
The spawner's existing data is the whole compatibility layer. If another mod or datapack places a normal Minecraft spawner with a registered entity type, Fought Not Farmed attempts to load that entity from the original NBT and fires NeoForge's spawner position/finalize-spawn hooks. There's no hardcoded list of supported mobs or structures.
The conversion system runs after chunks reach normal server-thread processing. It looks at block-entity positions instead of scanning every block, never scans the whole world, and doesn't wait on chunk-gen worker threads. Runtime scans rotate through a configurable number of loaded chunks at a configurable interval.
Datapacks can extend these entity-type tags:
foughtnotfarmed:cannot_be_spawned_by_living_spawner(hard exclusion; includes the Living Spawner itself)foughtnotfarmed:bosses(mobs with this tag are excluded whileallowBossEntitiesis false; includes the Ender Dragon and Wither by default)
Configuration
Gameplay settings go in config/foughtnotfarmed-common.toml. Presentation settings go in config/foughtnotfarmed-client.toml. Restart the game/server after changing them. .
Main groups:
conversion: automatic conversion, one-time chance, old/runtime chunk handling, player placement policy, entity/dimension filters, scan budgets, encased-spawner relocation.combat: health/scaling, armor, knockback resistance, damage categories, global damage multiplier.respawning: enablement, delay, clock source, optional max-health scaling.spawning: spawn-count/delay/range multipliers, active-summon policy, line of sight, boss policy, Peaceful behavior, warning timing.rewards: XP, loot table, whether loaded tracked summons are discarded on death.- client config: activation particles, cage shake, preview rotation, visual hover amount.
Filter semantics are explicit: in BLACKLIST mode only the blacklist is consulted, in WHITELIST mode only the whitelist is consulted. Every entity ID in a weighted spawner has to pass the active filter before the spawner converts.
When conversion chance is below 100%, the first roll result is saved in the vanilla spawner block entity. Reloading the chunk doesn't reroll it until it eventually converts. An admin can still force it with the convert command.
Player-placed spawners
playerPlacedMode supports CONVERT, KEEP, and DISALLOW. Placement is reliably identified only when this mod actually observes a player place the block. A kept placement gets a persistent marker. Minecraft doesn't store trustworthy natural-vs-player provenance on old spawner blocks, so player-placed spawners from before the mod was installed can't be told apart from generated ones; they follow the existing-chunk policy.
Commands
All commands require permission level 2.
/foughtnotfarmed convert(convert the spawner block you're looking at; bypasses automatic enable/chance and a saved player-keep marker while still respecting entity/dimension safety filters)/foughtnotfarmed convertchunk(convert eligible spawner block entities in the current loaded chunk)/foughtnotfarmed convertarea <radius>(inspect block entities in loaded chunks intersecting a block radius up to 256; doesn't force-load chunks)/foughtnotfarmed debug(show the looked-at Living Spawner's source position, UUID, entity pool, delay, ranges, and owned active-summon count)
Adding to an existing world
You can add the mod to an existing world. With convertExistingChunks=true, eligible spawners convert as their chunks load. No new world or structure-specific integration needed.
Back up your worlds before changing the mod list. Removing the mod removes the Living Spawner entities, but it can't recreate the block each one replaced.
Safety limits and known constraints
- Malformed values are bounded to protect the server: spawn count 64, active tracking/cap 256, player range 256, spawn range 64.
- The owner UUID is stored in each spawned entity's NeoForge persistent data. Loaded tracked entities count toward the cap; unloaded ones don't consume active processing or a slot until encountered again.
- A Living Spawner tracks at most 512 UUIDs, prunes dead/unloaded references, and rebuilds ownership from nearby loaded entities after a reload.
- If
despawnSummonsOnDeath=true, currently loaded tracked summons are discarded. Unloaded entities can't be removed without force-loading chunks, and I'm not doing that. - Respawn records are per dimension. A due respawn waits until its death chunk is loaded and never force-loads it.
- Programmatic conversion uses ordinary server block mutation. Damage is a normal living-entity event that protection mods can cancel; command access is permission-gated.

