Skip to content

Commit

Permalink
Port fabric-lifecycle-events-v1
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Jun 14, 2024
1 parent e053909 commit 7906a12
Show file tree
Hide file tree
Showing 18 changed files with 182 additions and 428 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,57 @@
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.impl.event.lifecycle.LoadedChunksCache;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.level.ChunkEvent;
import net.neoforged.neoforge.event.tick.LevelTickEvent;

public final class ClientLifecycleEventsImpl implements ClientModInitializer {
@Override
public void onInitializeClient() {
// Part of impl for block entity events
ClientChunkEvents.CHUNK_LOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markLoaded(chunk);
});
@Override
public void onInitializeClient() {
// Part of impl for block entity events
ClientChunkEvents.CHUNK_LOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markLoaded(chunk);
});

ClientChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markUnloaded(chunk);
});
ClientChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markUnloaded(chunk);
});

ClientChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
for (BlockEntity blockEntity : chunk.getBlockEntities().values()) {
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, world);
}
});
}
ClientChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
for (BlockEntity blockEntity : chunk.getBlockEntities().values()) {
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, world);
}
});

// Sinytra impl
NeoForge.EVENT_BUS.addListener(ChunkEvent.Load.class, ev -> {
if (ev.getLevel() instanceof ClientLevel cw && ev.getChunk() instanceof LevelChunk wc) {
ClientChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(cw, wc);
}
});
NeoForge.EVENT_BUS.addListener(ChunkEvent.Unload.class, ev -> {
if (ev.getLevel() instanceof ClientLevel cw && ev.getChunk() instanceof LevelChunk wc) {
ClientChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(cw, wc);
}
});
NeoForge.EVENT_BUS.addListener(ClientTickEvent.Pre.class, ev -> ClientTickEvents.START_CLIENT_TICK.invoker().onStartTick(Minecraft.getInstance()));
NeoForge.EVENT_BUS.addListener(ClientTickEvent.Post.class, ev -> ClientTickEvents.END_CLIENT_TICK.invoker().onEndTick(Minecraft.getInstance()));
NeoForge.EVENT_BUS.addListener(LevelTickEvent.Pre.class, ev -> {
if (ev.getLevel() instanceof ClientLevel cw) {
ClientTickEvents.START_WORLD_TICK.invoker().onStartTick(cw);
}
});
NeoForge.EVENT_BUS.addListener(LevelTickEvent.Post.class, ev -> {
if (ev.getLevel() instanceof ClientLevel cw) {
ClientTickEvents.END_WORLD_TICK.invoker().onEndTick(cw);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,13 @@ public abstract class ClientChunkManagerMixin {
@Shadow
private ClientLevel level;

@Inject(method = "replaceWithPacketData", at = @At("TAIL"))
private void onChunkLoad(int x, int z, FriendlyByteBuf packetByteBuf, CompoundTag nbtCompound, Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> consumer, CallbackInfoReturnable<LevelChunk> info) {
ClientChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(this.level, info.getReturnValue());
}

@Inject(method = "replaceWithPacketData", at = @At(value = "NEW", target = "net/minecraft/world/level/chunk/LevelChunk", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD)
private void onChunkUnload(int x, int z, FriendlyByteBuf buf, CompoundTag tag, Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> consumer, CallbackInfoReturnable<LevelChunk> info, int index, LevelChunk worldChunk, ChunkPos chunkPos) {
if (worldChunk != null) {
ClientChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(this.level, worldChunk);
}
}

@Inject(method = "drop", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientChunkCache$Storage;replace(ILnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/chunk/LevelChunk;)Lnet/minecraft/world/level/chunk/LevelChunk;"), locals = LocalCapture.CAPTURE_FAILHARD)
private void onChunkUnload(ChunkPos pos, CallbackInfo ci, int i, LevelChunk chunk) {
ClientChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(this.level, chunk);
}

@Inject(
method = "updateViewRadius",
at = @At(
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,6 @@

@Mixin(Minecraft.class)
public abstract class MinecraftClientMixin {
@Inject(at = @At("HEAD"), method = "tick")
private void onStartTick(CallbackInfo info) {
ClientTickEvents.START_CLIENT_TICK.invoker().onStartTick((Minecraft) (Object) this);
}

@Inject(at = @At("RETURN"), method = "tick")
private void onEndTick(CallbackInfo info) {
ClientTickEvents.END_CLIENT_TICK.invoker().onEndTick((Minecraft) (Object) this);
}

@Inject(at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;info(Ljava/lang/String;)V", shift = At.Shift.AFTER, remap = false), method = "destroy")
private void onStopping(CallbackInfo ci) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.llamalad7.mixinextras.sugar.Local;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
Expand Down Expand Up @@ -61,10 +62,23 @@ private void onRemoveBlockEntity(BlockEntity blockEntity, CallbackInfo info, @Lo
}

// Use the slice to not redirect codepath where block entity is loaded
@Redirect(method = "getBlockEntity(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk$EntityCreationType;)Lnet/minecraft/world/level/block/entity/BlockEntity;", at = @At(value = "INVOKE", target = "Ljava/util/Map;remove(Ljava/lang/Object;)Ljava/lang/Object;"),
slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;createBlockEntity(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/entity/BlockEntity;")))
@Redirect(
method = "getBlockEntity(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk$EntityCreationType;)Lnet/minecraft/world/level/block/entity/BlockEntity;",
at = @At(
value = "INVOKE",
target = "Ljava/util/Map;remove(Ljava/lang/Object;)Ljava/lang/Object;"
),
slice = @Slice(
to = @At(
value = "FIELD",
target = "Lnet/minecraft/world/level/chunk/LevelChunk;pendingBlockEntities:Ljava/util/Map;",
opcode = Opcodes.GETFIELD
)
)
)
private <K, V> Object onRemoveBlockEntity(Map<K, V> map, K key) {
@Nullable final V removed = map.remove(key);
@Nullable
final V removed = map.remove(key);

if (removed != null) {
if (this.getLevel() instanceof ServerLevel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"client": [
"ClientChunkManagerMixin",
"ClientPlayNetworkHandlerMixin",
"ClientTagLoaderMixin",

"ClientWorldClientEntityHandlerMixin",
"ClientWorldMixin",

"MinecraftClientMixin",
"WorldChunkMixin"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,101 @@
package net.fabricmc.fabric.impl.event.lifecycle;

import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.*;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.OnDatapackSyncEvent;
import net.neoforged.neoforge.event.TagsUpdatedEvent;
import net.neoforged.neoforge.event.entity.living.LivingEquipmentChangeEvent;
import net.neoforged.neoforge.event.level.ChunkEvent;
import net.neoforged.neoforge.event.level.LevelEvent;
import net.neoforged.neoforge.event.server.ServerAboutToStartEvent;
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import net.neoforged.neoforge.event.server.ServerStoppedEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import net.neoforged.neoforge.event.tick.LevelTickEvent;
import net.neoforged.neoforge.event.tick.ServerTickEvent;

public final class LifecycleEventsImpl implements ModInitializer {
@Override
public void onInitialize() {
// Part of impl for block entity events
ServerChunkEvents.CHUNK_LOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markLoaded(chunk);
});

ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markUnloaded(chunk);
});

// Fire block entity unload events.
// This handles the edge case where going through a portal will cause block entities to unload without warning.
ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
for (BlockEntity blockEntity : chunk.getBlockEntities().values()) {
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, world);
}
});

// We use the world unload event so worlds that are dynamically hot(un)loaded get (block) entity unload events fired when shut down.
ServerWorldEvents.UNLOAD.register((server, world) -> {
for (LevelChunk chunk : ((LoadedChunksCache) world).fabric_getLoadedChunks()) {
for (BlockEntity blockEntity : chunk.getBlockEntities().values()) {
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, world);
}
}

for (Entity entity : world.getAllEntities()) {
ServerEntityEvents.ENTITY_UNLOAD.invoker().onUnload(entity, world);
}
});
}
@Override
public void onInitialize() {
// Part of impl for block entity events
ServerChunkEvents.CHUNK_LOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markLoaded(chunk);
});

ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
((LoadedChunksCache) world).fabric_markUnloaded(chunk);
});

// Fire block entity unload events.
// This handles the edge case where going through a portal will cause block entities to unload without warning.
ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> {
for (BlockEntity blockEntity : chunk.getBlockEntities().values()) {
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, world);
}
});

// We use the world unload event so worlds that are dynamically hot(un)loaded get (block) entity unload events fired when shut down.
ServerWorldEvents.UNLOAD.register((server, world) -> {
for (LevelChunk chunk : ((LoadedChunksCache) world).fabric_getLoadedChunks()) {
for (BlockEntity blockEntity : chunk.getBlockEntities().values()) {
ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.invoker().onUnload(blockEntity, world);
}
}

for (Entity entity : world.getAllEntities()) {
ServerEntityEvents.ENTITY_UNLOAD.invoker().onUnload(entity, world);
}
});

// Sinytra impl
NeoForge.EVENT_BUS.addListener(TagsUpdatedEvent.class, ev -> CommonLifecycleEvents.TAGS_LOADED.invoker().onTagsLoaded(ev.getRegistryAccess(), ev.getUpdateCause() == TagsUpdatedEvent.UpdateCause.CLIENT_PACKET_RECEIVED));
NeoForge.EVENT_BUS.addListener(ChunkEvent.Load.class, ev -> {
if (ev.getLevel() instanceof ServerLevel sw && ev.getChunk() instanceof LevelChunk wc) {
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(sw, wc);
}
});
NeoForge.EVENT_BUS.addListener(ChunkEvent.Unload.class, ev -> {
if (ev.getLevel() instanceof ServerLevel sw && ev.getChunk() instanceof LevelChunk wc) {
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(sw, wc);
}
});
NeoForge.EVENT_BUS.addListener(LivingEquipmentChangeEvent.class, ev -> ServerEntityEvents.EQUIPMENT_CHANGE.invoker().onChange(ev.getEntity(), ev.getSlot(), ev.getFrom(), ev.getTo()));
// Server events
NeoForge.EVENT_BUS.addListener(ServerAboutToStartEvent.class, ev -> ServerLifecycleEvents.SERVER_STARTING.invoker().onServerStarting(ev.getServer()));
NeoForge.EVENT_BUS.addListener(ServerStartedEvent.class, ev -> ServerLifecycleEvents.SERVER_STARTED.invoker().onServerStarted(ev.getServer()));
NeoForge.EVENT_BUS.addListener(ServerStoppingEvent.class, ev -> ServerLifecycleEvents.SERVER_STOPPING.invoker().onServerStopping(ev.getServer()));
NeoForge.EVENT_BUS.addListener(ServerStoppedEvent.class, ev -> ServerLifecycleEvents.SERVER_STOPPED.invoker().onServerStopped(ev.getServer()));
NeoForge.EVENT_BUS.addListener(OnDatapackSyncEvent.class, ev -> {
if (ev.getPlayer() != null) {
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.invoker().onSyncDataPackContents(ev.getPlayer(), true);
} else {
for (ServerPlayer player : ev.getPlayerList().getPlayers()) {
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.invoker().onSyncDataPackContents(player, false);
}
}
});
NeoForge.EVENT_BUS.addListener(ServerTickEvent.Pre.class, ev -> ServerTickEvents.START_SERVER_TICK.invoker().onStartTick(ev.getServer()));
NeoForge.EVENT_BUS.addListener(ServerTickEvent.Post.class, ev -> ServerTickEvents.END_SERVER_TICK.invoker().onEndTick(ev.getServer()));
NeoForge.EVENT_BUS.addListener(LevelTickEvent.Post.class, ev -> {
if (ev.getLevel() instanceof ServerLevel sw) {
ServerTickEvents.END_WORLD_TICK.invoker().onEndTick(sw);
}
});
NeoForge.EVENT_BUS.addListener(LevelEvent.Load.class, ev -> {
if (ev.getLevel() instanceof ServerLevel sw) {
ServerWorldEvents.LOAD.invoker().onWorldLoad(sw.getServer(), sw);
}
});
NeoForge.EVENT_BUS.addListener(LevelEvent.Unload.class, ev -> {
if (ev.getLevel() instanceof ServerLevel sw) {
ServerWorldEvents.UNLOAD.invoker().onWorldUnload(sw.getServer(), sw);
}
});
}
}
Loading

0 comments on commit 7906a12

Please sign in to comment.