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

Commit 31262e4

Browse files
committed
Merge branch 'nuclearfarts'
# Conflicts: # patchwork-events-entity/src/main/java/com/patchworkmc/impl/event/entity/EntityEvents.java # patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinLivingEntity.java # patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinPlayerEntity.java # patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinServerPlayerEntity.java # patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json
2 parents 07cec08 + 092b7b9 commit 31262e4

11 files changed

Lines changed: 610 additions & 13 deletions

File tree

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

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,29 @@
2121

2222
import net.minecraftforge.common.MinecraftForge;
2323
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
24+
import net.minecraftforge.event.entity.living.LivingAttackEvent;
2425
import net.minecraftforge.event.entity.living.LivingDeathEvent;
26+
import net.minecraftforge.event.entity.living.LivingHurtEvent;
27+
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
2528
import net.minecraftforge.event.entity.living.LivingEvent;
2629
import net.minecraftforge.event.entity.player.PlayerEvent;
2730
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
2831
import net.minecraftforge.eventbus.api.Event;
29-
import org.apache.logging.log4j.LogManager;
32+
import net.minecraftforge.eventbus.api.Event.Result;
3033
import org.apache.logging.log4j.Logger;
34+
import org.apache.logging.log4j.LogManager;
3135

3236
import net.minecraft.entity.Entity;
3337
import net.minecraft.entity.LivingEntity;
38+
import net.minecraft.entity.SpawnType;
3439
import net.minecraft.entity.damage.DamageSource;
40+
import net.minecraft.entity.mob.MobEntity;
3541
import net.minecraft.entity.player.PlayerEntity;
3642
import net.minecraft.server.network.ServerPlayerEntity;
3743
import net.minecraft.util.ActionResult;
3844
import net.minecraft.util.Hand;
45+
import net.minecraft.world.IWorld;
46+
import net.minecraft.world.MobSpawnerLogic;
3947
import net.minecraft.world.World;
4048

4149
import net.fabricmc.api.ModInitializer;
@@ -70,6 +78,49 @@ public static void onPlayerLoggedIn(ServerPlayerEntity playerEntity) {
7078
MinecraftForge.EVENT_BUS.post(new PlayerEvent.PlayerLoggedInEvent(playerEntity));
7179
}
7280

81+
public static boolean onLivingAttack(LivingEntity entity, DamageSource src, float damage) {
82+
return MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, damage));
83+
}
84+
85+
public static float onLivingHurt(LivingEntity entity, DamageSource src, float damage) {
86+
LivingHurtEvent event = new LivingHurtEvent(entity, src, damage);
87+
return MinecraftForge.EVENT_BUS.post(event) ? 0 : event.getAmount();
88+
}
89+
90+
public static Result canEntitySpawn(MobEntity entity, IWorld world, double x, double y, double z, MobSpawnerLogic spawner, SpawnType spawnType) {
91+
if (entity == null) {
92+
return Result.DEFAULT;
93+
}
94+
95+
LivingSpawnEvent.CheckSpawn event = new LivingSpawnEvent.CheckSpawn(entity, world, x, y, z, spawner, spawnType);
96+
MinecraftForge.EVENT_BUS.post(event);
97+
return event.getResult();
98+
}
99+
100+
public static boolean canEntitySpawnFromSpawner(MobEntity entity, World world, double x, double y, double z, MobSpawnerLogic spawner) {
101+
Result result = canEntitySpawn(entity, world, x, y, z, spawner, SpawnType.SPAWNER);
102+
103+
if (result == Result.DEFAULT) {
104+
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
105+
} else {
106+
return result == Result.ALLOW;
107+
}
108+
}
109+
110+
public static boolean canEntitySpawnNaturally(MobEntity entity, IWorld world, double x, double y, double z, MobSpawnerLogic spawner, SpawnType spawnType, double sqDistanceFromPlayer) {
111+
Result result = canEntitySpawn(entity, world, x, y, z, spawner, spawnType);
112+
113+
if (result == Result.DEFAULT) {
114+
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
115+
} else {
116+
return result == Result.ALLOW;
117+
}
118+
}
119+
120+
public static boolean doSpecialSpawn(MobEntity entity, IWorld world, double x, double y, double z, MobSpawnerLogic spawner, SpawnType spawnType) {
121+
return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z, spawner, spawnType));
122+
}
123+
73124
@Override
74125
public void onInitialize() {
75126
UseItemCallback.EVENT.register((player, world, hand) -> {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 com.patchworkmc.mixin.event.entity;
21+
22+
import org.spongepowered.asm.mixin.Mixin;
23+
import org.spongepowered.asm.mixin.injection.At;
24+
import org.spongepowered.asm.mixin.injection.Inject;
25+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
26+
27+
import net.minecraft.client.network.ClientPlayerEntity;
28+
import net.minecraft.entity.LivingEntity;
29+
import net.minecraft.entity.damage.DamageSource;
30+
31+
import com.patchworkmc.impl.event.entity.EntityEvents;
32+
33+
@Mixin(ClientPlayerEntity.class)
34+
public class MixinClientPlayerEntity {
35+
@Inject(method = "damage", at = @At("HEAD"), cancellable = true)
36+
private void hookDamage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> callback) {
37+
LivingEntity entity = (LivingEntity) (Object) this;
38+
39+
if (EntityEvents.onLivingAttack(entity, source, amount)) {
40+
callback.setReturnValue(false);
41+
}
42+
}
43+
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
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;
27+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
2628

2729
import net.minecraft.entity.LivingEntity;
2830
import net.minecraft.entity.damage.DamageSource;
@@ -49,4 +51,28 @@ private void hookUpdate(CallbackInfo callback) {
4951
callback.cancel();
5052
}
5153
}
54+
55+
@Inject(method = "damage", at = @At("HEAD"), cancellable = true)
56+
private void hookDamage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> callback) {
57+
LivingEntity entity = (LivingEntity) (Object) this;
58+
59+
if (EntityEvents.onLivingAttack(entity, source, amount)) {
60+
callback.setReturnValue(false);
61+
}
62+
}
63+
64+
// 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
65+
@ModifyVariable(method = "applyDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.applyArmorToDamage(Lnet/minecraft/entity/damage/DamageSource;F)F", shift = At.Shift.BEFORE))
66+
private float hookApplyDamageForHurtEvent(float damage, DamageSource source) {
67+
LivingEntity entity = (LivingEntity) (Object) this;
68+
69+
return EntityEvents.onLivingHurt(entity, source, damage);
70+
}
71+
72+
@Inject(method = "applyDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.applyArmorToDamage(Lnet/minecraft/entity/damage/DamageSource;F)F"), cancellable = true)
73+
private void hookApplyDamageForHurtEventCancel(DamageSource source, float damage, CallbackInfo info) {
74+
if (damage <= 0) {
75+
info.cancel();
76+
}
77+
}
5278
}
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+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 com.patchworkmc.mixin.event.entity;
21+
22+
import org.spongepowered.asm.mixin.Mixin;
23+
import org.spongepowered.asm.mixin.injection.At;
24+
import org.spongepowered.asm.mixin.injection.Inject;
25+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
26+
27+
import net.minecraft.client.network.OtherClientPlayerEntity;
28+
import net.minecraft.entity.LivingEntity;
29+
import net.minecraft.entity.damage.DamageSource;
30+
31+
import com.patchworkmc.impl.event.entity.EntityEvents;
32+
33+
@Mixin(OtherClientPlayerEntity.class)
34+
public class MixinOtherClientPlayerEntity {
35+
@Inject(method = "damage", at = @At("HEAD"), cancellable = true)
36+
private void hookDamage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> callback) {
37+
LivingEntity entity = (LivingEntity) (Object) this;
38+
39+
if (EntityEvents.onLivingAttack(entity, source, amount)) {
40+
callback.setReturnValue(false);
41+
}
42+
}
43+
}

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

