Skip to content

Commit 8a8c79e

Browse files
committed
LivingDeathEventWrapper LevelEventWrapper
1 parent 6e9d35f commit 8a8c79e

17 files changed

Lines changed: 721 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.github.lounode.eventwrapper.event.entity.living;
2+
3+
import net.minecraft.server.level.ServerPlayer;
4+
import net.minecraft.world.damagesource.DamageSource;
5+
import net.minecraft.world.entity.LivingEntity;
6+
import net.minecraft.world.entity.player.Player;
7+
8+
9+
import io.github.lounode.eventwrapper.eventbus.api.Cancelable;
10+
11+
/**
12+
* LivingDeathEvent is fired when an Entity dies. <br>
13+
* This event is fired whenever an Entity dies in
14+
* {@link LivingEntity#die(DamageSource)},
15+
* {@link Player#die(DamageSource)}, and
16+
* {@link ServerPlayer#die(DamageSource)}. <br>
17+
* <br>
18+
* {@link #source} contains the DamageSource that caused the entity to die. <br>
19+
* <br>
20+
* This event is {@link Cancelable}.<br>
21+
* If this event is canceled, the Entity does not die.<br>
22+
**/
23+
@Cancelable
24+
public class LivingDeathEventWrapper extends LivingEventWrapper {
25+
private final DamageSource source;
26+
27+
public LivingDeathEventWrapper(LivingEntity entity, DamageSource source) {
28+
super(entity);
29+
this.source = source;
30+
}
31+
32+
public DamageSource getSource() {
33+
return source;
34+
}
35+
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package io.github.lounode.eventwrapper.event.level;
2+
3+
import net.minecraft.client.Minecraft;
4+
import net.minecraft.client.gui.screens.Screen;
5+
import net.minecraft.client.multiplayer.ClientLevel;
6+
import net.minecraft.core.BlockPos;
7+
import net.minecraft.server.MinecraftServer;
8+
import net.minecraft.server.level.ServerLevel;
9+
import net.minecraft.util.ProgressListener;
10+
import net.minecraft.util.random.WeightedRandomList;
11+
import net.minecraft.world.entity.MobCategory;
12+
import net.minecraft.world.level.LevelAccessor;
13+
import net.minecraft.world.level.biome.MobSpawnSettings;
14+
import net.minecraft.world.level.storage.ServerLevelData;
15+
16+
import java.util.ArrayList;
17+
import java.util.Collections;
18+
import java.util.List;
19+
20+
import io.github.lounode.eventwrapper.eventbus.api.Cancelable;
21+
import io.github.lounode.eventwrapper.eventbus.api.EventWrapper;
22+
23+
/**
24+
* This event is fired whenever an event involving a {@link LevelAccessor} occurs.
25+
* <p>
26+
* All children of this event are fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}.
27+
*/
28+
public class LevelEventWrapper extends EventWrapper {
29+
private final LevelAccessor level;
30+
31+
public LevelEventWrapper(LevelAccessor level) {
32+
this.level = level;
33+
}
34+
35+
/**
36+
* {@return the level this event is affecting}
37+
*/
38+
public LevelAccessor getLevel() {
39+
return level;
40+
}
41+
42+
/**
43+
* This event is fired whenever a level loads.
44+
* This event is fired whenever a level loads in ClientLevel's constructor and
45+
* {@literal MinecraftServer#createLevels(ChunkProgressListener)}.
46+
* <p>
47+
* This event is not {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}.
48+
* <p>
49+
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}
50+
* on both logical sides.
51+
**/
52+
public static class Load extends LevelEventWrapper {
53+
public Load(LevelAccessor level) {
54+
super(level);
55+
}
56+
}
57+
58+
/**
59+
* This event is fired whenever a level unloads.
60+
* This event is fired whenever a level unloads in
61+
* {@link Minecraft#setLevel(ClientLevel)},
62+
* {@link MinecraftServer#stopServer()},
63+
* {@link Minecraft#clearLevel(Screen)}, and
64+
* {@link ForgeInternalHandler#onDimensionUnload(net.minecraftforge.event.level.LevelEvent.Unload)}.
65+
* <p>
66+
* This event is not {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}.
67+
* <p>
68+
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}
69+
* on both logical sides.
70+
**/
71+
public static class Unload extends LevelEventWrapper {
72+
public Unload(LevelAccessor level) {
73+
super(level);
74+
}
75+
}
76+
77+
/**
78+
* This event fires whenever a level is saved.
79+
* This event is fired when a level is saved in
80+
* {@link ServerLevel#save(ProgressListener, boolean, boolean)}.
81+
* <p>
82+
* This event is not {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}.
83+
* <p>
84+
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}
85+
* only on the {@linkplain LogicalSide#SERVER logical server}.
86+
**/
87+
public static class Save extends LevelEventWrapper {
88+
public Save(LevelAccessor level) {
89+
super(level);
90+
}
91+
}
92+
93+
/**
94+
* This event fires whenever a {@link ServerLevel} is initialized for the first time
95+
* and a spawn position needs to be chosen.
96+
* <p>
97+
* This event is {@linkplain Cancelable cancellable} and does not {@linkplain HasResult have a result}.
98+
* If the event is canceled, the vanilla logic to choose a spawn position will be skipped.
99+
* <p>
100+
* This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}
101+
* only on the {@linkplain LogicalSide#SERVER logical server}.
102+
*
103+
* @see ServerLevelData#isInitialized()
104+
*/
105+
@Cancelable
106+
public static class CreateSpawnPosition extends LevelEventWrapper {
107+
private final ServerLevelData settings;
108+
109+
public CreateSpawnPosition(LevelAccessor level, ServerLevelData settings) {
110+
super(level);
111+
this.settings = settings;
112+
}
113+
114+
public ServerLevelData getSettings() {
115+
return settings;
116+
}
117+
}
118+
119+
/**
120+
* Fired when building a list of all possible entities that can spawn at the specified location.
121+
*
122+
* <p>
123+
* If an entry is added to the list, it needs to be a globally unique instance.
124+
* </p>
125+
*
126+
* The event is called in {@link net.minecraft.world.level.NaturalSpawner#mobsAt(ServerLevel,
127+
* StructureManager, ChunkGenerator, MobCategory, RandomSource, BlockPos)}.
128+
* </p>
129+
*
130+
* <p>
131+
* This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}.
132+
* Canceling the event will result in an empty list, meaning no entity will be spawned.
133+
* </p>
134+
*/
135+
@Cancelable
136+
public static class PotentialSpawns extends LevelEventWrapper {
137+
private final MobCategory mobcategory;
138+
private final BlockPos pos;
139+
private final List<MobSpawnSettings.SpawnerData> list;
140+
private final List<MobSpawnSettings.SpawnerData> view;
141+
142+
public PotentialSpawns(LevelAccessor level, MobCategory category, BlockPos pos, WeightedRandomList<MobSpawnSettings.SpawnerData> oldList) {
143+
super(level);
144+
this.pos = pos;
145+
this.mobcategory = category;
146+
if (!oldList.isEmpty()) {
147+
this.list = new ArrayList<>(oldList.unwrap());
148+
} else {
149+
this.list = new ArrayList<>();
150+
}
151+
152+
this.view = Collections.unmodifiableList(list);
153+
}
154+
155+
/**
156+
* {@return the category of the mobs in the spawn list.}
157+
*/
158+
public MobCategory getMobCategory() {
159+
return mobcategory;
160+
}
161+
162+
/**
163+
* {@return the block position where the chosen mob will be spawned.}
164+
*/
165+
public BlockPos getPos() {
166+
return pos;
167+
}
168+
169+
/**
170+
* {@return the list of mobs that can potentially be spawned.}
171+
*/
172+
public List<MobSpawnSettings.SpawnerData> getSpawnerDataList() {
173+
return view;
174+
}
175+
176+
/**
177+
* Appends a SpawnerData entry to the spawn list.
178+
*
179+
* @param data SpawnerData entry to be appended to the spawn list.
180+
*/
181+
public void addSpawnerData(MobSpawnSettings.SpawnerData data) {
182+
list.add(data);
183+
}
184+
185+
/**
186+
* Removes a SpawnerData entry from the spawn list.
187+
*
188+
* @param data SpawnerData entry to be removed from the spawn list.
189+
*
190+
* {@return {@code true} if the spawn list contained the specified element.}
191+
*/
192+
public boolean removeSpawnerData(MobSpawnSettings.SpawnerData data) {
193+
return list.remove(data);
194+
}
195+
}
196+
}

fabric/src/main/java/io/github/lounode/eventwrapper/fabric/EventWrapperHooks.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,27 @@
1111
import net.minecraft.server.MinecraftServer;
1212
import net.minecraft.sounds.SoundEvent;
1313
import net.minecraft.sounds.SoundSource;
14+
import net.minecraft.util.random.WeightedRandomList;
1415
import net.minecraft.world.Container;
1516
import net.minecraft.world.InteractionHand;
1617
import net.minecraft.world.InteractionResult;
18+
import net.minecraft.world.damagesource.DamageSource;
1719
import net.minecraft.world.effect.MobEffectInstance;
1820
import net.minecraft.world.entity.Entity;
1921
import net.minecraft.world.entity.LivingEntity;
22+
import net.minecraft.world.entity.MobCategory;
2023
import net.minecraft.world.entity.item.ItemEntity;
2124
import net.minecraft.world.entity.player.Player;
2225
import net.minecraft.world.item.Item;
2326
import net.minecraft.world.item.ItemStack;
2427
import net.minecraft.world.item.crafting.RecipeType;
2528
import net.minecraft.world.level.GameType;
2629
import net.minecraft.world.level.Level;
30+
import net.minecraft.world.level.LevelAccessor;
31+
import net.minecraft.world.level.biome.MobSpawnSettings;
2732
import net.minecraft.world.level.block.state.BlockState;
2833
import net.minecraft.world.level.storage.PlayerDataStorage;
34+
import net.minecraft.world.level.storage.ServerLevelData;
2935
import net.minecraft.world.phys.BlockHitResult;
3036
import net.minecraft.world.phys.HitResult;
3137
import net.minecraft.world.phys.Vec3;
@@ -37,12 +43,14 @@
3743

3844
import io.github.lounode.eventwrapper.EventsWrapper;
3945
import io.github.lounode.eventwrapper.event.PlayLevelSoundEventWrapper;
46+
import io.github.lounode.eventwrapper.event.entity.living.LivingDeathEventWrapper;
4047
import io.github.lounode.eventwrapper.event.entity.living.MobEffectEventWrapper;
4148
import io.github.lounode.eventwrapper.event.entity.player.AnvilRepairEventWrapper;
4249
import io.github.lounode.eventwrapper.event.entity.player.EntityItemPickupEventWrapper;
4350
import io.github.lounode.eventwrapper.event.entity.player.PlayerEventWrapper;
4451
import io.github.lounode.eventwrapper.event.entity.player.PlayerInteractEventWrapper;
4552
import io.github.lounode.eventwrapper.event.furnace.FurnaceFuelBurnTimeEventWrapper;
53+
import io.github.lounode.eventwrapper.event.level.LevelEventWrapper;
4654
import io.github.lounode.eventwrapper.event.server.*;
4755
import io.github.lounode.eventwrapper.eventbus.api.EventWrapper;
4856

@@ -257,4 +265,35 @@ public static PlayLevelSoundEventWrapper.AtPosition onPlaySoundAtPosition(Level
257265
EventsWrapper.post(event);
258266
return event;
259267
}
268+
269+
public static boolean onLivingDeath(LivingEntity entity, DamageSource src) {
270+
var event = new LivingDeathEventWrapper(entity, src);
271+
EventsWrapper.post(event);
272+
return event.isCanceled();
273+
}
274+
275+
public static void onLevelLoad(Level level) {
276+
EventsWrapper.post(new LevelEventWrapper.Load(level));
277+
}
278+
279+
public static void onLevelUnload(Level level) {
280+
EventsWrapper.post(new LevelEventWrapper.Unload(level));
281+
}
282+
283+
public static void onLevelSave(Level level) {
284+
EventsWrapper.post(new LevelEventWrapper.Save(level));
285+
}
286+
287+
public static boolean onCreateWorldSpawn(Level level, ServerLevelData settings) {
288+
var event = new LevelEventWrapper.CreateSpawnPosition(level, settings);
289+
return event.isCanceled();
290+
}
291+
292+
public static WeightedRandomList<MobSpawnSettings.SpawnerData> getPotentialSpawns(LevelAccessor level, MobCategory category, BlockPos pos, WeightedRandomList<MobSpawnSettings.SpawnerData> oldList) {
293+
var event = new LevelEventWrapper.PotentialSpawns(level, category, pos, oldList);
294+
if (event.isCanceled()) {
295+
return WeightedRandomList.create();
296+
}
297+
return WeightedRandomList.create(event.getSpawnerDataList());
298+
}
260299
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.github.lounode.eventwrapper.fabric.mixin.eventposter.entity.living.living_death_event;
2+
3+
import net.minecraft.world.damagesource.DamageSource;
4+
import net.minecraft.world.entity.LivingEntity;
5+
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.Inject;
9+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
10+
11+
12+
import io.github.lounode.eventwrapper.fabric.EventWrapperHooks;
13+
14+
@Mixin(LivingEntity.class)
15+
public class EventPosterLivingEntity {
16+
17+
@Inject(
18+
method = "die",
19+
at = @At("HEAD"),
20+
cancellable = true
21+
)
22+
private void onDie(DamageSource damageSource, CallbackInfo ci) {
23+
boolean cancel = EventWrapperHooks.onLivingDeath((LivingEntity) (Object) this, damageSource);
24+
if (cancel) {
25+
ci.cancel();
26+
}
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.github.lounode.eventwrapper.fabric.mixin.eventposter.entity.living.living_death_event;
2+
3+
import net.minecraft.world.damagesource.DamageSource;
4+
import net.minecraft.world.entity.player.Player;
5+
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.Inject;
9+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
10+
11+
12+
import io.github.lounode.eventwrapper.fabric.EventWrapperHooks;
13+
14+
@Mixin(Player.class)
15+
public class EventPosterPlayer {
16+
17+
@Inject(
18+
method = "die",
19+
at = @At("HEAD"),
20+
cancellable = true
21+
)
22+
private void onPlayerDie(DamageSource damageSource, CallbackInfo ci) {
23+
boolean cancel = EventWrapperHooks.onLivingDeath((Player) (Object) this, damageSource);
24+
if (cancel) {
25+
ci.cancel();
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)