mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-12-25 01:57:53 +01:00
Merge pull request #3567 from kosma/fabric-1.18-onchunkgenerate
Fabric 1.18: Fix onchunkgenerate trigger
This commit is contained in:
commit
ec369e96f8
@ -2,8 +2,6 @@ package org.dynmap.fabric_1_18;
|
|||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
|
||||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
@ -20,8 +18,6 @@ import net.minecraft.server.MinecraftServer;
|
|||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.server.world.ChunkHolder;
|
|
||||||
import net.minecraft.server.world.ServerChunkManager;
|
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.collection.IdList;
|
import net.minecraft.util.collection.IdList;
|
||||||
@ -46,11 +42,10 @@ import org.dynmap.fabric_1_18.command.DmarkerCommand;
|
|||||||
import org.dynmap.fabric_1_18.command.DynmapCommand;
|
import org.dynmap.fabric_1_18.command.DynmapCommand;
|
||||||
import org.dynmap.fabric_1_18.command.DynmapExpCommand;
|
import org.dynmap.fabric_1_18.command.DynmapExpCommand;
|
||||||
import org.dynmap.fabric_1_18.event.BlockEvents;
|
import org.dynmap.fabric_1_18.event.BlockEvents;
|
||||||
import org.dynmap.fabric_1_18.event.ChunkDataEvents;
|
import org.dynmap.fabric_1_18.event.CustomServerChunkEvents;
|
||||||
import org.dynmap.fabric_1_18.event.CustomServerLifecycleEvents;
|
import org.dynmap.fabric_1_18.event.CustomServerLifecycleEvents;
|
||||||
import org.dynmap.fabric_1_18.event.PlayerEvents;
|
import org.dynmap.fabric_1_18.event.PlayerEvents;
|
||||||
import org.dynmap.fabric_1_18.mixin.BiomeEffectsAccessor;
|
import org.dynmap.fabric_1_18.mixin.BiomeEffectsAccessor;
|
||||||
import org.dynmap.fabric_1_18.mixin.ThreadedAnvilChunkStorageAccessor;
|
|
||||||
import org.dynmap.fabric_1_18.permissions.FilePermissions;
|
import org.dynmap.fabric_1_18.permissions.FilePermissions;
|
||||||
import org.dynmap.fabric_1_18.permissions.OpPermissions;
|
import org.dynmap.fabric_1_18.permissions.OpPermissions;
|
||||||
import org.dynmap.fabric_1_18.permissions.PermissionProvider;
|
import org.dynmap.fabric_1_18.permissions.PermissionProvider;
|
||||||
@ -126,32 +121,6 @@ public class DynmapPlugin {
|
|||||||
|
|
||||||
public static DynmapBlockState[] stateByID;
|
public static DynmapBlockState[] stateByID;
|
||||||
|
|
||||||
private Map<String, LongOpenHashSet> knownloadedchunks = new HashMap<String, LongOpenHashSet>();
|
|
||||||
|
|
||||||
private void addKnownChunk(FabricWorld fw, ChunkPos pos) {
|
|
||||||
LongOpenHashSet cset = knownloadedchunks.get(fw.getName());
|
|
||||||
if (cset == null) {
|
|
||||||
cset = new LongOpenHashSet();
|
|
||||||
knownloadedchunks.put(fw.getName(), cset);
|
|
||||||
}
|
|
||||||
cset.add(pos.toLong());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeKnownChunk(FabricWorld fw, ChunkPos pos) {
|
|
||||||
LongOpenHashSet cset = knownloadedchunks.get(fw.getName());
|
|
||||||
if (cset != null) {
|
|
||||||
cset.remove(pos.toLong());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkIfKnownChunk(FabricWorld fw, ChunkPos pos) {
|
|
||||||
LongOpenHashSet cset = knownloadedchunks.get(fw.getName());
|
|
||||||
if (cset != null) {
|
|
||||||
return cset.contains(pos.toLong());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize block states (org.dynmap.blockstate.DynmapBlockState)
|
* Initialize block states (org.dynmap.blockstate.DynmapBlockState)
|
||||||
*/
|
*/
|
||||||
@ -658,69 +627,25 @@ public class DynmapPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleChunkLoad(ServerWorld world, WorldChunk chunk) {
|
public void handleChunkGenerate(ServerWorld world, Chunk chunk) {
|
||||||
if (!onchunkgenerate) return;
|
if (!onchunkgenerate) return;
|
||||||
|
|
||||||
if ((chunk != null) && (chunk.getStatus() == ChunkStatus.FULL)) {
|
FabricWorld fw = getWorld(world, false);
|
||||||
FabricWorld fw = getWorld(world, false);
|
ChunkPos chunkPos = chunk.getPos();
|
||||||
if (fw != null) {
|
|
||||||
addKnownChunk(fw, chunk.getPos());
|
int yMax = 0;
|
||||||
|
ChunkSection[] sections = chunk.getSectionArray();
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
if ((sections[i] != null) && (!sections[i].isEmpty())) {
|
||||||
|
yMax = 16 * (i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (yMax > 0) {
|
||||||
|
mapManager.touchVolume(fw.getName(),
|
||||||
public void handleChunkUnload(ServerWorld world, WorldChunk chunk) {
|
chunkPos.getStartX(), 0, chunkPos.getStartZ(),
|
||||||
if (!onchunkgenerate) return;
|
chunkPos.getEndX(), yMax, chunkPos.getEndZ(),
|
||||||
|
"chunkgenerate");
|
||||||
if ((chunk != null) && (chunk.getStatus() == ChunkStatus.FULL)) {
|
//Log.info("New generated chunk detected at %s[%s]".formatted(fw.getName(), chunkPos.getStartPos()));
|
||||||
FabricWorld fw = getWorld(world, false);
|
|
||||||
ChunkPos cp = chunk.getPos();
|
|
||||||
if (fw != null) {
|
|
||||||
if (!checkIfKnownChunk(fw, cp)) {
|
|
||||||
int ymax = 0;
|
|
||||||
ChunkSection[] sections = chunk.getSectionArray();
|
|
||||||
for (int i = 0; i < sections.length; i++) {
|
|
||||||
if ((sections[i] != null) && (!sections[i].isEmpty())) {
|
|
||||||
ymax = 16 * (i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int x = cp.x << 4;
|
|
||||||
int z = cp.z << 4;
|
|
||||||
// If not empty AND not initial scan
|
|
||||||
if (ymax > 0) {
|
|
||||||
Log.info("New generated chunk detected at " + cp + " for " + fw.getName());
|
|
||||||
mapManager.touchVolume(fw.getName(), x, 0, z, x + 15, ymax, z + 16, "chunkgenerate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeKnownChunk(fw, cp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleChunkDataSave(ServerWorld world, Chunk chunk) {
|
|
||||||
if (!onchunkgenerate) return;
|
|
||||||
|
|
||||||
if ((chunk != null) && (chunk.getStatus() == ChunkStatus.FULL)) {
|
|
||||||
FabricWorld fw = getWorld(world, false);
|
|
||||||
ChunkPos cp = chunk.getPos();
|
|
||||||
if (fw != null) {
|
|
||||||
if (!checkIfKnownChunk(fw, cp)) {
|
|
||||||
int ymax = 0;
|
|
||||||
ChunkSection[] sections = chunk.getSectionArray();
|
|
||||||
for (int i = 0; i < sections.length; i++) {
|
|
||||||
if ((sections[i] != null) && (!sections[i].isEmpty())) {
|
|
||||||
ymax = 16 * (i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int x = cp.x << 4;
|
|
||||||
int z = cp.z << 4;
|
|
||||||
// If not empty AND not initial scan
|
|
||||||
if (ymax > 0) {
|
|
||||||
mapManager.touchVolume(fw.getName(), x, 0, z, x + 15, ymax, z + 16, "chunkgenerate");
|
|
||||||
}
|
|
||||||
addKnownChunk(fw, cp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,39 +680,17 @@ public class DynmapPlugin {
|
|||||||
onblockchange_with_id = core.isTrigger("blockupdate-with-id");
|
onblockchange_with_id = core.isTrigger("blockupdate-with-id");
|
||||||
if (onblockchange_with_id)
|
if (onblockchange_with_id)
|
||||||
onblockchange = true;
|
onblockchange = true;
|
||||||
if ((worldTracker == null) && (onblockchange || onchunkpopulate || onchunkgenerate)) {
|
if (worldTracker == null)
|
||||||
worldTracker = new WorldTracker();
|
worldTracker = new WorldTracker();
|
||||||
ServerWorldEvents.LOAD.register((server, world) -> worldTracker.handleWorldLoad(server, world));
|
if (onchunkpopulate || onchunkgenerate) {
|
||||||
ServerWorldEvents.UNLOAD.register((server, world) -> worldTracker.handleWorldUnload(server, world));
|
CustomServerChunkEvents.CHUNK_GENERATE.register((world, chunk) -> worldTracker.handleChunkGenerate(world, chunk));
|
||||||
ServerChunkEvents.CHUNK_LOAD.register((world, chunk) -> worldTracker.handleChunkLoad(world, chunk));
|
}
|
||||||
ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> worldTracker.handleChunkUnload(world, chunk));
|
if (onblockchange) {
|
||||||
ChunkDataEvents.SAVE.register((world, chunk) -> worldTracker.handleChunkDataSave(world, chunk));
|
|
||||||
BlockEvents.BLOCK_EVENT.register((world, pos) -> worldTracker.handleBlockEvent(world, pos));
|
BlockEvents.BLOCK_EVENT.register((world, pos) -> worldTracker.handleBlockEvent(world, pos));
|
||||||
}
|
}
|
||||||
// Prime the known full chunks
|
|
||||||
if (onchunkgenerate && (server.getWorlds() != null)) {
|
ServerWorldEvents.LOAD.register((server, world) -> worldTracker.handleWorldLoad(server, world));
|
||||||
for (ServerWorld world : server.getWorlds()) {
|
ServerWorldEvents.UNLOAD.register((server, world) -> worldTracker.handleWorldUnload(server, world));
|
||||||
FabricWorld fw = getWorld(world);
|
|
||||||
if (fw == null) continue;
|
|
||||||
ServerChunkManager chunkManager = world.getChunkManager();
|
|
||||||
Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = ((ThreadedAnvilChunkStorageAccessor) chunkManager.threadedAnvilChunkStorage).getChunkHolders();
|
|
||||||
for (Map.Entry<Long, ChunkHolder> k : chunks.long2ObjectEntrySet()) {
|
|
||||||
ChunkHolder ch = k.getValue();
|
|
||||||
Chunk c = null;
|
|
||||||
try {
|
|
||||||
c = ch.getSavingFuture().getNow(null);
|
|
||||||
} catch (Exception x) {
|
|
||||||
}
|
|
||||||
if (c == null) continue;
|
|
||||||
ChunkStatus cs = c.getStatus();
|
|
||||||
ChunkPos pos = ch.getPos();
|
|
||||||
if (cs == ChunkStatus.FULL) { // Cooked?
|
|
||||||
// Add it as known
|
|
||||||
addKnownChunk(fw, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FabricWorld getWorldByName(String name) {
|
FabricWorld getWorldByName(String name) {
|
||||||
@ -890,5 +793,4 @@ public class DynmapPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
|||||||
|
package org.dynmap.fabric_1_18.access;
|
||||||
|
|
||||||
|
public interface ProtoChunkAccessor {
|
||||||
|
boolean getTouchedByWorldGen();
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
package org.dynmap.fabric_1_18.event;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.event.Event;
|
|
||||||
import net.fabricmc.fabric.api.event.EventFactory;
|
|
||||||
import net.minecraft.server.world.ServerWorld;
|
|
||||||
import net.minecraft.world.chunk.Chunk;
|
|
||||||
|
|
||||||
public class ChunkDataEvents {
|
|
||||||
private ChunkDataEvents() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Event<Save> SAVE = EventFactory.createArrayBacked(Save.class,
|
|
||||||
(listeners) -> (world, chunk) -> {
|
|
||||||
for (Save callback : listeners) {
|
|
||||||
callback.onSave(world, chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Save {
|
|
||||||
void onSave(ServerWorld world, Chunk chunk);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.dynmap.fabric_1_18.event;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.Event;
|
||||||
|
import net.fabricmc.fabric.api.event.EventFactory;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
|
||||||
|
public class CustomServerChunkEvents {
|
||||||
|
public static Event<ChunkGenerate> CHUNK_GENERATE = EventFactory.createArrayBacked(ChunkGenerate.class,
|
||||||
|
(listeners) -> (world, chunk) -> {
|
||||||
|
for (ChunkGenerate callback : listeners) {
|
||||||
|
callback.onChunkGenerate(world, chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ChunkGenerate {
|
||||||
|
void onChunkGenerate(ServerWorld world, Chunk chunk);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package org.dynmap.fabric_1_18.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.chunk.ProtoChunk;
|
||||||
|
import org.dynmap.fabric_1_18.access.ProtoChunkAccessor;
|
||||||
|
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.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(ProtoChunk.class)
|
||||||
|
public class ProtoChunkMixin implements ProtoChunkAccessor {
|
||||||
|
private boolean touchedByWorldGen = false;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "setBlockState",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/chunk/ChunkSection;setBlockState(IIILnet/minecraft/block/BlockState;)Lnet/minecraft/block/BlockState;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
public void setBlockState(BlockPos pos, BlockState state, boolean moved, CallbackInfoReturnable<BlockState> info) {
|
||||||
|
touchedByWorldGen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getTouchedByWorldGen() {
|
||||||
|
return touchedByWorldGen;
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
package org.dynmap.fabric_1_18.mixin;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
|
||||||
import net.minecraft.server.world.ChunkHolder;
|
|
||||||
import net.minecraft.server.world.ThreadedAnvilChunkStorage;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
@Mixin(ThreadedAnvilChunkStorage.class)
|
|
||||||
public interface ThreadedAnvilChunkStorageAccessor {
|
|
||||||
@Accessor
|
|
||||||
Long2ObjectLinkedOpenHashMap<ChunkHolder> getChunkHolders();
|
|
||||||
}
|
|
@ -1,9 +1,11 @@
|
|||||||
package org.dynmap.fabric_1_18.mixin;
|
package org.dynmap.fabric_1_18.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.server.world.ChunkHolder;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.server.world.ThreadedAnvilChunkStorage;
|
import net.minecraft.server.world.ThreadedAnvilChunkStorage;
|
||||||
import net.minecraft.world.chunk.Chunk;
|
import net.minecraft.world.chunk.Chunk;
|
||||||
import org.dynmap.fabric_1_18.event.ChunkDataEvents;
|
import org.dynmap.fabric_1_18.access.ProtoChunkAccessor;
|
||||||
|
import org.dynmap.fabric_1_18.event.CustomServerChunkEvents;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@ -11,16 +13,20 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
@Mixin(ThreadedAnvilChunkStorage.class)
|
@Mixin(value = ThreadedAnvilChunkStorage.class, priority = 666 /* fire before Fabric API CHUNK_LOAD event */)
|
||||||
public abstract class ThreadedAnvilChunkStorageMixin {
|
public abstract class ThreadedAnvilChunkStorageMixin {
|
||||||
@Shadow
|
|
||||||
@Final
|
@Final
|
||||||
private ServerWorld world;
|
@Shadow
|
||||||
|
ServerWorld world;
|
||||||
|
|
||||||
@Inject(method = "save(Lnet/minecraft/world/chunk/Chunk;)Z", at = @At("RETURN"))
|
@Inject(
|
||||||
private void save(Chunk chunk, CallbackInfoReturnable<Boolean> info) {
|
/* Same place as fabric-lifecycle-events-v1 event CHUNK_LOAD (we will fire before it) */
|
||||||
if (info.getReturnValueZ()) {
|
method = "method_17227",
|
||||||
ChunkDataEvents.SAVE.invoker().onSave(this.world, chunk);
|
at = @At("TAIL")
|
||||||
|
)
|
||||||
|
private void onChunkGenerate(ChunkHolder chunkHolder, Chunk protoChunk, CallbackInfoReturnable<Chunk> callbackInfoReturnable) {
|
||||||
|
if (((ProtoChunkAccessor)protoChunk).getTouchedByWorldGen()) {
|
||||||
|
CustomServerChunkEvents.CHUNK_GENERATE.invoker().onChunkGenerate(this.world, callbackInfoReturnable.getReturnValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -301,8 +301,6 @@ compass-mode: newnorth
|
|||||||
render-triggers:
|
render-triggers:
|
||||||
- blockupdate
|
- blockupdate
|
||||||
#- blockupdate-with-id
|
#- blockupdate-with-id
|
||||||
#- lightingupdate
|
|
||||||
- chunkpopulate
|
|
||||||
- chunkgenerate
|
- chunkgenerate
|
||||||
#- none
|
#- none
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
"BiomeEffectsAccessor",
|
"BiomeEffectsAccessor",
|
||||||
"MinecraftServerMixin",
|
"MinecraftServerMixin",
|
||||||
"PlayerManagerMixin",
|
"PlayerManagerMixin",
|
||||||
|
"ProtoChunkMixin",
|
||||||
"ServerPlayerEntityMixin",
|
"ServerPlayerEntityMixin",
|
||||||
"ServerPlayNetworkHandlerMixin",
|
"ServerPlayNetworkHandlerMixin",
|
||||||
"ThreadedAnvilChunkStorageAccessor",
|
|
||||||
"ThreadedAnvilChunkStorageMixin",
|
"ThreadedAnvilChunkStorageMixin",
|
||||||
"WorldChunkMixin"
|
"WorldChunkMixin"
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user