Lines changed: 35 additions & 10 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

@@ -36,16 +37,6 @@
3637

3738
@Mixin(PlayerEntity.class)
3839
public class MixinPlayerEntity {
39-
// TODO: Forge bug: PlayerEntity calls its super, so this event gets fired twice on the client.
40-
@Inject(method = "onDeath", at = @At("HEAD"), cancellable = true)
41-
private void hookDeath(DamageSource source, CallbackInfo callback) {
42-
LivingEntity entity = (LivingEntity) (Object) this;
43-
44-
if (EntityEvents.onLivingDeath(entity, source)) {
45-
callback.cancel();
46-
}
47-
}
48-
4940
@Inject(method = "interact", at = @At("HEAD"), cancellable = true)
5041
private void hookInteractEntity(Entity entity, Hand hand, CallbackInfoReturnable<ActionResult> callback) {
5142
PlayerEntity player = (PlayerEntity) (Object) this;
@@ -73,4 +64,38 @@ private void hookInteractEntity(Entity entity, Hand hand, CallbackInfoReturnable
7364
}
7465
}
7566
}
67+
68+
// TODO: Forge bug: PlayerEntity calls its super, so this event gets fired twice on the client.
69+
@Inject(method = "onDeath", at = @At("HEAD"), cancellable = true)
70+
private void hookDeath(DamageSource source, CallbackInfo callback) {
71+
LivingEntity entity = (LivingEntity) (Object) this;
72+
73+
if (EntityEvents.onLivingDeath(entity, source)) {
74+
callback.cancel();
75+
}
76+
}
77+
78+
@Inject(method = "damage", at = @At("HEAD"), cancellable = true)
79+
private void hookDamage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> callback) {
80+
LivingEntity entity = (LivingEntity) (Object) this;
81+
82+
if (EntityEvents.onLivingAttack(entity, source, amount)) {
83+
callback.setReturnValue(false);
84+
}
85+
}
86+
87+
// 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
88+
@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))
89+
private float hookApplyDamageForHurtEvent(float damage, DamageSource source) {
90+
LivingEntity entity = (LivingEntity) (Object) this;
91+
92+
return EntityEvents.onLivingHurt(entity, source, damage);
93+
}
94+
95+
@Inject(method = "applyDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/player/PlayerEntity.applyArmorToDamage(Lnet/minecraft/entity/damage/DamageSource;F)F"), cancellable = true)
96+
private void hookApplyDamageForHurtEventCancel(DamageSource source, float damage, CallbackInfo info) {
97+
if (damage <= 0) {
98+
info.cancel();
99+
}
100+
}
76101
}
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+
}

0 commit comments

Comments
 (0)