Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit 092b7b9

Browse files
NuclearfartsNuclearfarts
authored andcommitted
LivingSpawnEvent.CheckSpawn and LivingSpawnEvent.SpecialSpawn
1 parent 67211e2 commit 092b7b9

9 files changed

Lines changed: 420 additions & 4 deletions

File tree

patchwork-events-entity/src/main/java/com/patchworkmc/impl/event/entity/EntityEvents.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,24 @@
2323
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
2424
import net.minecraftforge.event.entity.living.LivingAttackEvent;
2525
import net.minecraftforge.event.entity.living.LivingDeathEvent;
26+
import net.minecraftforge.event.entity.living.LivingHurtEvent;
27+
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
2628
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
2729
import net.minecraftforge.eventbus.api.Event;
28-
import org.apache.logging.log4j.LogManager;
30+
import net.minecraftforge.eventbus.api.Event.Result;
2931
import org.apache.logging.log4j.Logger;
32+
import org.apache.logging.log4j.LogManager;
3033

3134
import net.minecraft.entity.Entity;
3235
import net.minecraft.entity.LivingEntity;
36+
import net.minecraft.entity.SpawnType;
3337
import net.minecraft.entity.damage.DamageSource;
38+
import net.minecraft.entity.mob.MobEntity;
3439
import net.minecraft.entity.player.PlayerEntity;
3540
import net.minecraft.util.ActionResult;
3641
import net.minecraft.util.Hand;
42+
import net.minecraft.world.IWorld;
43+
import net.minecraft.world.MobSpawnerLogic;
3744
import net.minecraft.world.World;
3845

3946
import net.fabricmc.api.ModInitializer;
@@ -63,6 +70,45 @@ public static boolean onLivingAttack(LivingEntity entity, DamageSource src, floa
6370
return MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, damage));
6471
}
6572

73+
public static float onLivingHurt(LivingEntity entity, DamageSource src, float damage) {
74+
LivingHurtEvent event = new LivingHurtEvent(entity, src, damage);
75+
return MinecraftForge.EVENT_BUS.post(event) ? 0 : event.getAmount();
76+
}
77+
78+
public static Result canEntitySpawn(MobEntity entity, IWorld world, double x, double y, double z, MobSpawnerLogic spawner, SpawnType spawnType) {
79+
if (entity == null) {
80+
return Result.DEFAULT;
81+
}
82+
83+
LivingSpawnEvent.CheckSpawn event = new LivingSpawnEvent.CheckSpawn(entity, world, x, y, z, spawner, spawnType);
84+
MinecraftForge.EVENT_BUS.post(event);
85+
return event.getResult();
86+
}
87+
88+
public static boolean canEntitySpawnFromSpawner(MobEntity entity, World world, double x, double y, double z, MobSpawnerLogic spawner) {
89+
Result result = canEntitySpawn(entity, world, x, y, z, spawner, SpawnType.SPAWNER);
90+
91+
if (result == Result.DEFAULT) {
92+
return entity.canSpawn(world, SpawnType.SPAWNER) && entity.canSpawn(world); //vanilla logic, but inverted since we're checking if it CAN spawn instead of if it CAN'T
93+
} else {
94+
return result == Result.ALLOW;
95+
}
96+
}
97+
98+
public static boolean canEntitySpawnNaturally(MobEntity entity, IWorld world, double x, double y, double z, MobSpawnerLogic spawner, SpawnType spawnType, double sqDistanceFromPlayer) {
99+
Result result = canEntitySpawn(entity, world, x, y, z, spawner, spawnType);
100+
101+
if (result == Result.DEFAULT) {
102+
return !(sqDistanceFromPlayer > 16384.0D && entity.canImmediatelyDespawn(sqDistanceFromPlayer)) && entity.canSpawn(world, SpawnType.NATURAL) && entity.canSpawn(world); //vanilla logic, but inverted since we're checking if it CAN spawn instead of if it CAN'T
103+
} else {
104+
return result == Result.ALLOW;
105+
}
106+
}
107+
108+
public static boolean doSpecialSpawn(MobEntity entity, IWorld world, double x, double y, double z, MobSpawnerLogic spawner, SpawnType spawnType) {
109+
return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z, spawner, spawnType));
110+
}
111+
66112
@Override
67113
public void onInitialize() {
68114
UseItemCallback.EVENT.register((player, world, hand) -> {

patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinLivingEntity.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.spongepowered.asm.mixin.Mixin;
2323
import org.spongepowered.asm.mixin.injection.At;
2424
import org.spongepowered.asm.mixin.injection.Inject;
25+
import org.spongepowered.asm.mixin.injection.ModifyVariable;
2526
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
2627
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
2728

@@ -50,4 +51,19 @@ private void hookDamage(DamageSource source, float amount, CallbackInfoReturnabl
5051
callback.setReturnValue(false);
5152
}
5253
}
54+
55+
// Shift back one because otherwise we inject after the value of damage is pushed onto the JVM stack, causing the modification to have no effect
56+
@ModifyVariable(method = "applyDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.applyArmorToDamage(Lnet/minecraft/entity/damage/DamageSource;F)F", shift = At.Shift.BEFORE))
57+
private float hookApplyDamageForHurtEvent(float damage, DamageSource source) {
58+
LivingEntity entity = (LivingEntity) (Object) this;
59+
60+
return EntityEvents.onLivingHurt(entity, source, damage);
61+
}
62+
63+
@Inject(method = "applyDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.applyArmorToDamage(Lnet/minecraft/entity/damage/DamageSource;F)F"), cancellable = true)
64+
private void hookApplyDamageForHurtEventCancel(DamageSource source, float damage, CallbackInfo info) {
65+
if (damage <= 0) {
66+
info.cancel();
67+
}
68+
}
5369
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.patchworkmc.mixin.event.entity;
2+
3+
import org.spongepowered.asm.mixin.Mixin;
4+
import org.spongepowered.asm.mixin.injection.At;
5+
import org.spongepowered.asm.mixin.injection.Redirect;
6+
7+
import net.minecraft.entity.SpawnType;
8+
import net.minecraft.entity.mob.MobEntity;
9+
import net.minecraft.world.IWorld;
10+
import net.minecraft.world.MobSpawnerLogic;
11+
import net.minecraft.world.ViewableWorld;
12+
import net.minecraft.world.World;
13+
14+
import com.patchworkmc.impl.event.entity.EntityEvents;
15+
16+
@Mixin(MobSpawnerLogic.class)
17+
public class MixinMobSpawnerLogic {
18+
@Redirect(method = "update", at = @At(value = "INVOKE", target = "net/minecraft/entity/mob/MobEntity.canSpawn(Lnet/minecraft/world/IWorld;Lnet/minecraft/entity/SpawnType;)Z"))
19+
private boolean spawnTestRedirect(MobEntity on, IWorld world, SpawnType type) {
20+
MobSpawnerLogic spawner = (MobSpawnerLogic) (Object) this;
21+
22+
return EntityEvents.canEntitySpawnFromSpawner(on, (World) world, on.x, on.y, on.z, spawner);
23+
}
24+
25+
@Redirect(method = "update", at = @At(value = "INVOKE", target = "net/minecraft/entity/mob/MobEntity.canSpawn(Lnet/minecraft/world/ViewableWorld;)Z"))
26+
private boolean makeTheOtherMethodNotMessItUp(MobEntity on, ViewableWorld world) {
27+
return true;
28+
}
29+
}

patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinPlayerEntity.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.spongepowered.asm.mixin.Mixin;
2323
import org.spongepowered.asm.mixin.injection.At;
2424
import org.spongepowered.asm.mixin.injection.Inject;
25+
import org.spongepowered.asm.mixin.injection.ModifyVariable;
2526
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
2627
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
2728

@@ -81,4 +82,19 @@ private void hookDamage(DamageSource source, float amount, CallbackInfoReturnabl
8182
callback.setReturnValue(false);
8283
}
8384
}
85+
86+
// Shift back one because otherwise we inject after the value of damage is pushed onto the JVM stack, causing the modification to have no effect
87+
@ModifyVariable(method = "applyDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/player/PlayerEntity.applyArmorToDamage(Lnet/minecraft/entity/damage/DamageSource;F)F", shift = At.Shift.BEFORE))
88+
private float hookApplyDamageForHurtEvent(float damage, DamageSource source) {
89+
LivingEntity entity = (LivingEntity) (Object) this;
90+
91+
return EntityEvents.onLivingHurt(entity, source, damage);
92+
}
93+
94+
@Inject(method = "applyDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/player/PlayerEntity.applyArmorToDamage(Lnet/minecraft/entity/damage/DamageSource;F)F"), cancellable = true)
95+
private void hookApplyDamageForHurtEventCancel(DamageSource source, float damage, CallbackInfo info) {
96+
if (damage <= 0) {
97+
info.cancel();
98+
}
99+
}
84100
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.patchworkmc.mixin.event.entity;
2+
3+
import org.spongepowered.asm.mixin.Mixin;
4+
import org.spongepowered.asm.mixin.Unique;
5+
import org.spongepowered.asm.mixin.injection.At;
6+
import org.spongepowered.asm.mixin.injection.Redirect;
7+
8+
import net.minecraft.entity.EntityData;
9+
import net.minecraft.entity.SpawnType;
10+
import net.minecraft.entity.mob.MobEntity;
11+
import net.minecraft.nbt.CompoundTag;
12+
import net.minecraft.world.IWorld;
13+
import net.minecraft.world.LocalDifficulty;
14+
import net.minecraft.world.SpawnHelper;
15+
import net.minecraft.world.ViewableWorld;
16+
17+
import com.patchworkmc.impl.event.entity.EntityEvents;
18+
19+
@Mixin(SpawnHelper.class)
20+
public class MixinSpawnHelper {
21+
@Unique
22+
private static double playerDistanceStore;
23+
24+
//We re-implement the vanilla logic in the event, disable it here. Also capture the player distance.
25+
@Redirect(method = "spawnEntitiesInChunk", at = @At(value = "INVOKE", target = "net/minecraft/entity/mob/MobEntity.canImmediatelyDespawn(D)Z"))
26+
private static boolean disableVanillaLogicAndCaptureDistance(MobEntity entity, double distFromPlayer) {
27+
playerDistanceStore = distFromPlayer;
28+
return false;
29+
}
30+
31+
@Redirect(method = "spawnEntitiesInChunk", at = @At(value = "INVOKE", target = "net/minecraft/entity/mob/MobEntity.canSpawn(Lnet/minecraft/world/IWorld;Lnet/minecraft/entity/SpawnType;)Z"))
32+
private static boolean hookCheckSpawn(MobEntity entity, IWorld world, SpawnType spawnType) {
33+
return EntityEvents.canEntitySpawnNaturally(entity, entity.world, entity.x, entity.y, entity.x, null, spawnType, playerDistanceStore);
34+
}
35+
36+
@Redirect(method = "spawnEntitiesInChunk", at = @At(value = "INVOKE", target = "net/minecraft/entity/mob/MobEntity.canSpawn(Lnet/minecraft/world/ViewableWorld;)Z"))
37+
private static boolean disableVanillaLogic(MobEntity entity, ViewableWorld world) {
38+
return true;
39+
}
40+
41+
@Redirect(method = "spawnEntitiesInChunk", at = @At(value = "INVOKE", target = "net/minecraft/entity/mob/MobEntity.initialize(Lnet/minecraft/world/IWorld;Lnet/minecraft/world/LocalDifficulty;Lnet/minecraft/entity/SpawnType;Lnet/minecraft/entity/EntityData;Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/entity/EntityData;"))
42+
private static EntityData hookSpecialSpawn(MobEntity entity, IWorld world, LocalDifficulty localDifficulty, SpawnType spawnType, EntityData data, CompoundTag tag) {
43+
if (!EntityEvents.doSpecialSpawn(entity, world, entity.x, entity.y, entity.z, null, spawnType)) {
44+
return entity.initialize(world, localDifficulty, spawnType, data, tag);
45+
} else {
46+
return data;
47+
}
48+
}
49+
}

patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/living/LivingAttackEvent.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
/**
2626
* LivingAttackEvent is fired when a living Entity is attacked.
2727
*
28-
* <p>This event is fired whenever a LivingEntity is attacked in
28+
* <p>This event is fired whenever a {@link LivingEntity} is attacked in
2929
* {@link LivingEntity#damage(DamageSource, float)} and
3030
* {@link net.minecraft.entity.player.PlayerEntity#damage(DamageSource, float)}.</p>
3131
*
3232
* <p>This event is fired via the {@link com.patchworkmc.impl.event.entity.EntityEvents#onLivingAttack(EntityLivingBase, DamageSource, float)}.</p>
3333
*
34-
* <p>{@link #source} contains the DamageSource of the attack.
34+
* <p>{@link #source} contains the {@link DamageSource} of the attack.
3535
* {@link #amount} contains the amount of damage dealt to the entity.</p>
3636
*
3737
* <p>This event is cancellable.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2019, 2019
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package net.minecraftforge.event.entity.living;
21+
22+
import net.minecraft.entity.LivingEntity;
23+
import net.minecraft.entity.damage.DamageSource;
24+
25+
/**
26+
* <p>LivingHurtEvent is fired when an Entity is set to be hurt.
27+
* This event is fired whenever an Entity is hurt in
28+
* {@link LivingEntity#applyDamage(DamageSource, float)} and
29+
* {@link net.minecraft.entity.player.PlayerEntity#applyDamage(DamageSource, float)}.</p>
30+
*
31+
* <p>This event is fired via {@link com.patchworkmc.impl.event.entity.EntityEvents#onLivingHurt(LivingEntity, DamageSource, float)}.</p>
32+
*
33+
* <p>{@link #source} contains the {@link DamageSource} that caused this {@link LivingEntity} to be hurt.
34+
* {@link #amount} contains the amount of damage dealt to the {@link LivingEntity} that was hurt.</p>
35+
*
36+
* <p>This event is cancellable.
37+
* If this event is canceled, the Entity is not hurt.</p>
38+
*
39+
* <p>This event is fired on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}.</p>
40+
*/
41+
public class LivingHurtEvent extends LivingEvent {
42+
private final DamageSource source;
43+
private float amount;
44+
// For EventBus
45+
public LivingHurtEvent() {
46+
this.source = null;
47+
this.amount = 0;
48+
}
49+
50+
public LivingHurtEvent(LivingEntity entity, DamageSource source, float amount) {
51+
super(entity);
52+
this.source = source;
53+
this.amount = amount;
54+
}
55+
56+
public DamageSource getSource() {
57+
return source;
58+
}
59+
60+
public float getAmount() {
61+
return amount;
62+
}
63+
64+
public void setAmount(float amount) {
65+
this.amount = amount;
66+
}
67+
68+
@Override
69+
public boolean isCancelable() {
70+
return true;
71+
}
72+
}

0 commit comments

Comments
 (0)