Avoid unnecessary chunkloads when remove_spawn_chunks is enabled
This commit is contained in:
parent
ee34dcf96e
commit
30e3deb8e2
|
|
@ -1,24 +1,99 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
|
||||
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.WorldData;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.duck.ISpawnTrackingMinecraftServer;
|
||||
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.Redirect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mixin(value = MinecraftServer.class, priority = 1100)
|
||||
public class MinecraftServerMixin {
|
||||
public abstract class MinecraftServerMixin implements ISpawnTrackingMinecraftServer {
|
||||
@Shadow
|
||||
public abstract boolean isDedicatedServer();
|
||||
|
||||
@Shadow
|
||||
public abstract WorldData getWorldData();
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
public abstract ServerLevel getLevel(ResourceKey<Level> dimension);
|
||||
|
||||
private Pair<ResourceKey<Level>, ChunkPos> mfix$initialSpawnLocation;
|
||||
|
||||
private @Nullable Pair<ResourceKey<Level>, ChunkPos> loadPlayerSpawnLocation() {
|
||||
CompoundTag player = this.getWorldData().getLoadedPlayerTag();
|
||||
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ListTag pos = player.getList("Pos", CompoundTag.TAG_DOUBLE);
|
||||
double x = pos.getDouble(0);
|
||||
double z = pos.getDouble(2);
|
||||
|
||||
// Dimension
|
||||
ResourceKey<Level> dimension = DimensionType.parseLegacy(
|
||||
new Dynamic<>(NbtOps.INSTANCE, player.get("Dimension"))
|
||||
).resultOrPartial(ModernFix.LOGGER::error).orElse(Level.OVERWORLD);
|
||||
|
||||
return Pair.of(dimension, new ChunkPos(SectionPos.blockToSectionCoord(Mth.floor(x)), SectionPos.blockToSectionCoord(Mth.floor(z))));
|
||||
}
|
||||
|
||||
@Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"))
|
||||
private void addSpawnChunkTicket(ServerChunkCache cache, TicketType<?> type, ChunkPos pos, int distance, Object o) {
|
||||
// load first chunk
|
||||
cache.getChunk(pos.x, pos.z, ChunkStatus.FULL, true);
|
||||
private void addSpawnChunkTicket(ServerChunkCache cache, TicketType<?> type, ChunkPos pos, int distance, Object o, @Local(ordinal = 0, argsOnly = true) ChunkProgressListener listener) {
|
||||
if (!this.isDedicatedServer()) {
|
||||
// Temporarily create a START ticket around the player to load the world in parallel with client join
|
||||
// We remove it once the player has joined the world
|
||||
var pair = this.mfix$initialSpawnLocation = loadPlayerSpawnLocation();
|
||||
if (pair != null) {
|
||||
var level = this.getLevel(pair.getLeft());
|
||||
if (level != null) {
|
||||
cache = level.getChunkSource();
|
||||
pos = pair.getRight();
|
||||
}
|
||||
}
|
||||
|
||||
listener.updateSpawnPos(pos);
|
||||
cache.addRegionTicket(TicketType.START, pos, 0, Unit.INSTANCE);
|
||||
} else {
|
||||
// just trigger sync load of initial spawn once
|
||||
// TODO: figure out if this magic is still needed
|
||||
cache.getChunk(pos.x, pos.z, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;getTickingGenerated()I"), require = 0)
|
||||
private int getGenerated(ServerChunkCache cache) {
|
||||
return 441;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<ResourceKey<Level>, ChunkPos> mfix$getInitialStartTicketLocation() {
|
||||
var pair = this.mfix$initialSpawnLocation;
|
||||
this.mfix$initialSpawnLocation = null;
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
|
||||
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.server.players.PlayerList;
|
||||
import net.minecraft.util.Unit;
|
||||
import org.embeddedt.modernfix.duck.ISpawnTrackingMinecraftServer;
|
||||
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(PlayerList.class)
|
||||
public class PlayerListMixin {
|
||||
@Inject(method = "placeNewPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;addNewPlayer(Lnet/minecraft/server/level/ServerPlayer;)V", shift = At.Shift.AFTER))
|
||||
private void removeStartTicket(Connection netManager, ServerPlayer player, CallbackInfo ci) {
|
||||
var initial = ((ISpawnTrackingMinecraftServer)player.server).mfix$getInitialStartTicketLocation();
|
||||
if (initial != null) {
|
||||
var level = player.server.getLevel(initial.getLeft());
|
||||
if (level != null) {
|
||||
level.getChunkSource().removeRegionTicket(TicketType.START, initial.getRight(), 0, Unit.INSTANCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
|
||||
|
||||
import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ServerChunkCache.class)
|
||||
public interface ServerChunkCacheAccessor {
|
||||
@Accessor("distanceManager")
|
||||
DistanceManager getDistanceManager();
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public class ServerPlayerMixin {
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason do not waste time loading the wrong chunks and placing the player there just to correct it later
|
||||
*/
|
||||
@WrapWithCondition(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;fudgeSpawnLocation(Lnet/minecraft/server/level/ServerLevel;)V"))
|
||||
private boolean skipFudgingForSPOwner(ServerPlayer player, ServerLevel targetLevel) {
|
||||
return targetLevel.getServer().getWorldData().getLoadedPlayerTag() == null
|
||||
|| !targetLevel.getServer().isSingleplayerOwner(player.getGameProfile());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
public interface ISpawnTrackingMinecraftServer {
|
||||
Pair<ResourceKey<Level>, ChunkPos> mfix$getInitialStartTicketLocation();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user