Skip to content

Commit

Permalink
lifecycle-events done
Browse files Browse the repository at this point in the history
  • Loading branch information
TexBlock committed Aug 5, 2024
1 parent 3c462a3 commit eccb4ae
Show file tree
Hide file tree
Showing 16 changed files with 465 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package band.kessoku.lib.events.lifecycle.api.client;

import band.kessoku.lib.event.api.Event;

import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.world.ClientWorld;

public class ClientBlockEntityEvent {

/**
* Called when a BlockEntity is loaded into a ClientWorld.
*
* <p>When this event is called, the block entity is already in the world.
* However, its data might not be loaded yet, so don't rely on it.
*/
public static final Event<Loaded> LOADED = Event.of(loadeds -> (blockEntity, world) -> {
for (Loaded loaded : loadeds) {
loaded.onLoaded(blockEntity, world);
}
});

/**
* Called when a BlockEntity is about to be unloaded from a ClientWorld.
*
* <p>When this event is called, the block entity is still present on the world.
*/
public static final Event<Unloaded> UNLOADED = Event.of(unloadeds -> (blockEntity, world) -> {
for (Unloaded unloaded : unloadeds) {
unloaded.onUnloaded(blockEntity, world);
}
});

@FunctionalInterface
public interface Loaded {
void onLoaded(BlockEntity blockEntity, ClientWorld world);
}

@FunctionalInterface
public interface Unloaded {
void onUnloaded(BlockEntity blockEntity, ClientWorld world);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package band.kessoku.lib.events.lifecycle.api.client;

import band.kessoku.lib.event.api.Event;

import net.minecraft.client.world.ClientWorld;
import net.minecraft.world.chunk.WorldChunk;

public class ClientChunkEvent {

/**
* Called when a chunk is loaded into a ClientWorld.
*
* <p>When this event is called, the chunk is already in the world.
*/
public static final Event<Loaded> LOADED = Event.of(loadeds -> (clientWorld, chunk) -> {
for (Loaded callback : loadeds) {
callback.onChunkLoaded(clientWorld, chunk);
}
});

/**
* Called when a chunk is about to be unloaded from a ClientWorld.
*
* <p>When this event is called, the chunk is still present in the world.
*/
public static final Event<Unloaded> UNLOADED = Event.of(unloadeds -> (clientWorld, chunk) -> {
for (Unloaded unloaded : unloadeds) {
unloaded.onChunkUnloaded(clientWorld, chunk);
}
});

@FunctionalInterface
public interface Loaded {
void onChunkLoaded(ClientWorld world, WorldChunk chunk);
}

@FunctionalInterface
public interface Unloaded {
void onChunkUnloaded(ClientWorld world, WorldChunk chunk);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package band.kessoku.lib.events.lifecycle.api.client;

import band.kessoku.lib.event.api.Event;

import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;

public class ClientEntityEvent {

/**
* Called when an Entity is loaded into a ClientWorld.
*
* <p>When this event is called, the chunk is already in the world.
*/
public static final Event<Loaded> LOADED = Event.of(loadeds -> (entity, world) -> {
for (Loaded loaded : loadeds) {
loaded.onLoaded(entity, world);
}
});

/**
* Called when an Entity is about to be unloaded from a ClientWorld.
*
* <p>This event is called before the entity is unloaded from the world.
*/
public static final Event<Unloaded> UNLOADED = Event.of(unloadeds -> (entity, world) -> {
for (Unloaded unloaded : unloadeds) {
unloaded.onUnloaded(entity, world);
}
});

@FunctionalInterface
public interface Loaded {
void onLoaded(Entity entity, ClientWorld world);
}

@FunctionalInterface
public interface Unloaded {
void onUnloaded(Entity entity, ClientWorld world);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,4 @@ interface End {
void onEndTick(ClientWorld world);
}
}


}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package band.kessoku.lib.events.lifecycle.impl;

import band.kessoku.lib.events.lifecycle.api.*;
import band.kessoku.lib.events.lifecycle.api.client.ClientLifecycleEvent;
import band.kessoku.lib.events.lifecycle.api.client.ClientTickEvent;
import band.kessoku.lib.events.lifecycle.api.client.*;

import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.*;
import net.fabricmc.fabric.api.event.lifecycle.v1.*;

public class KessokuLifecycleEventsImplFabric {
Expand All @@ -19,6 +17,15 @@ public static void registerClientEvents() {
ClientTickEvents.END_CLIENT_TICK.register(client -> ClientTickEvent.END_CLIENT_TICK.invoker().onEndTick(client));
ClientTickEvents.START_WORLD_TICK.register(world -> ClientTickEvent.START_WORLD_TICK.invoker().onStartTick(world));
ClientTickEvents.END_WORLD_TICK.register(world -> ClientTickEvent.END_WORLD_TICK.invoker().onEndTick(world));

ClientEntityEvents.ENTITY_LOAD.register((entity, world) -> ClientEntityEvent.LOADED.invoker().onLoaded(entity, world));
ClientEntityEvents.ENTITY_UNLOAD.register((entity, world) -> ClientEntityEvent.UNLOADED.invoker().onUnloaded(entity, world));

ClientChunkEvents.CHUNK_LOAD.register((world, chunk) -> ClientChunkEvent.LOADED.invoker().onChunkLoaded(world, chunk));
ClientChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> ClientChunkEvent.UNLOADED.invoker().onChunkUnloaded(world, chunk));

ClientBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> ClientBlockEntityEvent.LOADED.invoker().onLoaded(blockEntity, world));
ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.register((blockEntity, world) -> ClientBlockEntityEvent.UNLOADED.invoker().onUnloaded(blockEntity, world));
}

public static void registerCommonEvents() {
Expand Down
6 changes: 6 additions & 0 deletions lifecycle-events-neo/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ architectury {
neoForge()
}

loom {
neoForge {
setAccessTransformers(files("src/main/resources/META-INF/accesstransformer.cfg"))
}
}

repositories {
maven { url "https://maven.neoforged.net/releases/" }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ public class KessokuLifecycleEventsEntrypoint {
public KessokuLifecycleEventsEntrypoint(IEventBus modEventBus, ModContainer modContainer) {
var forgeEventBus = NeoForge.EVENT_BUS;

KessokuLifecycleEventsImplNeo.registerCommonEvents(modEventBus, forgeEventBus);

KessokuLifecycleEventsImplNeo.registerCommonEvents(forgeEventBus);
if (FMLLoader.getDist().isClient()) {
KessokuLifecycleEventsImplNeo.registerClientEvents(modEventBus, forgeEventBus);
KessokuLifecycleEventsImplNeo.registerClientEvents(forgeEventBus);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
import band.kessoku.lib.event.util.NeoEventUtils;
import band.kessoku.lib.events.lifecycle.api.*;

import band.kessoku.lib.events.lifecycle.api.client.ClientChunkEvent;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;

import net.minecraft.world.chunk.WorldChunk;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.client.event.ClientTickEvent;
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.ServerStartedEvent;
import net.neoforged.neoforge.event.server.ServerStartingEvent;
Expand All @@ -21,9 +24,20 @@
import net.neoforged.neoforge.event.tick.LevelTickEvent;

public class KessokuLifecycleEventsImplNeo {
public static void registerClientEvents(IEventBus modEventBus, IEventBus forgeEventBus) {
public static void registerClientEvents(IEventBus forgeEventBus) {
KessokuLifecycleEventsImpl.clientInit();

NeoEventUtils.registerEvent(forgeEventBus, ChunkEvent.Load.class, event -> {
if (event.getLevel() instanceof ClientWorld world && event.getChunk() instanceof WorldChunk chunk) {
ClientChunkEvent.LOADED.invoker().onChunkLoaded(world, chunk);
}
});
NeoEventUtils.registerEvent(forgeEventBus, ChunkEvent.Unload.class, event -> {
if (event.getLevel() instanceof ClientWorld world && event.getChunk() instanceof WorldChunk chunk) {
ClientChunkEvent.UNLOADED.invoker().onChunkUnloaded(world, chunk);
}
});

NeoEventUtils.registerEvent(forgeEventBus, ClientTickEvent.Pre.class, event -> {
band.kessoku.lib.events.lifecycle.api.client.ClientTickEvent.START_CLIENT_TICK.invoker().onStartTick(MinecraftClient.getInstance());
});
Expand All @@ -43,13 +57,24 @@ public static void registerClientEvents(IEventBus modEventBus, IEventBus forgeEv
});
}

public static void registerCommonEvents(IEventBus modEventBus, IEventBus forgeEventBus) {
public static void registerCommonEvents(IEventBus forgeEventBus) {
KessokuLifecycleEventsImpl.init();

NeoEventUtils.registerEvent(forgeEventBus, TagsUpdatedEvent.class, event -> {
LifecycleEvent.TAG_LOADED.invoker().onTagsLoaded(event.getRegistryAccess(), event.getUpdateCause() == TagsUpdatedEvent.UpdateCause.CLIENT_PACKET_RECEIVED);
});

NeoEventUtils.registerEvent(forgeEventBus, ChunkEvent.Load.class, event -> {
if (event.getLevel() instanceof ServerWorld world && event.getChunk() instanceof WorldChunk chunk) {
ServerChunkEvent.LOADED.invoker().onChunkLoaded(world, chunk);
}
});
NeoEventUtils.registerEvent(forgeEventBus, ChunkEvent.Unload.class, event -> {
if (event.getLevel() instanceof ServerWorld world && event.getChunk() instanceof WorldChunk chunk) {
ServerChunkEvent.UNLOADED.invoker().onChunkUnloaded(world, chunk);
}
});

NeoEventUtils.registerEvent(forgeEventBus, ServerStartingEvent.class, event -> {
ServerLifecycleEvent.STARTING.invoker().onServerStarting(event.getServer());
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package band.kessoku.lib.events.lifecycle.mixin.neo.client;

import java.util.function.Consumer;

import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;

import net.minecraft.client.world.ClientChunkManager;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.packet.s2c.play.ChunkData;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.WorldChunk;

import band.kessoku.lib.events.lifecycle.api.client.ClientChunkEvent;

@Mixin(ClientChunkManager.class)
public abstract class ClientChunkManagerMixin {
@Final
@Shadow
private ClientWorld world;

@Inject(method = "loadChunkFromPacket", at = @At(value = "NEW", target = "net/minecraft/world/chunk/WorldChunk", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD)
private void onChunkUnload(int x, int z, PacketByteBuf buf, NbtCompound tag, Consumer<ChunkData.BlockEntityVisitor> consumer, CallbackInfoReturnable<WorldChunk> info, int index, WorldChunk worldChunk, ChunkPos chunkPos) {
if (worldChunk != null) {
ClientChunkEvent.UNLOADED.invoker().onChunkUnloaded(this.world, worldChunk);
}
}

@Inject(
method = "updateLoadDistance",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/world/ClientChunkManager$ClientChunkMap.isInRadius(II)Z"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onUpdateLoadDistance(int loadDistance, CallbackInfo ci, int oldRadius, int newRadius, ClientChunkManager.ClientChunkMap clientChunkMap, int k, WorldChunk oldChunk, ChunkPos chunkPos) {
if (!clientChunkMap.isInRadius(chunkPos.x, chunkPos.z)) {
ClientChunkEvent.UNLOADED.invoker().onChunkUnloaded(this.world, oldChunk);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package band.kessoku.lib.events.lifecycle.mixin.neo.client;

import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;

import band.kessoku.lib.events.lifecycle.api.client.ClientEntityEvent;

@Mixin(targets = "net/minecraft/client/world/ClientWorld$ClientEntityHandler")
public class ClientEntityHandlerMixin {
// final synthetic Lnet/minecraft/client/world/ClientWorld; field_27735
@SuppressWarnings("ShadowTarget")
@Shadow
@Final
private ClientWorld field_27735;

// Call our load event after vanilla has loaded the entity
@Inject(method = "startTracking(Lnet/minecraft/entity/Entity;)V", at = @At("TAIL"))
private void invokeLoadEntity(Entity entity, CallbackInfo ci) {
ClientEntityEvent.LOADED.invoker().onLoaded(entity, this.field_27735);
}

// Call our unload event before vanilla does.
@Inject(method = "stopTracking(Lnet/minecraft/entity/Entity;)V", at = @At("HEAD"))
private void invokeUnloadEntity(Entity entity, CallbackInfo ci) {
ClientEntityEvent.UNLOADED.invoker().onUnloaded(entity, this.field_27735);
}
}
Loading

0 comments on commit eccb4ae

Please sign in to comment.