mirror of
https://github.com/architectury/architectury-api.git
synced 2026-03-28 03:56:59 -05:00
Add ChunkWatchEvent (#464)
Signed-off-by: Sergey Shatunov <me@aur.rocks> Co-authored-by: Max <maxh2709@gmail.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.event.events.common;
|
||||
|
||||
import dev.architectury.event.Event;
|
||||
import dev.architectury.event.EventFactory;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
||||
public interface ChunkWatchEvent {
|
||||
/**
|
||||
* This event is fired whenever a {@link ServerPlayer} begins watching a chunk and the chunk is queued up for
|
||||
* sending to the client.
|
||||
* <p>
|
||||
* This event must NOT be used to send additional chunk-related data to the client as the client will not be aware
|
||||
* of the chunk yet when this event fires. {@link ChunkWatchEvent#SENT} should be used for this purpose instead
|
||||
*/
|
||||
Event<ChunkListener> WATCH = EventFactory.createLoop();
|
||||
|
||||
/**
|
||||
* This event is fired whenever a chunk being watched by a {@link ServerPlayer} is transmitted to their client.
|
||||
* <p>
|
||||
* This event may be used to send additional chunk-related data to the client.
|
||||
*/
|
||||
Event<ChunkListener> SENT = EventFactory.createLoop();
|
||||
|
||||
/**
|
||||
* This event is fired whenever a {@link ServerPlayer} stops watching a chunk. The chunk this event fires for
|
||||
* may never have actually been known to the client if the chunk goes out of range before being sent due to
|
||||
* slow pacing of chunk sync on slow connections or to slow clients.
|
||||
*/
|
||||
Event<ChunkPosListener> UNWATCH = EventFactory.createLoop();
|
||||
|
||||
@FunctionalInterface
|
||||
interface ChunkListener {
|
||||
void listen(LevelChunk chunk, ServerLevel level, ServerPlayer player);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ChunkPosListener {
|
||||
void listen(ChunkPos chunkPos, ServerLevel level, ServerPlayer player);
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,21 @@
|
||||
package dev.architectury.mixin.fabric;
|
||||
|
||||
import dev.architectury.event.events.common.ChunkEvent;
|
||||
import dev.architectury.event.events.common.ChunkWatchEvent;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
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;
|
||||
|
||||
@@ -48,4 +52,14 @@ public class MixinChunkMap {
|
||||
private void save(ChunkAccess chunkAccess, CallbackInfoReturnable<Boolean> cir, ChunkPos pos, ChunkStatus chunkStatus, CompoundTag nbt) {
|
||||
ChunkEvent.SAVE_DATA.invoker().save(chunkAccess, this.level, nbt);
|
||||
}
|
||||
|
||||
@Inject(method = "markChunkPendingToSend(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/chunk/LevelChunk;)V", at = @At("TAIL"))
|
||||
private static void watch(ServerPlayer player, LevelChunk chunk, CallbackInfo ci) {
|
||||
ChunkWatchEvent.WATCH.invoker().listen(chunk, player.serverLevel(), player);
|
||||
}
|
||||
|
||||
@Inject(method = "dropChunk(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/ChunkPos;)V", at = @At("HEAD"))
|
||||
private static void unwatch(ServerPlayer player, ChunkPos chunkPos, CallbackInfo ci) {
|
||||
ChunkWatchEvent.UNWATCH.invoker().listen(chunkPos, player.serverLevel(), player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.fabric;
|
||||
|
||||
import dev.architectury.event.events.common.ChunkWatchEvent;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.network.PlayerChunkSender;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerChunkSender.class)
|
||||
public class MixinPlayerChunkSender {
|
||||
@Inject(method = "sendChunk", at = @At("TAIL"))
|
||||
private static void send(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk, CallbackInfo ci) {
|
||||
ChunkWatchEvent.SENT.invoker().listen(chunk, level, packetListener.player);
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@
|
||||
"MixinPhantomSpawner",
|
||||
"MixinPlayer",
|
||||
"MixinPlayerAdvancements",
|
||||
"MixinPlayerChunkSender",
|
||||
"MixinPlayerList",
|
||||
"MixinResultSlot",
|
||||
"MixinServerLevel",
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge.minecraftforge;
|
||||
|
||||
import dev.architectury.event.events.common.ChunkWatchEvent;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public abstract class MixinChunkMap {
|
||||
@Inject(method = "markChunkPendingToSend(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/chunk/LevelChunk;)V", at = @At("TAIL"))
|
||||
private static void watch(ServerPlayer player, LevelChunk chunk, CallbackInfo ci) {
|
||||
ChunkWatchEvent.WATCH.invoker().listen(chunk, player.serverLevel(), player);
|
||||
}
|
||||
|
||||
@Inject(method = "dropChunk(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/ChunkPos;)V", at = @At("HEAD"))
|
||||
private static void unwatch(ServerPlayer player, ChunkPos chunkPos, CallbackInfo ci) {
|
||||
ChunkWatchEvent.UNWATCH.invoker().listen(chunkPos, player.serverLevel(), player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge.minecraftforge;
|
||||
|
||||
import dev.architectury.event.events.common.ChunkWatchEvent;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.network.PlayerChunkSender;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerChunkSender.class)
|
||||
public abstract class MixinPlayerChunkSender {
|
||||
@Inject(method = "sendChunk", at = @At("TAIL"))
|
||||
private static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk, CallbackInfo ci) {
|
||||
ChunkWatchEvent.SENT.invoker().listen(chunk, level, packetListener.player);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
"client": [
|
||||
],
|
||||
"mixins": [
|
||||
"minecraftforge.MixinChunkMap",
|
||||
"minecraftforge.MixinPlayerChunkSender",
|
||||
"minecraftforge.MixinChunkSerializer",
|
||||
"minecraftforge.MixinEntitySpawnExtension"
|
||||
],
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
package dev.architectury.neoforge;
|
||||
|
||||
import dev.architectury.event.EventHandler;
|
||||
import dev.architectury.event.events.common.ChunkWatchEvent;
|
||||
import dev.architectury.networking.SpawnEntityPacket;
|
||||
import dev.architectury.registry.level.biome.forge.BiomeModificationsImpl;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import dev.architectury.utils.Env;
|
||||
import dev.architectury.utils.EnvExecutor;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
@@ -35,4 +37,22 @@ public class ArchitecturyNeoForge {
|
||||
|
||||
EnvExecutor.runInEnv(Env.CLIENT, () -> SpawnEntityPacket.Client::register);
|
||||
}
|
||||
|
||||
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE)
|
||||
private static class ForgeBusSubscriber {
|
||||
@SubscribeEvent
|
||||
private static void event(net.neoforged.neoforge.event.level.ChunkWatchEvent.Watch event) {
|
||||
ChunkWatchEvent.WATCH.invoker().listen(event.getChunk(), event.getLevel(), event.getPlayer());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
private static void event(net.neoforged.neoforge.event.level.ChunkWatchEvent.Sent event) {
|
||||
ChunkWatchEvent.SENT.invoker().listen(event.getChunk(), event.getLevel(), event.getPlayer());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
private static void event(net.neoforged.neoforge.event.level.ChunkWatchEvent.UnWatch event) {
|
||||
ChunkWatchEvent.UNWATCH.invoker().listen(event.getPos(), event.getLevel(), event.getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +235,15 @@ public class DebugEvents {
|
||||
ChunkEvent.SAVE_DATA.register((chunk, level, nbt) -> {
|
||||
// TestMod.SINK.accept("Chunk saved at x=" + chunk.getPos().x + ", z=" + chunk.getPos().z + " in dimension '" + level.dimension().location() + "'");
|
||||
});
|
||||
ChunkWatchEvent.WATCH.register((chunk, level, player) -> {
|
||||
// TestMod.SINK.accept("Chunk at x=%d, z=%d in dimension '%s' being watched by %s", chunk.getPos().x, chunk.getPos().z, level.dimension().location(), player.getScoreboardName());
|
||||
});
|
||||
ChunkWatchEvent.SENT.register((chunk, level, player) -> {
|
||||
// TestMod.SINK.accept("Chunk at x=%d, z=%d in dimension '%s' sent to %s", chunk.getPos().x, chunk.getPos().z, level.dimension().location(), player.getScoreboardName());
|
||||
});
|
||||
ChunkWatchEvent.UNWATCH.register((chunkPos, level, player) -> {
|
||||
// TestMod.SINK.accept("Chunk at x=%d, z=%d in dimension '%s' abandoned by %s", chunkPos.x, chunkPos.z, level.dimension().location(), player.getScoreboardName());
|
||||
});
|
||||
}
|
||||
|
||||
public static String toShortString(Vec3i pos) {
|
||||
|
||||
Reference in New Issue
Block a user