diff --git a/patches/minecraft/net/minecraft/world/entity/Mob.java.patch b/patches/minecraft/net/minecraft/world/entity/Mob.java.patch
index 371f7510dd..5e2b43e39a 100644
--- a/patches/minecraft/net/minecraft/world/entity/Mob.java.patch
+++ b/patches/minecraft/net/minecraft/world/entity/Mob.java.patch
@@ -74,16 +74,17 @@
if (entity != null) {
double d0 = entity.m_20280_(this);
int i = this.m_6095_().m_20674_().m_21611_();
-@@ -1020,6 +_,15 @@
+@@ -1020,6 +_,16 @@
}
+ /**
-+ * Forge: Deprecated, call via ForgeEventFactory.onFinalizeSpawn.
-+ * Overrides are fine. Super calls within overrides are fine and should not be wrapped (as that will cause stack overflows).
-+ * Vanilla calls are replaced with a transformer, and are not visible in source.
++ * Forge: Override-Only, call via ForgeEventFactory.onFinalizeSpawn.
++ * Overrides are allowed. Do not wrap super calls within override (as that will cause stack overflows).
++ * Vanilla calls are replaced with a transformer, and are not visible in source.
+ *
+ * Be certain to either call super.finalizeSpawn or set the {@link #spawnType} field from within your override.
++ * @see {@link net.minecraftforge.event.ForgeEventFactory#onFinalizeSpawn onFinalizeSpawn} for additional documentation.
+ */
+ @Deprecated
+ @org.jetbrains.annotations.ApiStatus.OverrideOnly
diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
index d25ceb4b04..60a7735635 100644
--- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
+++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
@@ -193,12 +193,34 @@ public class ForgeEventFactory
* Vanilla calls to {@link Mob#finalizeSpawn} are replaced with calls to this method via coremod.
* Mods should call this method in place of calling {@link Mob#finalizeSpawn}. Super calls (from within overrides) should not be wrapped.
*
- * Returns the SpawnGroupData from this event, or null if it was canceled. + * When interfacing with this event, write all code as normal, and replace the call to {@link Mob#finalizeSpawn} with a call to this method.
+ * As an example, the following code block:
+ *
+ * Would become:
+ *
+ * var zombie = new Zombie(level);
+ * zombie.finalizeSpawn(level, difficulty, spawnType, spawnData, spawnTag);
+ * level.tryAddFreshEntityWithPassengers(zombie);
+ * if (zombie.isAddedToWorld()) {
+ * // Do stuff with your new zombie
+ * }
+ *
+ * The only code that changes is the {@link Mob#finalizeSpawn} call.
+ * @return The SpawnGroupData from this event, or null if it was canceled. The return value of this method has no bearing on if the entity will be spawned.
* @see MobSpawnEvent.FinalizeSpawn
* @see Mob#finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData, CompoundTag)
+ * @apiNote Callers do not need to check if the entity's spawn was cancelled, as the spawn will be blocked by Forge.
* @implNote Changes to the signature of this method must be reflected in the method redirector coremod.
*/
@Nullable
+ @SuppressWarnings("deprecation") // Call to deprecated Mob#finalizeSpawn is expected.
public static SpawnGroupData onFinalizeSpawn(Mob mob, ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnType, @Nullable SpawnGroupData spawnData, @Nullable CompoundTag spawnTag)
{
var event = new MobSpawnEvent.FinalizeSpawn(mob, level, mob.getX(), mob.getY(), mob.getZ(), difficulty, spawnType, spawnData, spawnTag, null);
diff --git a/src/main/java/net/minecraftforge/event/entity/living/MobSpawnEvent.java b/src/main/java/net/minecraftforge/event/entity/living/MobSpawnEvent.java
index 17febc27fd..6c6db13de2 100644
--- a/src/main/java/net/minecraftforge/event/entity/living/MobSpawnEvent.java
+++ b/src/main/java/net/minecraftforge/event/entity/living/MobSpawnEvent.java
@@ -86,14 +86,16 @@ public abstract class MobSpawnEvent extends EntityEvent
}
/**
- * This event is fired before {@link Mob#finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData, CompoundTag)} is called.
+ * var zombie = new Zombie(level);
+ * ForgeEventFactory.onFinalizeSpawn(zombie, level, difficulty, spawnType, spawnData, spawnTag);
+ * level.tryAddFreshEntityWithPassengers(zombie);
+ * if (zombie.isAddedToWorld()) {
+ * // Do stuff with your new zombie
+ * }
+ *
+ * This event is fired before {@link Mob#finalizeSpawn} is called.
* This allows mods to control mob initialization.
- * In vanilla code, this event is injected by a transformer and not via patch, so calls cannot be traced via call hierarchy.
+ * In vanilla code, this event is injected by a transformer and not via patch, so calls cannot be traced via call hierarchy (it is not source-visible).
*
* Canceling this event will result in {@link Mob#finalizeSpawn} not being called, and the returned value always being null, instead of propagating the SpawnGroupData.
- * The entity will still be spawned. If you want to prevent the spawn, use {@link FinalizeSpawn#cancelSpawn()}
+ * The entity will still be spawned. If you want to prevent the spawn, use {@link FinalizeSpawn#setSpawnCancelled}, which will cause Forge to prevent the spawn.
*
* This event is fired on {@link MinecraftForge#EVENT_BUS}, and is only fired on the logical server. + * @see ForgeEventFactory#onFinalizeSpawn + * @apiNote Callers do not need to check if the entity's spawn was cancelled, as the spawn will be blocked by Forge. */ @Cancelable public static class FinalizeSpawn extends MobSpawnEvent