Skip to content

Commit 4de3b9b

Browse files
committed
Chunk load / unload and block update events
1 parent 3bd4b00 commit 4de3b9b

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.lambda.mixin.world;
2+
3+
import com.lambda.event.EventFlow;
4+
import com.lambda.event.events.WorldEvent;
5+
import net.minecraft.client.world.ClientChunkManager;
6+
import net.minecraft.client.world.ClientWorld;
7+
import net.minecraft.nbt.NbtCompound;
8+
import net.minecraft.network.PacketByteBuf;
9+
import net.minecraft.network.packet.s2c.play.ChunkData;
10+
import net.minecraft.util.math.ChunkPos;
11+
import net.minecraft.world.chunk.WorldChunk;
12+
import org.spongepowered.asm.mixin.Final;
13+
import org.spongepowered.asm.mixin.Mixin;
14+
import org.spongepowered.asm.mixin.Shadow;
15+
import org.spongepowered.asm.mixin.injection.At;
16+
import org.spongepowered.asm.mixin.injection.Inject;
17+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
18+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
19+
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
20+
21+
import java.util.function.Consumer;
22+
23+
@Mixin(ClientChunkManager.class)
24+
public class ClientChunkManagerMixin {
25+
@Final
26+
@Shadow
27+
ClientWorld world;
28+
29+
@Inject(method = "loadChunkFromPacket", at = @At("TAIL"))
30+
private void onChunkLoad(
31+
int x,
32+
int z,
33+
PacketByteBuf packetByteBuf,
34+
NbtCompound nbtCompound,
35+
Consumer<ChunkData.BlockEntityVisitor> consumer,
36+
CallbackInfoReturnable<WorldChunk> info
37+
) {
38+
EventFlow.post(new WorldEvent.ChunkEvent.Load(this.world, info.getReturnValue()));
39+
}
40+
41+
@Inject(method = "loadChunkFromPacket", at = @At(value = "NEW", target = "net/minecraft/world/chunk/WorldChunk", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD)
42+
private void onChunkUnload(
43+
int x,
44+
int z,
45+
PacketByteBuf buf,
46+
NbtCompound tag,
47+
Consumer<ChunkData.BlockEntityVisitor> consumer,
48+
CallbackInfoReturnable<WorldChunk> info,
49+
int index,
50+
WorldChunk chunk,
51+
ChunkPos chunkPos
52+
) {
53+
if (chunk != null) {
54+
EventFlow.post(new WorldEvent.ChunkEvent.Unload(this.world, chunk));
55+
}
56+
}
57+
58+
@Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;"), locals = LocalCapture.CAPTURE_FAILHARD)
59+
private void onChunkUnload(ChunkPos pos, CallbackInfo ci, int i, WorldChunk chunk) {
60+
EventFlow.post(new WorldEvent.ChunkEvent.Unload(this.world, chunk));
61+
}
62+
63+
// @Inject(
64+
// method = "updateLoadDistance",
65+
// at = @At(
66+
// value = "INVOKE",
67+
// target = "net/minecraft/client/world/ClientChunkManager$ClientChunkMap.isInRadius(II)Z"
68+
// ),
69+
// locals = LocalCapture.CAPTURE_FAILHARD
70+
// )
71+
// private void onUpdateLoadDistance(
72+
// int loadDistance,
73+
// CallbackInfo ci,
74+
// int oldRadius,
75+
// int newRadius,
76+
// ClientChunkManager.ClientChunkMap clientChunkMap,
77+
// int k,
78+
// WorldChunk oldChunk,
79+
// ChunkPos chunkPos
80+
// ) {
81+
// if (!clientChunkMap.isInRadius(chunkPos.x, chunkPos.z)) {
82+
// EventFlow.post(new WorldEvent.ChunkEvent.Unload(this.world, oldChunk));
83+
// }
84+
// }
85+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.lambda.mixin.world;
2+
3+
import com.lambda.event.EventFlow;
4+
import com.lambda.event.events.WorldEvent;
5+
import net.minecraft.block.BlockState;
6+
import net.minecraft.client.world.ClientWorld;
7+
import net.minecraft.util.math.BlockPos;
8+
import org.spongepowered.asm.mixin.Mixin;
9+
import org.spongepowered.asm.mixin.injection.At;
10+
import org.spongepowered.asm.mixin.injection.Inject;
11+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
12+
13+
@Mixin(ClientWorld.class)
14+
public class ClientWorldMixin {
15+
@Inject(method = "handleBlockUpdate", at = @At("HEAD"), cancellable = true)
16+
private void handleBlockUpdateInject(BlockPos pos, BlockState state, int flags, CallbackInfo ci) {
17+
if (EventFlow.post(new WorldEvent.BlockUpdate(pos, state, flags)).isCanceled()) {
18+
ci.cancel();
19+
}
20+
}
21+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.lambda.event.events
2+
3+
import com.lambda.event.Event
4+
import com.lambda.event.callback.Cancellable
5+
import com.lambda.event.callback.ICancellable
6+
import net.minecraft.block.BlockState
7+
import net.minecraft.client.world.ClientWorld
8+
import net.minecraft.util.math.BlockPos
9+
import net.minecraft.world.chunk.WorldChunk
10+
11+
abstract class WorldEvent : Event {
12+
13+
abstract class ChunkEvent : WorldEvent() {
14+
abstract val world: ClientWorld
15+
abstract val chunk: WorldChunk
16+
17+
class Load(
18+
override val world: ClientWorld,
19+
override val chunk: WorldChunk
20+
) : ChunkEvent()
21+
class Unload(
22+
override val world: ClientWorld,
23+
override val chunk: WorldChunk
24+
) : ChunkEvent()
25+
}
26+
class BlockUpdate(
27+
val pos: BlockPos,
28+
val state: BlockState,
29+
val flags: Int
30+
) : WorldEvent(), ICancellable by Cancellable()
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.lambda.module.modules.debug
2+
3+
import com.lambda.event.events.WorldEvent
4+
import com.lambda.event.listener.SafeListener.Companion.listener
5+
import com.lambda.module.Module
6+
import com.lambda.module.tag.ModuleTag
7+
import com.lambda.util.Communication.info
8+
9+
object UpdateTest : Module(
10+
name = "UpdateTest",
11+
description = "A module for testing updates",
12+
defaultTags = setOf(ModuleTag.DEBUG)
13+
) {
14+
init {
15+
listener<WorldEvent.BlockUpdate> {
16+
info("Block update at ${it.pos} with state ${it.state} and flags ${it.flags}")
17+
}
18+
19+
listener<WorldEvent.ChunkEvent.Load> {
20+
info("Chunk load at ${it.chunk.pos}")
21+
}
22+
23+
listener<WorldEvent.ChunkEvent.Unload> {
24+
info("Chunk unload at ${it.chunk.pos}")
25+
}
26+
}
27+
}

common/src/main/resources/lambda.mixins.common.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
"render.RenderLayersMixin",
3232
"render.RenderTickCounterMixin",
3333
"render.VertexBufferMixin",
34-
"render.WorldRendererMixin"
34+
"render.WorldRendererMixin",
35+
"world.ClientChunkManagerMixin",
36+
"world.ClientWorldMixin"
3537
],
3638
"injectors": {
3739
"defaultRequire": 1

0 commit comments

Comments
 (0)