Spaces:
Build error
Build error
package net.minecraft.server; | |
import com.google.common.base.Preconditions; | |
import com.google.common.base.Splitter; | |
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.Lists; | |
import com.google.common.collect.Maps; | |
import com.google.common.collect.Sets; | |
import com.mojang.authlib.GameProfile; | |
import com.mojang.authlib.GameProfileRepository; | |
import com.mojang.authlib.minecraft.MinecraftSessionService; | |
import com.mojang.datafixers.DataFixer; | |
import com.mojang.jtracy.DiscontinuousFrame; | |
import com.mojang.jtracy.TracyClient; | |
import com.mojang.logging.LogUtils; | |
import it.unimi.dsi.fastutil.longs.LongIterator; | |
import it.unimi.dsi.fastutil.objects.ObjectArrayList; | |
import it.unimi.dsi.fastutil.objects.ObjectArraySet; | |
import java.awt.image.BufferedImage; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.io.Writer; | |
import java.lang.management.ManagementFactory; | |
import java.lang.management.ThreadInfo; | |
import java.lang.management.ThreadMXBean; | |
import java.net.Proxy; | |
import java.nio.file.FileStore; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.security.KeyPair; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import java.util.Objects; | |
import java.util.Optional; | |
import java.util.Set; | |
import java.util.UUID; | |
import java.util.Map.Entry; | |
import java.util.concurrent.CompletableFuture; | |
import java.util.concurrent.Executor; | |
import java.util.concurrent.RejectedExecutionException; | |
import java.util.concurrent.atomic.AtomicReference; | |
import java.util.concurrent.locks.LockSupport; | |
import java.util.function.BooleanSupplier; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import java.util.stream.Collectors; | |
import javax.annotation.Nullable; | |
import javax.imageio.ImageIO; | |
import net.minecraft.CrashReport; | |
import net.minecraft.CrashReportCategory; | |
import net.minecraft.FileUtil; | |
import net.minecraft.ReportType; | |
import net.minecraft.ReportedException; | |
import net.minecraft.SharedConstants; | |
import net.minecraft.SystemReport; | |
import net.minecraft.Util; | |
import net.minecraft.commands.CommandSource; | |
import net.minecraft.commands.CommandSourceStack; | |
import net.minecraft.commands.Commands; | |
import net.minecraft.core.BlockPos; | |
import net.minecraft.core.Holder; | |
import net.minecraft.core.HolderGetter; | |
import net.minecraft.core.LayeredRegistryAccess; | |
import net.minecraft.core.Registry; | |
import net.minecraft.core.RegistryAccess; | |
import net.minecraft.core.registries.Registries; | |
import net.minecraft.data.worldgen.features.MiscOverworldFeatures; | |
import net.minecraft.gametest.framework.GameTestTicker; | |
import net.minecraft.network.chat.ChatDecorator; | |
import net.minecraft.network.chat.ChatType; | |
import net.minecraft.network.chat.Component; | |
import net.minecraft.network.protocol.PacketType; | |
import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; | |
import net.minecraft.network.protocol.game.ClientboundSetTimePacket; | |
import net.minecraft.network.protocol.status.ServerStatus; | |
import net.minecraft.obfuscate.DontObfuscate; | |
import net.minecraft.resources.ResourceKey; | |
import net.minecraft.resources.ResourceLocation; | |
import net.minecraft.server.bossevents.CustomBossEvents; | |
import net.minecraft.server.level.DemoMode; | |
import net.minecraft.server.level.PlayerRespawnLogic; | |
import net.minecraft.server.level.ServerChunkCache; | |
import net.minecraft.server.level.ServerLevel; | |
import net.minecraft.server.level.ServerPlayer; | |
import net.minecraft.server.level.ServerPlayerGameMode; | |
import net.minecraft.server.level.progress.ChunkProgressListener; | |
import net.minecraft.server.level.progress.ChunkProgressListenerFactory; | |
import net.minecraft.server.network.ServerConnectionListener; | |
import net.minecraft.server.network.TextFilter; | |
import net.minecraft.server.packs.PackType; | |
import net.minecraft.server.packs.repository.Pack; | |
import net.minecraft.server.packs.repository.PackRepository; | |
import net.minecraft.server.packs.repository.PackSource; | |
import net.minecraft.server.packs.resources.CloseableResourceManager; | |
import net.minecraft.server.packs.resources.MultiPackResourceManager; | |
import net.minecraft.server.packs.resources.ResourceManager; | |
import net.minecraft.server.players.GameProfileCache; | |
import net.minecraft.server.players.PlayerList; | |
import net.minecraft.server.players.ServerOpListEntry; | |
import net.minecraft.server.players.UserWhiteList; | |
import net.minecraft.tags.TagLoader; | |
import net.minecraft.util.Crypt; | |
import net.minecraft.util.CryptException; | |
import net.minecraft.util.ModCheck; | |
import net.minecraft.util.Mth; | |
import net.minecraft.util.NativeModuleLister; | |
import net.minecraft.util.RandomSource; | |
import net.minecraft.util.SignatureValidator; | |
import net.minecraft.util.TimeUtil; | |
import net.minecraft.util.debugchart.RemoteDebugSampleType; | |
import net.minecraft.util.debugchart.SampleLogger; | |
import net.minecraft.util.debugchart.TpsDebugDimensions; | |
import net.minecraft.util.profiling.EmptyProfileResults; | |
import net.minecraft.util.profiling.ProfileResults; | |
import net.minecraft.util.profiling.Profiler; | |
import net.minecraft.util.profiling.ProfilerFiller; | |
import net.minecraft.util.profiling.ResultField; | |
import net.minecraft.util.profiling.SingleTickProfiler; | |
import net.minecraft.util.profiling.jfr.JvmProfiler; | |
import net.minecraft.util.profiling.jfr.callback.ProfiledDuration; | |
import net.minecraft.util.profiling.metrics.profiling.ActiveMetricsRecorder; | |
import net.minecraft.util.profiling.metrics.profiling.InactiveMetricsRecorder; | |
import net.minecraft.util.profiling.metrics.profiling.MetricsRecorder; | |
import net.minecraft.util.profiling.metrics.profiling.ServerMetricsSamplersProvider; | |
import net.minecraft.util.profiling.metrics.storage.MetricsPersister; | |
import net.minecraft.util.thread.ReentrantBlockableEventLoop; | |
import net.minecraft.world.Difficulty; | |
import net.minecraft.world.RandomSequences; | |
import net.minecraft.world.entity.ai.village.VillageSiege; | |
import net.minecraft.world.entity.npc.CatSpawner; | |
import net.minecraft.world.entity.npc.WanderingTraderSpawner; | |
import net.minecraft.world.entity.player.Player; | |
import net.minecraft.world.flag.FeatureFlagSet; | |
import net.minecraft.world.flag.FeatureFlags; | |
import net.minecraft.world.item.alchemy.PotionBrewing; | |
import net.minecraft.world.item.crafting.RecipeManager; | |
import net.minecraft.world.level.ChunkPos; | |
import net.minecraft.world.level.CustomSpawner; | |
import net.minecraft.world.level.DataPackConfig; | |
import net.minecraft.world.level.ForcedChunksSavedData; | |
import net.minecraft.world.level.GameRules; | |
import net.minecraft.world.level.GameType; | |
import net.minecraft.world.level.Level; | |
import net.minecraft.world.level.LevelSettings; | |
import net.minecraft.world.level.WorldDataConfiguration; | |
import net.minecraft.world.level.biome.BiomeManager; | |
import net.minecraft.world.level.block.Block; | |
import net.minecraft.world.level.block.entity.FuelValues; | |
import net.minecraft.world.level.border.BorderChangeListener; | |
import net.minecraft.world.level.border.WorldBorder; | |
import net.minecraft.world.level.chunk.storage.ChunkIOErrorReporter; | |
import net.minecraft.world.level.chunk.storage.RegionStorageInfo; | |
import net.minecraft.world.level.dimension.LevelStem; | |
import net.minecraft.world.level.levelgen.Heightmap; | |
import net.minecraft.world.level.levelgen.PatrolSpawner; | |
import net.minecraft.world.level.levelgen.PhantomSpawner; | |
import net.minecraft.world.level.levelgen.WorldOptions; | |
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; | |
import net.minecraft.world.level.storage.CommandStorage; | |
import net.minecraft.world.level.storage.DerivedLevelData; | |
import net.minecraft.world.level.storage.DimensionDataStorage; | |
import net.minecraft.world.level.storage.LevelData; | |
import net.minecraft.world.level.storage.LevelResource; | |
import net.minecraft.world.level.storage.LevelStorageSource; | |
import net.minecraft.world.level.storage.PlayerDataStorage; | |
import net.minecraft.world.level.storage.ServerLevelData; | |
import net.minecraft.world.level.storage.WorldData; | |
import net.minecraft.world.phys.Vec2; | |
import net.minecraft.world.phys.Vec3; | |
import org.slf4j.Logger; | |
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements ServerInfo, ChunkIOErrorReporter, CommandSource { | |
private static final Logger LOGGER = LogUtils.getLogger(); | |
public static final String VANILLA_BRAND = "vanilla"; | |
private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F; | |
private static final int TICK_STATS_SPAN = 100; | |
private static final long OVERLOADED_THRESHOLD_NANOS = 20L * TimeUtil.NANOSECONDS_PER_SECOND / 20L; | |
private static final int OVERLOADED_TICKS_THRESHOLD = 20; | |
private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND; | |
private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; | |
private static final long STATUS_EXPIRE_TIME_NANOS = 5L * TimeUtil.NANOSECONDS_PER_SECOND; | |
private static final long PREPARE_LEVELS_DEFAULT_DELAY_NANOS = 10L * TimeUtil.NANOSECONDS_PER_MILLISECOND; | |
private static final int MAX_STATUS_PLAYER_SAMPLE = 12; | |
private static final int SPAWN_POSITION_SEARCH_RADIUS = 5; | |
private static final int AUTOSAVE_INTERVAL = 6000; | |
private static final int MIMINUM_AUTOSAVE_TICKS = 100; | |
private static final int MAX_TICK_LATENCY = 3; | |
public static final int ABSOLUTE_MAX_WORLD_SIZE = 29999984; | |
public static final LevelSettings DEMO_SETTINGS = new LevelSettings( | |
"Demo World", GameType.SURVIVAL, false, Difficulty.NORMAL, false, new GameRules(FeatureFlags.DEFAULT_FLAGS), WorldDataConfiguration.DEFAULT | |
); | |
public static final GameProfile ANONYMOUS_PLAYER_PROFILE = new GameProfile(Util.NIL_UUID, "Anonymous Player"); | |
protected final LevelStorageSource.LevelStorageAccess storageSource; | |
protected final PlayerDataStorage playerDataStorage; | |
private final List<Runnable> tickables = Lists.newArrayList(); | |
private MetricsRecorder metricsRecorder = InactiveMetricsRecorder.INSTANCE; | |
private Consumer<ProfileResults> onMetricsRecordingStopped = p_177903_ -> this.stopRecordingMetrics(); | |
private Consumer<Path> onMetricsRecordingFinished = p_177954_ -> { | |
}; | |
private boolean willStartRecordingMetrics; | |
private MinecraftServer.TimeProfiler debugCommandProfiler; | |
private boolean debugCommandProfilerDelayStart; | |
private final ServerConnectionListener connection; | |
private final ChunkProgressListenerFactory progressListenerFactory; | |
private ServerStatus status; | |
private ServerStatus.Favicon statusIcon; | |
private final RandomSource random = RandomSource.create(); | |
private final DataFixer fixerUpper; | |
private String localIp; | |
private int port = -1; | |
private final LayeredRegistryAccess<RegistryLayer> registries; | |
private final Map<ResourceKey<Level>, ServerLevel> levels = Maps.newLinkedHashMap(); | |
private PlayerList playerList; | |
private volatile boolean running = true; | |
private boolean stopped; | |
private int tickCount; | |
private int ticksUntilAutosave = 6000; | |
protected final Proxy proxy; | |
private boolean onlineMode; | |
private boolean preventProxyConnections; | |
private boolean pvp; | |
private boolean allowFlight; | |
private String motd; | |
private int playerIdleTimeout; | |
private final long[] tickTimesNanos = new long[100]; | |
private long aggregatedTickTimesNanos = 0L; | |
private KeyPair keyPair; | |
private GameProfile singleplayerProfile; | |
private boolean isDemo; | |
private volatile boolean isReady; | |
private long lastOverloadWarningNanos; | |
protected final Services services; | |
private long lastServerStatus; | |
private final Thread serverThread; | |
private long lastTickNanos = Util.getNanos(); | |
private long taskExecutionStartNanos = Util.getNanos(); | |
private long idleTimeNanos; | |
private long nextTickTimeNanos = Util.getNanos(); | |
private boolean waitingForNextTick = false; | |
private long delayedTasksMaxNextTickTimeNanos; | |
private boolean mayHaveDelayedTasks; | |
private final PackRepository packRepository; | |
private final ServerScoreboard scoreboard = new ServerScoreboard(this); | |
private CommandStorage commandStorage; | |
private final CustomBossEvents customBossEvents = new CustomBossEvents(); | |
private final ServerFunctionManager functionManager; | |
private boolean enforceWhitelist; | |
private float smoothedTickTimeMillis; | |
private final Executor executor; | |
private String serverId; | |
private MinecraftServer.ReloadableResources resources; | |
private final StructureTemplateManager structureTemplateManager; | |
private final ServerTickRateManager tickRateManager; | |
protected final WorldData worldData; | |
private final PotionBrewing potionBrewing; | |
private FuelValues fuelValues; | |
private int emptyTicks; | |
private volatile boolean isSaving; | |
private static final AtomicReference<RuntimeException> fatalException = new AtomicReference<>(); | |
private final SuppressedExceptionCollector suppressedExceptions = new SuppressedExceptionCollector(); | |
private final DiscontinuousFrame tickFrame; | |
public static <S extends MinecraftServer> S spin(Function<Thread, S> p_129873_) { | |
AtomicReference<S> atomicreference = new AtomicReference<>(); | |
Thread thread = new Thread(() -> atomicreference.get().runServer(), "Server thread"); | |
thread.setUncaughtExceptionHandler((p_177909_, p_177910_) -> LOGGER.error("Uncaught exception in server thread", p_177910_)); | |
if (Runtime.getRuntime().availableProcessors() > 4) { | |
thread.setPriority(8); | |
} | |
S s = (S)p_129873_.apply(thread); | |
atomicreference.set(s); | |
thread.start(); | |
return s; | |
} | |
public MinecraftServer( | |
Thread p_236723_, | |
LevelStorageSource.LevelStorageAccess p_236724_, | |
PackRepository p_236725_, | |
WorldStem p_236726_, | |
Proxy p_236727_, | |
DataFixer p_236728_, | |
Services p_236729_, | |
ChunkProgressListenerFactory p_236730_ | |
) { | |
super("Server"); | |
this.registries = p_236726_.registries(); | |
this.worldData = p_236726_.worldData(); | |
if (!this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) { | |
throw new IllegalStateException("Missing Overworld dimension data"); | |
} else { | |
this.proxy = p_236727_; | |
this.packRepository = p_236725_; | |
this.resources = new MinecraftServer.ReloadableResources(p_236726_.resourceManager(), p_236726_.dataPackResources()); | |
this.services = p_236729_; | |
if (p_236729_.profileCache() != null) { | |
p_236729_.profileCache().setExecutor(this); | |
} | |
this.connection = new ServerConnectionListener(this); | |
this.tickRateManager = new ServerTickRateManager(this); | |
this.progressListenerFactory = p_236730_; | |
this.storageSource = p_236724_; | |
this.playerDataStorage = p_236724_.createPlayerStorage(); | |
this.fixerUpper = p_236728_; | |
this.functionManager = new ServerFunctionManager(this, this.resources.managers.getFunctionLibrary()); | |
HolderGetter<Block> holdergetter = this.registries.compositeAccess().lookupOrThrow(Registries.BLOCK).filterFeatures(this.worldData.enabledFeatures()); | |
this.structureTemplateManager = new StructureTemplateManager(p_236726_.resourceManager(), p_236724_, p_236728_, holdergetter); | |
this.serverThread = p_236723_; | |
this.executor = Util.backgroundExecutor(); | |
this.potionBrewing = PotionBrewing.bootstrap(this.worldData.enabledFeatures()); | |
this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures()); | |
this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures()); | |
this.tickFrame = TracyClient.createDiscontinuousFrame("Server Tick"); | |
} | |
} | |
private void readScoreboard(DimensionDataStorage p_129842_) { | |
p_129842_.computeIfAbsent(this.getScoreboard().dataFactory(), "scoreboard"); | |
} | |
protected abstract boolean initServer() throws IOException; | |
protected void loadLevel() { | |
if (!JvmProfiler.INSTANCE.isRunning()) { | |
} | |
boolean flag = false; | |
ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onWorldLoadedStarted(); | |
this.worldData.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified()); | |
ChunkProgressListener chunkprogresslistener = this.progressListenerFactory.create(this.worldData.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)); | |
this.createLevels(chunkprogresslistener); | |
this.forceDifficulty(); | |
this.prepareLevels(chunkprogresslistener); | |
if (profiledduration != null) { | |
profiledduration.finish(true); | |
} | |
if (flag) { | |
try { | |
JvmProfiler.INSTANCE.stop(); | |
} catch (Throwable throwable) { | |
LOGGER.warn("Failed to stop JFR profiling", throwable); | |
} | |
} | |
} | |
protected void forceDifficulty() { | |
} | |
protected void createLevels(ChunkProgressListener p_129816_) { | |
ServerLevelData serverleveldata = this.worldData.overworldData(); | |
boolean flag = this.worldData.isDebugWorld(); | |
Registry<LevelStem> registry = this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM); | |
WorldOptions worldoptions = this.worldData.worldGenOptions(); | |
long i = worldoptions.seed(); | |
long j = BiomeManager.obfuscateSeed(i); | |
List<CustomSpawner> list = ImmutableList.of( | |
new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(serverleveldata) | |
); | |
LevelStem levelstem = registry.getValue(LevelStem.OVERWORLD); | |
ServerLevel serverlevel = new ServerLevel( | |
this, this.executor, this.storageSource, serverleveldata, Level.OVERWORLD, levelstem, p_129816_, flag, j, list, true, null | |
); | |
this.levels.put(Level.OVERWORLD, serverlevel); | |
DimensionDataStorage dimensiondatastorage = serverlevel.getDataStorage(); | |
this.readScoreboard(dimensiondatastorage); | |
this.commandStorage = new CommandStorage(dimensiondatastorage); | |
WorldBorder worldborder = serverlevel.getWorldBorder(); | |
if (!serverleveldata.isInitialized()) { | |
try { | |
setInitialSpawn(serverlevel, serverleveldata, worldoptions.generateBonusChest(), flag); | |
serverleveldata.setInitialized(true); | |
if (flag) { | |
this.setupDebugLevel(this.worldData); | |
} | |
} catch (Throwable throwable1) { | |
CrashReport crashreport = CrashReport.forThrowable(throwable1, "Exception initializing level"); | |
try { | |
serverlevel.fillReportDetails(crashreport); | |
} catch (Throwable throwable) { | |
} | |
throw new ReportedException(crashreport); | |
} | |
serverleveldata.setInitialized(true); | |
} | |
this.getPlayerList().addWorldborderListener(serverlevel); | |
if (this.worldData.getCustomBossEvents() != null) { | |
this.getCustomBossEvents().load(this.worldData.getCustomBossEvents(), this.registryAccess()); | |
} | |
RandomSequences randomsequences = serverlevel.getRandomSequences(); | |
for (Entry<ResourceKey<LevelStem>, LevelStem> entry : registry.entrySet()) { | |
ResourceKey<LevelStem> resourcekey = entry.getKey(); | |
if (resourcekey != LevelStem.OVERWORLD) { | |
ResourceKey<Level> resourcekey1 = ResourceKey.create(Registries.DIMENSION, resourcekey.location()); | |
DerivedLevelData derivedleveldata = new DerivedLevelData(this.worldData, serverleveldata); | |
ServerLevel serverlevel1 = new ServerLevel( | |
this, | |
this.executor, | |
this.storageSource, | |
derivedleveldata, | |
resourcekey1, | |
entry.getValue(), | |
p_129816_, | |
flag, | |
j, | |
ImmutableList.of(), | |
false, | |
randomsequences | |
); | |
worldborder.addListener(new BorderChangeListener.DelegateBorderChangeListener(serverlevel1.getWorldBorder())); | |
this.levels.put(resourcekey1, serverlevel1); | |
} | |
} | |
worldborder.applySettings(serverleveldata.getWorldBorder()); | |
} | |
private static void setInitialSpawn(ServerLevel p_177897_, ServerLevelData p_177898_, boolean p_177899_, boolean p_177900_) { | |
if (p_177900_) { | |
p_177898_.setSpawn(BlockPos.ZERO.above(80), 0.0F); | |
} else { | |
ServerChunkCache serverchunkcache = p_177897_.getChunkSource(); | |
ChunkPos chunkpos = new ChunkPos(serverchunkcache.randomState().sampler().findSpawnPosition()); | |
int i = serverchunkcache.getGenerator().getSpawnHeight(p_177897_); | |
if (i < p_177897_.getMinY()) { | |
BlockPos blockpos = chunkpos.getWorldPosition(); | |
i = p_177897_.getHeight(Heightmap.Types.WORLD_SURFACE, blockpos.getX() + 8, blockpos.getZ() + 8); | |
} | |
p_177898_.setSpawn(chunkpos.getWorldPosition().offset(8, i, 8), 0.0F); | |
int j1 = 0; | |
int j = 0; | |
int k = 0; | |
int l = -1; | |
for (int i1 = 0; i1 < Mth.square(11); i1++) { | |
if (j1 >= -5 && j1 <= 5 && j >= -5 && j <= 5) { | |
BlockPos blockpos1 = PlayerRespawnLogic.getSpawnPosInChunk(p_177897_, new ChunkPos(chunkpos.x + j1, chunkpos.z + j)); | |
if (blockpos1 != null) { | |
p_177898_.setSpawn(blockpos1, 0.0F); | |
break; | |
} | |
} | |
if (j1 == j || j1 < 0 && j1 == -j || j1 > 0 && j1 == 1 - j) { | |
int k1 = k; | |
k = -l; | |
l = k1; | |
} | |
j1 += k; | |
j += l; | |
} | |
if (p_177899_) { | |
p_177897_.registryAccess() | |
.lookup(Registries.CONFIGURED_FEATURE) | |
.flatMap(p_358516_ -> p_358516_.get(MiscOverworldFeatures.BONUS_CHEST)) | |
.ifPresent(p_326186_ -> p_326186_.value().place(p_177897_, serverchunkcache.getGenerator(), p_177897_.random, p_177898_.getSpawnPos())); | |
} | |
} | |
} | |
private void setupDebugLevel(WorldData p_129848_) { | |
p_129848_.setDifficulty(Difficulty.PEACEFUL); | |
p_129848_.setDifficultyLocked(true); | |
ServerLevelData serverleveldata = p_129848_.overworldData(); | |
serverleveldata.setRaining(false); | |
serverleveldata.setThundering(false); | |
serverleveldata.setClearWeatherTime(1000000000); | |
serverleveldata.setDayTime(6000L); | |
serverleveldata.setGameType(GameType.SPECTATOR); | |
} | |
private void prepareLevels(ChunkProgressListener p_129941_) { | |
ServerLevel serverlevel = this.overworld(); | |
LOGGER.info("Preparing start region for dimension {}", serverlevel.dimension().location()); | |
BlockPos blockpos = serverlevel.getSharedSpawnPos(); | |
p_129941_.updateSpawnPos(new ChunkPos(blockpos)); | |
ServerChunkCache serverchunkcache = serverlevel.getChunkSource(); | |
this.nextTickTimeNanos = Util.getNanos(); | |
serverlevel.setDefaultSpawnPos(blockpos, serverlevel.getSharedSpawnAngle()); | |
int i = this.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS); | |
int j = i > 0 ? Mth.square(ChunkProgressListener.calculateDiameter(i)) : 0; | |
while (serverchunkcache.getTickingGenerated() < j) { | |
this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; | |
this.waitUntilNextTick(); | |
} | |
this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; | |
this.waitUntilNextTick(); | |
for (ServerLevel serverlevel1 : this.levels.values()) { | |
ForcedChunksSavedData forcedchunkssaveddata = serverlevel1.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks"); | |
if (forcedchunkssaveddata != null) { | |
LongIterator longiterator = forcedchunkssaveddata.getChunks().iterator(); | |
while (longiterator.hasNext()) { | |
long k = longiterator.nextLong(); | |
ChunkPos chunkpos = new ChunkPos(k); | |
serverlevel1.getChunkSource().updateChunkForced(chunkpos, true); | |
} | |
} | |
} | |
this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; | |
this.waitUntilNextTick(); | |
p_129941_.stop(); | |
this.updateMobSpawningFlags(); | |
} | |
public GameType getDefaultGameType() { | |
return this.worldData.getGameType(); | |
} | |
public boolean isHardcore() { | |
return this.worldData.isHardcore(); | |
} | |
public abstract int getOperatorUserPermissionLevel(); | |
public abstract int getFunctionCompilationLevel(); | |
public abstract boolean shouldRconBroadcast(); | |
public boolean saveAllChunks(boolean p_129886_, boolean p_129887_, boolean p_129888_) { | |
boolean flag = false; | |
for (ServerLevel serverlevel : this.getAllLevels()) { | |
if (!p_129886_) { | |
LOGGER.info("Saving chunks for level '{}'/{}", serverlevel, serverlevel.dimension().location()); | |
} | |
serverlevel.save(null, p_129887_, serverlevel.noSave && !p_129888_); | |
flag = true; | |
} | |
ServerLevel serverlevel2 = this.overworld(); | |
ServerLevelData serverleveldata = this.worldData.overworldData(); | |
serverleveldata.setWorldBorder(serverlevel2.getWorldBorder().createSettings()); | |
this.worldData.setCustomBossEvents(this.getCustomBossEvents().save(this.registryAccess())); | |
this.storageSource.saveDataTag(this.registryAccess(), this.worldData, this.getPlayerList().getSingleplayerData()); | |
if (p_129887_) { | |
for (ServerLevel serverlevel1 : this.getAllLevels()) { | |
LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", serverlevel1.getChunkSource().chunkMap.getStorageName()); | |
} | |
LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved"); | |
} | |
return flag; | |
} | |
public boolean saveEverything(boolean p_195515_, boolean p_195516_, boolean p_195517_) { | |
boolean flag; | |
try { | |
this.isSaving = true; | |
this.getPlayerList().saveAll(); | |
flag = this.saveAllChunks(p_195515_, p_195516_, p_195517_); | |
} finally { | |
this.isSaving = false; | |
} | |
return flag; | |
} | |
public void close() { | |
this.stopServer(); | |
} | |
public void stopServer() { | |
if (this.metricsRecorder.isRecording()) { | |
this.cancelRecordingMetrics(); | |
} | |
LOGGER.info("Stopping server"); | |
this.getConnection().stop(); | |
this.isSaving = true; | |
if (this.playerList != null) { | |
LOGGER.info("Saving players"); | |
this.playerList.saveAll(); | |
this.playerList.removeAll(); | |
} | |
LOGGER.info("Saving worlds"); | |
for (ServerLevel serverlevel : this.getAllLevels()) { | |
if (serverlevel != null) { | |
serverlevel.noSave = false; | |
} | |
} | |
while (this.levels.values().stream().anyMatch(p_202480_ -> p_202480_.getChunkSource().chunkMap.hasWork())) { | |
this.nextTickTimeNanos = Util.getNanos() + TimeUtil.NANOSECONDS_PER_MILLISECOND; | |
for (ServerLevel serverlevel1 : this.getAllLevels()) { | |
serverlevel1.getChunkSource().removeTicketsOnClosing(); | |
serverlevel1.getChunkSource().tick(() -> true, false); | |
} | |
this.waitUntilNextTick(); | |
} | |
this.saveAllChunks(false, true, false); | |
for (ServerLevel serverlevel2 : this.getAllLevels()) { | |
if (serverlevel2 != null) { | |
try { | |
serverlevel2.close(); | |
} catch (IOException ioexception1) { | |
LOGGER.error("Exception closing the level", (Throwable)ioexception1); | |
} | |
} | |
} | |
this.isSaving = false; | |
this.resources.close(); | |
try { | |
this.storageSource.close(); | |
} catch (IOException ioexception) { | |
LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), ioexception); | |
} | |
} | |
public String getLocalIp() { | |
return this.localIp; | |
} | |
public void setLocalIp(String p_129914_) { | |
this.localIp = p_129914_; | |
} | |
public boolean isRunning() { | |
return this.running; | |
} | |
public void halt(boolean p_129884_) { | |
this.running = false; | |
if (p_129884_) { | |
try { | |
this.serverThread.join(); | |
} catch (InterruptedException interruptedexception) { | |
LOGGER.error("Error while shutting down", (Throwable)interruptedexception); | |
} | |
} | |
} | |
protected void runServer() { | |
try { | |
if (!this.initServer()) { | |
throw new IllegalStateException("Failed to initialize server"); | |
} | |
this.nextTickTimeNanos = Util.getNanos(); | |
this.statusIcon = this.loadStatusIcon().orElse(null); | |
this.status = this.buildServerStatus(); | |
while (this.running) { | |
long i; | |
if (!this.isPaused() && this.tickRateManager.isSprinting() && this.tickRateManager.checkShouldSprintThisTick()) { | |
i = 0L; | |
this.nextTickTimeNanos = Util.getNanos(); | |
this.lastOverloadWarningNanos = this.nextTickTimeNanos; | |
} else { | |
i = this.tickRateManager.nanosecondsPerTick(); | |
long k = Util.getNanos() - this.nextTickTimeNanos; | |
if (k > OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) { | |
long j = k / i; | |
LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", k / TimeUtil.NANOSECONDS_PER_MILLISECOND, j); | |
this.nextTickTimeNanos += j * i; | |
this.lastOverloadWarningNanos = this.nextTickTimeNanos; | |
} | |
} | |
boolean flag = i == 0L; | |
if (this.debugCommandProfilerDelayStart) { | |
this.debugCommandProfilerDelayStart = false; | |
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount); | |
} | |
this.nextTickTimeNanos += i; | |
try (Profiler.Scope profiler$scope = Profiler.use(this.createProfiler())) { | |
ProfilerFiller profilerfiller = Profiler.get(); | |
profilerfiller.push("tick"); | |
this.tickFrame.start(); | |
this.tickServer(flag ? () -> false : this::haveTime); | |
this.tickFrame.end(); | |
profilerfiller.popPush("nextTickWait"); | |
this.mayHaveDelayedTasks = true; | |
this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + i, this.nextTickTimeNanos); | |
this.startMeasuringTaskExecutionTime(); | |
this.waitUntilNextTick(); | |
this.finishMeasuringTaskExecutionTime(); | |
if (flag) { | |
this.tickRateManager.endTickWork(); | |
} | |
profilerfiller.pop(); | |
this.logFullTickTime(); | |
} finally { | |
this.endMetricsRecordingTick(); | |
} | |
this.isReady = true; | |
JvmProfiler.INSTANCE.onServerTick(this.smoothedTickTimeMillis); | |
} | |
} catch (Throwable throwable2) { | |
LOGGER.error("Encountered an unexpected exception", throwable2); | |
CrashReport crashreport = constructOrExtractCrashReport(throwable2); | |
this.fillSystemReport(crashreport.getSystemReport()); | |
Path path = this.getServerDirectory().resolve("crash-reports").resolve("crash-" + Util.getFilenameFormattedDateTime() + "-server.txt"); | |
if (crashreport.saveToFile(path, ReportType.CRASH)) { | |
LOGGER.error("This crash report has been saved to: {}", path.toAbsolutePath()); | |
} else { | |
LOGGER.error("We were unable to save this crash report to disk."); | |
} | |
this.onServerCrash(crashreport); | |
} finally { | |
try { | |
this.stopped = true; | |
this.stopServer(); | |
} catch (Throwable throwable) { | |
LOGGER.error("Exception stopping the server", throwable); | |
} finally { | |
if (this.services.profileCache() != null) { | |
this.services.profileCache().clearExecutor(); | |
} | |
this.onServerExit(); | |
} | |
} | |
} | |
private void logFullTickTime() { | |
long i = Util.getNanos(); | |
if (this.isTickTimeLoggingEnabled()) { | |
this.getTickTimeLogger().logSample(i - this.lastTickNanos); | |
} | |
this.lastTickNanos = i; | |
} | |
private void startMeasuringTaskExecutionTime() { | |
if (this.isTickTimeLoggingEnabled()) { | |
this.taskExecutionStartNanos = Util.getNanos(); | |
this.idleTimeNanos = 0L; | |
} | |
} | |
private void finishMeasuringTaskExecutionTime() { | |
if (this.isTickTimeLoggingEnabled()) { | |
SampleLogger samplelogger = this.getTickTimeLogger(); | |
samplelogger.logPartialSample(Util.getNanos() - this.taskExecutionStartNanos - this.idleTimeNanos, TpsDebugDimensions.SCHEDULED_TASKS.ordinal()); | |
samplelogger.logPartialSample(this.idleTimeNanos, TpsDebugDimensions.IDLE.ordinal()); | |
} | |
} | |
private static CrashReport constructOrExtractCrashReport(Throwable p_206569_) { | |
ReportedException reportedexception = null; | |
for (Throwable throwable = p_206569_; throwable != null; throwable = throwable.getCause()) { | |
if (throwable instanceof ReportedException reportedexception1) { | |
reportedexception = reportedexception1; | |
} | |
} | |
CrashReport crashreport; | |
if (reportedexception != null) { | |
crashreport = reportedexception.getReport(); | |
if (reportedexception != p_206569_) { | |
crashreport.addCategory("Wrapped in").setDetailError("Wrapping exception", p_206569_); | |
} | |
} else { | |
crashreport = new CrashReport("Exception in server tick loop", p_206569_); | |
} | |
return crashreport; | |
} | |
private boolean haveTime() { | |
return this.runningTask() || Util.getNanos() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTimeNanos : this.nextTickTimeNanos); | |
} | |
public static boolean throwIfFatalException() { | |
RuntimeException runtimeexception = fatalException.get(); | |
if (runtimeexception != null) { | |
throw runtimeexception; | |
} else { | |
return true; | |
} | |
} | |
public static void setFatalException(RuntimeException p_343685_) { | |
fatalException.compareAndSet(null, p_343685_); | |
} | |
public void managedBlock(BooleanSupplier p_343833_) { | |
super.managedBlock(() -> throwIfFatalException() && p_343833_.getAsBoolean()); | |
} | |
protected void waitUntilNextTick() { | |
this.runAllTasks(); | |
this.waitingForNextTick = true; | |
try { | |
this.managedBlock(() -> !this.haveTime()); | |
} finally { | |
this.waitingForNextTick = false; | |
} | |
} | |
public void waitForTasks() { | |
boolean flag = this.isTickTimeLoggingEnabled(); | |
long i = flag ? Util.getNanos() : 0L; | |
long j = this.waitingForNextTick ? this.nextTickTimeNanos - Util.getNanos() : 100000L; | |
LockSupport.parkNanos("waiting for tasks", j); | |
if (flag) { | |
this.idleTimeNanos = this.idleTimeNanos + (Util.getNanos() - i); | |
} | |
} | |
public TickTask wrapRunnable(Runnable p_129852_) { | |
return new TickTask(this.tickCount, p_129852_); | |
} | |
protected boolean shouldRun(TickTask p_129883_) { | |
return p_129883_.getTick() + 3 < this.tickCount || this.haveTime(); | |
} | |
public boolean pollTask() { | |
boolean flag = this.pollTaskInternal(); | |
this.mayHaveDelayedTasks = flag; | |
return flag; | |
} | |
private boolean pollTaskInternal() { | |
if (super.pollTask()) { | |
return true; | |
} else { | |
if (this.tickRateManager.isSprinting() || this.haveTime()) { | |
for (ServerLevel serverlevel : this.getAllLevels()) { | |
if (serverlevel.getChunkSource().pollTask()) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
} | |
public void doRunTask(TickTask p_129957_) { | |
Profiler.get().incrementCounter("runTask"); | |
super.doRunTask(p_129957_); | |
} | |
private Optional<ServerStatus.Favicon> loadStatusIcon() { | |
Optional<Path> optional = Optional.of(this.getFile("server-icon.png")) | |
.filter(p_272385_ -> Files.isRegularFile(p_272385_)) | |
.or(() -> this.storageSource.getIconFile().filter(p_272387_ -> Files.isRegularFile(p_272387_))); | |
return optional.flatMap(p_272386_ -> { | |
try { | |
BufferedImage bufferedimage = ImageIO.read(p_272386_.toFile()); | |
Preconditions.checkState(bufferedimage.getWidth() == 64, "Must be 64 pixels wide"); | |
Preconditions.checkState(bufferedimage.getHeight() == 64, "Must be 64 pixels high"); | |
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); | |
ImageIO.write(bufferedimage, "PNG", bytearrayoutputstream); | |
return Optional.of(new ServerStatus.Favicon(bytearrayoutputstream.toByteArray())); | |
} catch (Exception exception) { | |
LOGGER.error("Couldn't load server icon", (Throwable)exception); | |
return Optional.empty(); | |
} | |
}); | |
} | |
public Optional<Path> getWorldScreenshotFile() { | |
return this.storageSource.getIconFile(); | |
} | |
public Path getServerDirectory() { | |
return Path.of(""); | |
} | |
public void onServerCrash(CrashReport p_129874_) { | |
} | |
public void onServerExit() { | |
} | |
public boolean isPaused() { | |
return false; | |
} | |
public void tickServer(BooleanSupplier p_129871_) { | |
long i = Util.getNanos(); | |
int j = this.pauseWhileEmptySeconds() * 20; | |
if (j > 0) { | |
if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting()) { | |
this.emptyTicks++; | |
} else { | |
this.emptyTicks = 0; | |
} | |
if (this.emptyTicks >= j) { | |
if (this.emptyTicks == j) { | |
LOGGER.info("Server empty for {} seconds, pausing", this.pauseWhileEmptySeconds()); | |
this.autoSave(); | |
} | |
this.tickConnection(); | |
return; | |
} | |
} | |
this.tickCount++; | |
this.tickRateManager.tick(); | |
this.tickChildren(p_129871_); | |
if (i - this.lastServerStatus >= STATUS_EXPIRE_TIME_NANOS) { | |
this.lastServerStatus = i; | |
this.status = this.buildServerStatus(); | |
} | |
this.ticksUntilAutosave--; | |
if (this.ticksUntilAutosave <= 0) { | |
this.autoSave(); | |
} | |
ProfilerFiller profilerfiller = Profiler.get(); | |
profilerfiller.push("tallying"); | |
long k = Util.getNanos() - i; | |
int l = this.tickCount % 100; | |
this.aggregatedTickTimesNanos = this.aggregatedTickTimesNanos - this.tickTimesNanos[l]; | |
this.aggregatedTickTimesNanos += k; | |
this.tickTimesNanos[l] = k; | |
this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float)k / (float)TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F; | |
this.logTickMethodTime(i); | |
profilerfiller.pop(); | |
} | |
private void autoSave() { | |
this.ticksUntilAutosave = this.computeNextAutosaveInterval(); | |
LOGGER.debug("Autosave started"); | |
ProfilerFiller profilerfiller = Profiler.get(); | |
profilerfiller.push("save"); | |
this.saveEverything(true, false, false); | |
profilerfiller.pop(); | |
LOGGER.debug("Autosave finished"); | |
} | |
private void logTickMethodTime(long p_331549_) { | |
if (this.isTickTimeLoggingEnabled()) { | |
this.getTickTimeLogger().logPartialSample(Util.getNanos() - p_331549_, TpsDebugDimensions.TICK_SERVER_METHOD.ordinal()); | |
} | |
} | |
private int computeNextAutosaveInterval() { | |
float f; | |
if (this.tickRateManager.isSprinting()) { | |
long i = this.getAverageTickTimeNanos() + 1L; | |
f = (float)TimeUtil.NANOSECONDS_PER_SECOND / (float)i; | |
} else { | |
f = this.tickRateManager.tickrate(); | |
} | |
int j = 300; | |
return Math.max(100, (int)(f * 300.0F)); | |
} | |
public void onTickRateChanged() { | |
int i = this.computeNextAutosaveInterval(); | |
if (i < this.ticksUntilAutosave) { | |
this.ticksUntilAutosave = i; | |
} | |
} | |
protected abstract SampleLogger getTickTimeLogger(); | |
public abstract boolean isTickTimeLoggingEnabled(); | |
private ServerStatus buildServerStatus() { | |
ServerStatus.Players serverstatus$players = this.buildPlayerStatus(); | |
return new ServerStatus( | |
Component.nullToEmpty(this.motd), | |
Optional.of(serverstatus$players), | |
Optional.of(ServerStatus.Version.current()), | |
Optional.ofNullable(this.statusIcon), | |
this.enforceSecureProfile() | |
); | |
} | |
private ServerStatus.Players buildPlayerStatus() { | |
List<ServerPlayer> list = this.playerList.getPlayers(); | |
int i = this.getMaxPlayers(); | |
if (this.hidesOnlinePlayers()) { | |
return new ServerStatus.Players(i, list.size(), List.of()); | |
} else { | |
int j = Math.min(list.size(), 12); | |
ObjectArrayList<GameProfile> objectarraylist = new ObjectArrayList<>(j); | |
int k = Mth.nextInt(this.random, 0, list.size() - j); | |
for (int l = 0; l < j; l++) { | |
ServerPlayer serverplayer = list.get(k + l); | |
objectarraylist.add(serverplayer.allowsListing() ? serverplayer.getGameProfile() : ANONYMOUS_PLAYER_PROFILE); | |
} | |
Util.shuffle(objectarraylist, this.random); | |
return new ServerStatus.Players(i, list.size(), objectarraylist); | |
} | |
} | |
protected void tickChildren(BooleanSupplier p_129954_) { | |
ProfilerFiller profilerfiller = Profiler.get(); | |
this.getPlayerList().getPlayers().forEach(p_326187_ -> p_326187_.connection.suspendFlushing()); | |
profilerfiller.push("commandFunctions"); | |
this.getFunctions().tick(); | |
profilerfiller.popPush("levels"); | |
for (ServerLevel serverlevel : this.getAllLevels()) { | |
profilerfiller.push(() -> serverlevel + " " + serverlevel.dimension().location()); | |
if (this.tickCount % 20 == 0) { | |
profilerfiller.push("timeSync"); | |
this.synchronizeTime(serverlevel); | |
profilerfiller.pop(); | |
} | |
profilerfiller.push("tick"); | |
try { | |
serverlevel.tick(p_129954_); | |
} catch (Throwable throwable) { | |
CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world"); | |
serverlevel.fillReportDetails(crashreport); | |
throw new ReportedException(crashreport); | |
} | |
profilerfiller.pop(); | |
profilerfiller.pop(); | |
} | |
profilerfiller.popPush("connection"); | |
this.tickConnection(); | |
profilerfiller.popPush("players"); | |
this.playerList.tick(); | |
if (SharedConstants.IS_RUNNING_IN_IDE && this.tickRateManager.runsNormally()) { | |
GameTestTicker.SINGLETON.tick(); | |
} | |
profilerfiller.popPush("server gui refresh"); | |
for (int i = 0; i < this.tickables.size(); i++) { | |
this.tickables.get(i).run(); | |
} | |
profilerfiller.popPush("send chunks"); | |
for (ServerPlayer serverplayer : this.playerList.getPlayers()) { | |
serverplayer.connection.chunkSender.sendNextChunks(serverplayer); | |
serverplayer.connection.resumeFlushing(); | |
} | |
profilerfiller.pop(); | |
} | |
public void tickConnection() { | |
this.getConnection().tick(); | |
} | |
private void synchronizeTime(ServerLevel p_276371_) { | |
this.playerList | |
.broadcastAll( | |
new ClientboundSetTimePacket(p_276371_.getGameTime(), p_276371_.getDayTime(), p_276371_.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)), | |
p_276371_.dimension() | |
); | |
} | |
public void forceTimeSynchronization() { | |
ProfilerFiller profilerfiller = Profiler.get(); | |
profilerfiller.push("timeSync"); | |
for (ServerLevel serverlevel : this.getAllLevels()) { | |
this.synchronizeTime(serverlevel); | |
} | |
profilerfiller.pop(); | |
} | |
public boolean isLevelEnabled(Level p_345327_) { | |
return true; | |
} | |
public void addTickable(Runnable p_129947_) { | |
this.tickables.add(p_129947_); | |
} | |
protected void setId(String p_129949_) { | |
this.serverId = p_129949_; | |
} | |
public boolean isShutdown() { | |
return !this.serverThread.isAlive(); | |
} | |
public Path getFile(String p_129972_) { | |
return this.getServerDirectory().resolve(p_129972_); | |
} | |
public final ServerLevel overworld() { | |
return this.levels.get(Level.OVERWORLD); | |
} | |
public ServerLevel getLevel(ResourceKey<Level> p_129881_) { | |
return this.levels.get(p_129881_); | |
} | |
public Set<ResourceKey<Level>> levelKeys() { | |
return this.levels.keySet(); | |
} | |
public Iterable<ServerLevel> getAllLevels() { | |
return this.levels.values(); | |
} | |
public String getServerVersion() { | |
return SharedConstants.getCurrentVersion().getName(); | |
} | |
public int getPlayerCount() { | |
return this.playerList.getPlayerCount(); | |
} | |
public int getMaxPlayers() { | |
return this.playerList.getMaxPlayers(); | |
} | |
public String[] getPlayerNames() { | |
return this.playerList.getPlayerNamesArray(); | |
} | |
public String getServerModName() { | |
return "vanilla"; | |
} | |
public SystemReport fillSystemReport(SystemReport p_177936_) { | |
p_177936_.setDetail("Server Running", () -> Boolean.toString(this.running)); | |
if (this.playerList != null) { | |
p_177936_.setDetail("Player Count", () -> this.playerList.getPlayerCount() + " / " + this.playerList.getMaxPlayers() + "; " + this.playerList.getPlayers()); | |
} | |
p_177936_.setDetail("Active Data Packs", () -> PackRepository.displayPackList(this.packRepository.getSelectedPacks())); | |
p_177936_.setDetail("Available Data Packs", () -> PackRepository.displayPackList(this.packRepository.getAvailablePacks())); | |
p_177936_.setDetail( | |
"Enabled Feature Flags", | |
() -> FeatureFlags.REGISTRY.toNames(this.worldData.enabledFeatures()).stream().map(ResourceLocation::toString).collect(Collectors.joining(", ")) | |
); | |
p_177936_.setDetail("World Generation", () -> this.worldData.worldGenSettingsLifecycle().toString()); | |
p_177936_.setDetail("World Seed", () -> String.valueOf(this.worldData.worldGenOptions().seed())); | |
p_177936_.setDetail("Suppressed Exceptions", this.suppressedExceptions::dump); | |
if (this.serverId != null) { | |
p_177936_.setDetail("Server Id", () -> this.serverId); | |
} | |
return this.fillServerSystemReport(p_177936_); | |
} | |
public abstract SystemReport fillServerSystemReport(SystemReport p_177901_); | |
public ModCheck getModdedStatus() { | |
return ModCheck.identify("vanilla", this::getServerModName, "Server", MinecraftServer.class); | |
} | |
public void sendSystemMessage(Component p_236736_) { | |
LOGGER.info(p_236736_.getString()); | |
} | |
public KeyPair getKeyPair() { | |
return this.keyPair; | |
} | |
public int getPort() { | |
return this.port; | |
} | |
public void setPort(int p_129802_) { | |
this.port = p_129802_; | |
} | |
public GameProfile getSingleplayerProfile() { | |
return this.singleplayerProfile; | |
} | |
public void setSingleplayerProfile( { GameProfile p_236741_) | |
this.singleplayerProfile = p_236741_; | |
} | |
public boolean isSingleplayer() { | |
return this.singleplayerProfile != null; | |
} | |
protected void initializeKeyPair() { | |
LOGGER.info("Generating keypair"); | |
try { | |
this.keyPair = Crypt.generateKeyPair(); | |
} catch (CryptException cryptexception) { | |
throw new IllegalStateException("Failed to generate key pair", cryptexception); | |
} | |
} | |
public void setDifficulty(Difficulty p_129828_, boolean p_129829_) { | |
if (p_129829_ || !this.worldData.isDifficultyLocked()) { | |
this.worldData.setDifficulty(this.worldData.isHardcore() ? Difficulty.HARD : p_129828_); | |
this.updateMobSpawningFlags(); | |
this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate); | |
} | |
} | |
public int getScaledTrackingDistance(int p_129935_) { | |
return p_129935_; | |
} | |
private void updateMobSpawningFlags() { | |
for (ServerLevel serverlevel : this.getAllLevels()) { | |
serverlevel.setSpawnSettings(this.isSpawningMonsters()); | |
} | |
} | |
public void setDifficultyLocked(boolean p_129959_) { | |
this.worldData.setDifficultyLocked(p_129959_); | |
this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate); | |
} | |
private void sendDifficultyUpdate(ServerPlayer p_129939_) { | |
LevelData leveldata = p_129939_.level().getLevelData(); | |
p_129939_.connection.send(new ClientboundChangeDifficultyPacket(leveldata.getDifficulty(), leveldata.isDifficultyLocked())); | |
} | |
public boolean isSpawningMonsters() { | |
return this.worldData.getDifficulty() != Difficulty.PEACEFUL; | |
} | |
public boolean isDemo() { | |
return this.isDemo; | |
} | |
public void setDemo(boolean p_129976_) { | |
this.isDemo = p_129976_; | |
} | |
public Optional<MinecraftServer.ServerResourcePackInfo> getServerResourcePack() { | |
return Optional.empty(); | |
} | |
public boolean isResourcePackRequired() { | |
return this.getServerResourcePack().filter(MinecraftServer.ServerResourcePackInfo::isRequired).isPresent(); | |
} | |
public abstract boolean isDedicatedServer(); | |
public abstract int getRateLimitPacketsPerSecond(); | |
public boolean usesAuthentication() { | |
return this.onlineMode; | |
} | |
public void setUsesAuthentication(boolean p_129986_) { | |
this.onlineMode = p_129986_; | |
} | |
public boolean getPreventProxyConnections() { | |
return this.preventProxyConnections; | |
} | |
public void setPreventProxyConnections(boolean p_129994_) { | |
this.preventProxyConnections = p_129994_; | |
} | |
public abstract boolean isEpollEnabled(); | |
public boolean isPvpAllowed() { | |
return this.pvp; | |
} | |
public void setPvpAllowed(boolean p_129998_) { | |
this.pvp = p_129998_; | |
} | |
public boolean isFlightAllowed() { | |
return this.allowFlight; | |
} | |
public void setFlightAllowed(boolean p_130000_) { | |
this.allowFlight = p_130000_; | |
} | |
public abstract boolean isCommandBlockEnabled(); | |
public String getMotd() { | |
return this.motd; | |
} | |
public void setMotd(String p_129990_) { | |
this.motd = p_129990_; | |
} | |
public boolean isStopped() { | |
return this.stopped; | |
} | |
public PlayerList getPlayerList() { | |
return this.playerList; | |
} | |
public void setPlayerList(PlayerList p_129824_) { | |
this.playerList = p_129824_; | |
} | |
public abstract boolean isPublished(); | |
public void setDefaultGameType(GameType p_129832_) { | |
this.worldData.setGameType(p_129832_); | |
} | |
public ServerConnectionListener getConnection() { | |
return this.connection; | |
} | |
public boolean isReady() { | |
return this.isReady; | |
} | |
public boolean hasGui() { | |
return false; | |
} | |
public boolean publishServer(boolean p_129834_, int p_129835_) { GameType p_129833_, | |
return false; | |
} | |
public int getTickCount() { | |
return this.tickCount; | |
} | |
public int getSpawnProtectionRadius() { | |
return 16; | |
} | |
public boolean isUnderSpawnProtection(ServerLevel p_129811_, BlockPos p_129812_, Player p_129813_) { | |
return false; | |
} | |
public boolean repliesToStatus() { | |
return true; | |
} | |
public boolean hidesOnlinePlayers() { | |
return false; | |
} | |
public Proxy getProxy() { | |
return this.proxy; | |
} | |
public int getPlayerIdleTimeout() { | |
return this.playerIdleTimeout; | |
} | |
public void setPlayerIdleTimeout(int p_129978_) { | |
this.playerIdleTimeout = p_129978_; | |
} | |
public MinecraftSessionService getSessionService() { | |
return this.services.sessionService(); | |
} | |
public SignatureValidator getProfileKeySignatureValidator() { | |
return this.services.profileKeySignatureValidator(); | |
} | |
public GameProfileRepository getProfileRepository() { | |
return this.services.profileRepository(); | |
} | |
public GameProfileCache getProfileCache() { | |
return this.services.profileCache(); | |
} | |
public ServerStatus getStatus() { | |
return this.status; | |
} | |
public void invalidateStatus() { | |
this.lastServerStatus = 0L; | |
} | |
public int getAbsoluteMaxWorldSize() { | |
return 29999984; | |
} | |
public boolean scheduleExecutables() { | |
return super.scheduleExecutables() && !this.isStopped(); | |
} | |
public void executeIfPossible(Runnable p_202482_) { | |
if (this.isStopped()) { | |
throw new RejectedExecutionException("Server already shutting down"); | |
} else { | |
super.executeIfPossible(p_202482_); | |
} | |
} | |
public Thread getRunningThread() { | |
return this.serverThread; | |
} | |
public int getCompressionThreshold() { | |
return 256; | |
} | |
public boolean enforceSecureProfile() { | |
return false; | |
} | |
public long getNextTickTime() { | |
return this.nextTickTimeNanos; | |
} | |
public DataFixer getFixerUpper() { | |
return this.fixerUpper; | |
} | |
public int getSpawnRadius( { ServerLevel p_129804_) | |
return p_129804_ != null ? p_129804_.getGameRules().getInt(GameRules.RULE_SPAWN_RADIUS) : 10; | |
} | |
public ServerAdvancementManager getAdvancements() { | |
return this.resources.managers.getAdvancements(); | |
} | |
public ServerFunctionManager getFunctions() { | |
return this.functionManager; | |
} | |
public CompletableFuture<Void> reloadResources(Collection<String> p_129862_) { | |
CompletableFuture<Void> completablefuture = CompletableFuture.<ImmutableList>supplyAsync( | |
() -> p_129862_.stream().map(this.packRepository::getPack).filter(Objects::nonNull).map(Pack::open).collect(ImmutableList.toImmutableList()), | |
this | |
) | |
.thenCompose( | |
p_358514_ -> { | |
CloseableResourceManager closeableresourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, p_358514_); | |
List<Registry.PendingTags<?>> list = TagLoader.loadTagsForExistingRegistries(closeableresourcemanager, this.registries.compositeAccess()); | |
return ReloadableServerResources.loadResources( | |
closeableresourcemanager, | |
this.registries, | |
list, | |
this.worldData.enabledFeatures(), | |
this.isDedicatedServer() ? Commands.CommandSelection.DEDICATED : Commands.CommandSelection.INTEGRATED, | |
this.getFunctionCompilationLevel(), | |
this.executor, | |
this | |
) | |
.whenComplete((p_212907_, p_212908_) -> { | |
if (p_212908_ != null) { | |
closeableresourcemanager.close(); | |
} | |
}) | |
.thenApply(p_212904_ -> new MinecraftServer.ReloadableResources(closeableresourcemanager, p_212904_)); | |
} | |
) | |
.thenAcceptAsync(p_358513_ -> { | |
this.resources.close(); | |
this.resources = p_358513_; | |
this.packRepository.setSelected(p_129862_); | |
WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); | |
this.worldData.setDataConfiguration(worlddataconfiguration); | |
this.resources.managers.updateStaticRegistryTags(); | |
this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures()); | |
this.getPlayerList().saveAll(); | |
this.getPlayerList().reloadResources(); | |
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary()); | |
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager); | |
this.fuelValues = FuelValues.vanillaBurnTimes(this.registries.compositeAccess(), this.worldData.enabledFeatures()); | |
}, this); | |
if (this.isSameThread()) { | |
this.managedBlock(completablefuture::isDone); | |
} | |
return completablefuture; | |
} | |
public static WorldDataConfiguration configurePackRepository(PackRepository p_248681_, WorldDataConfiguration p_331931_, boolean p_249869_, boolean p_330480_) { | |
DataPackConfig datapackconfig = p_331931_.dataPacks(); | |
FeatureFlagSet featureflagset = p_249869_ ? FeatureFlagSet.of() : p_331931_.enabledFeatures(); | |
FeatureFlagSet featureflagset1 = p_249869_ ? FeatureFlags.REGISTRY.allFlags() : p_331931_.enabledFeatures(); | |
p_248681_.reload(); | |
if (p_330480_) { | |
return configureRepositoryWithSelection(p_248681_, List.of("vanilla"), featureflagset, false); | |
} else { | |
Set<String> set = Sets.newLinkedHashSet(); | |
for (String s : datapackconfig.getEnabled()) { | |
if (p_248681_.isAvailable(s)) { | |
set.add(s); | |
} else { | |
LOGGER.warn("Missing data pack {}", s); | |
} | |
} | |
for (Pack pack : p_248681_.getAvailablePacks()) { | |
String s1 = pack.getId(); | |
if (!datapackconfig.getDisabled().contains(s1)) { | |
FeatureFlagSet featureflagset2 = pack.getRequestedFeatures(); | |
boolean flag = set.contains(s1); | |
if (!flag && pack.getPackSource().shouldAddAutomatically()) { | |
if (featureflagset2.isSubsetOf(featureflagset1)) { | |
LOGGER.info("Found new data pack {}, loading it automatically", s1); | |
set.add(s1); | |
} else { | |
LOGGER.info( | |
"Found new data pack {}, but can't load it due to missing features {}", | |
s1, | |
FeatureFlags.printMissingFlags(featureflagset1, featureflagset2) | |
); | |
} | |
} | |
if (flag && !featureflagset2.isSubsetOf(featureflagset1)) { | |
LOGGER.warn( | |
"Pack {} requires features {} that are not enabled for this world, disabling pack.", | |
s1, | |
FeatureFlags.printMissingFlags(featureflagset1, featureflagset2) | |
); | |
set.remove(s1); | |
} | |
} | |
} | |
if (set.isEmpty()) { | |
LOGGER.info("No datapacks selected, forcing vanilla"); | |
set.add("vanilla"); | |
} | |
return configureRepositoryWithSelection(p_248681_, set, featureflagset, true); | |
} | |
} | |
private static WorldDataConfiguration configureRepositoryWithSelection(PackRepository p_331926_, Collection<String> p_333329_, FeatureFlagSet p_331153_, boolean p_334241_) { | |
p_331926_.setSelected(p_333329_); | |
enableForcedFeaturePacks(p_331926_, p_331153_); | |
DataPackConfig datapackconfig = getSelectedPacks(p_331926_, p_334241_); | |
FeatureFlagSet featureflagset = p_331926_.getRequestedFeatureFlags().join(p_331153_); | |
return new WorldDataConfiguration(datapackconfig, featureflagset); | |
} | |
private static void enableForcedFeaturePacks(PackRepository p_335711_, FeatureFlagSet p_335242_) { | |
FeatureFlagSet featureflagset = p_335711_.getRequestedFeatureFlags(); | |
FeatureFlagSet featureflagset1 = p_335242_.subtract(featureflagset); | |
if (!featureflagset1.isEmpty()) { | |
Set<String> set = new ObjectArraySet<>(p_335711_.getSelectedIds()); | |
for (Pack pack : p_335711_.getAvailablePacks()) { | |
if (featureflagset1.isEmpty()) { | |
break; | |
} | |
if (pack.getPackSource() == PackSource.FEATURE) { | |
String s = pack.getId(); | |
FeatureFlagSet featureflagset2 = pack.getRequestedFeatures(); | |
if (!featureflagset2.isEmpty() && featureflagset2.intersects(featureflagset1) && featureflagset2.isSubsetOf(p_335242_)) { | |
if (!set.add(s)) { | |
throw new IllegalStateException("Tried to force '" + s + "', but it was already enabled"); | |
} | |
LOGGER.info("Found feature pack ('{}') for requested feature, forcing to enabled", s); | |
featureflagset1 = featureflagset1.subtract(featureflagset2); | |
} | |
} | |
} | |
p_335711_.setSelected(set); | |
} | |
} | |
private static DataPackConfig getSelectedPacks(PackRepository p_129818_, boolean p_334831_) { | |
Collection<String> collection = p_129818_.getSelectedIds(); | |
List<String> list = ImmutableList.copyOf(collection); | |
List<String> list1 = p_334831_ ? p_129818_.getAvailableIds().stream().filter(p_212916_ -> !collection.contains(p_212916_)).toList() : List.of(); | |
return new DataPackConfig(list, list1); | |
} | |
public void kickUnlistedPlayers(CommandSourceStack p_129850_) { | |
if (this.isEnforceWhitelist()) { | |
PlayerList playerlist = p_129850_.getServer().getPlayerList(); | |
UserWhiteList userwhitelist = playerlist.getWhiteList(); | |
for (ServerPlayer serverplayer : Lists.newArrayList(playerlist.getPlayers())) { | |
if (!userwhitelist.isWhiteListed(serverplayer.getGameProfile())) { | |
serverplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.not_whitelisted")); | |
} | |
} | |
} | |
} | |
public PackRepository getPackRepository() { | |
return this.packRepository; | |
} | |
public Commands getCommands() { | |
return this.resources.managers.getCommands(); | |
} | |
public CommandSourceStack createCommandSourceStack() { | |
ServerLevel serverlevel = this.overworld(); | |
return new CommandSourceStack( | |
this, | |
serverlevel == null ? Vec3.ZERO : Vec3.atLowerCornerOf(serverlevel.getSharedSpawnPos()), | |
Vec2.ZERO, | |
serverlevel, | |
4, | |
"Server", | |
Component.literal("Server"), | |
this, | |
null | |
); | |
} | |
public boolean acceptsSuccess() { | |
return true; | |
} | |
public boolean acceptsFailure() { | |
return true; | |
} | |
public abstract boolean shouldInformAdmins(); | |
public RecipeManager getRecipeManager() { | |
return this.resources.managers.getRecipeManager(); | |
} | |
public ServerScoreboard getScoreboard() { | |
return this.scoreboard; | |
} | |
public CommandStorage getCommandStorage() { | |
if (this.commandStorage == null) { | |
throw new NullPointerException("Called before server init"); | |
} else { | |
return this.commandStorage; | |
} | |
} | |
public GameRules getGameRules() { | |
return this.overworld().getGameRules(); | |
} | |
public CustomBossEvents getCustomBossEvents() { | |
return this.customBossEvents; | |
} | |
public boolean isEnforceWhitelist() { | |
return this.enforceWhitelist; | |
} | |
public void setEnforceWhitelist(boolean p_130005_) { | |
this.enforceWhitelist = p_130005_; | |
} | |
public float getCurrentSmoothedTickTime() { | |
return this.smoothedTickTimeMillis; | |
} | |
public ServerTickRateManager tickRateManager() { | |
return this.tickRateManager; | |
} | |
public long getAverageTickTimeNanos() { | |
return this.aggregatedTickTimesNanos / (long)Math.min(100, Math.max(this.tickCount, 1)); | |
} | |
public long[] getTickTimesNanos() { | |
return this.tickTimesNanos; | |
} | |
public int getProfilePermissions(GameProfile p_129945_) { | |
if (this.getPlayerList().isOp(p_129945_)) { | |
ServerOpListEntry serveroplistentry = this.getPlayerList().getOps().get(p_129945_); | |
if (serveroplistentry != null) { | |
return serveroplistentry.getLevel(); | |
} else if (this.isSingleplayerOwner(p_129945_)) { | |
return 4; | |
} else if (this.isSingleplayer()) { | |
return this.getPlayerList().isAllowCommandsForAllPlayers() ? 4 : 0; | |
} else { | |
return this.getOperatorUserPermissionLevel(); | |
} | |
} else { | |
return 0; | |
} | |
} | |
public abstract boolean isSingleplayerOwner(GameProfile p_129840_); | |
public void dumpServerProperties(Path p_177911_) throws IOException { | |
} | |
private void saveDebugReport(Path p_129860_) { | |
Path path = p_129860_.resolve("levels"); | |
try { | |
for (Entry<ResourceKey<Level>, ServerLevel> entry : this.levels.entrySet()) { | |
ResourceLocation resourcelocation = entry.getKey().location(); | |
Path path1 = path.resolve(resourcelocation.getNamespace()).resolve(resourcelocation.getPath()); | |
Files.createDirectories(path1); | |
entry.getValue().saveDebugReport(path1); | |
} | |
this.dumpGameRules(p_129860_.resolve("gamerules.txt")); | |
this.dumpClasspath(p_129860_.resolve("classpath.txt")); | |
this.dumpMiscStats(p_129860_.resolve("stats.txt")); | |
this.dumpThreads(p_129860_.resolve("threads.txt")); | |
this.dumpServerProperties(p_129860_.resolve("server.properties.txt")); | |
this.dumpNativeModules(p_129860_.resolve("modules.txt")); | |
} catch (IOException ioexception) { | |
LOGGER.warn("Failed to save debug report", (Throwable)ioexception); | |
} | |
} | |
private void dumpMiscStats(Path p_129951_) throws IOException { | |
try (Writer writer = Files.newBufferedWriter(p_129951_)) { | |
writer.write(String.format(Locale.ROOT, "pending_tasks: %d\n", this.getPendingTasksCount())); | |
writer.write(String.format(Locale.ROOT, "average_tick_time: %f\n", this.getCurrentSmoothedTickTime())); | |
writer.write(String.format(Locale.ROOT, "tick_times: %s\n", Arrays.toString(this.tickTimesNanos))); | |
writer.write(String.format(Locale.ROOT, "queue: %s\n", Util.backgroundExecutor())); | |
} | |
} | |
private void dumpGameRules(Path p_129984_) throws IOException { | |
try (Writer writer = Files.newBufferedWriter(p_129984_)) { | |
final List<String> list = Lists.newArrayList(); | |
final GameRules gamerules = this.getGameRules(); | |
gamerules.visitGameRuleTypes(new GameRules.GameRuleTypeVisitor() { | |
public <T extends GameRules.Value<T>> void visit(GameRules.Key<T> p_195531_, GameRules.Type<T> p_195532_) { | |
list.add(String.format(Locale.ROOT, "%s=%s\n", p_195531_.getId(), gamerules.getRule(p_195531_))); | |
} | |
}); | |
for (String s : list) { | |
writer.write(s); | |
} | |
} | |
} | |
private void dumpClasspath(Path p_129992_) throws IOException { | |
try (Writer writer = Files.newBufferedWriter(p_129992_)) { | |
String s = System.getProperty("java.class.path"); | |
String s1 = System.getProperty("path.separator"); | |
for (String s2 : Splitter.on(s1).split(s)) { | |
writer.write(s2); | |
writer.write("\n"); | |
} | |
} | |
} | |
private void dumpThreads(Path p_129996_) throws IOException { | |
ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean(); | |
ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true); | |
Arrays.sort(athreadinfo, Comparator.comparing(ThreadInfo::getThreadName)); | |
try (Writer writer = Files.newBufferedWriter(p_129996_)) { | |
for (ThreadInfo threadinfo : athreadinfo) { | |
writer.write(threadinfo.toString()); | |
writer.write(10); | |
} | |
} | |
} | |
private void dumpNativeModules(Path p_195522_) throws IOException { | |
try (Writer writer = Files.newBufferedWriter(p_195522_)) { | |
List<NativeModuleLister.NativeModuleInfo> list; | |
try { | |
list = Lists.newArrayList(NativeModuleLister.listModules()); | |
} catch (Throwable throwable) { | |
LOGGER.warn("Failed to list native modules", throwable); | |
return; | |
} | |
list.sort(Comparator.comparing(p_212910_ -> p_212910_.name)); | |
for (NativeModuleLister.NativeModuleInfo nativemodulelister$nativemoduleinfo : list) { | |
writer.write(nativemodulelister$nativemoduleinfo.toString()); | |
writer.write(10); | |
} | |
} | |
} | |
private ProfilerFiller createProfiler() { | |
if (this.willStartRecordingMetrics) { | |
this.metricsRecorder = ActiveMetricsRecorder.createStarted( | |
new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), | |
Util.timeSource, | |
Util.ioPool(), | |
new MetricsPersister("server"), | |
this.onMetricsRecordingStopped, | |
p_212927_ -> { | |
this.executeBlocking(() -> this.saveDebugReport(p_212927_.resolve("server"))); | |
this.onMetricsRecordingFinished.accept(p_212927_); | |
} | |
); | |
this.willStartRecordingMetrics = false; | |
} | |
this.metricsRecorder.startTick(); | |
return SingleTickProfiler.decorateFiller(this.metricsRecorder.getProfiler(), SingleTickProfiler.createTickProfiler("Server")); | |
} | |
public void endMetricsRecordingTick() { | |
this.metricsRecorder.endTick(); | |
} | |
public boolean isRecordingMetrics() { | |
return this.metricsRecorder.isRecording(); | |
} | |
public void startRecordingMetrics(Consumer<ProfileResults> p_177924_, Consumer<Path> p_177925_) { | |
this.onMetricsRecordingStopped = p_212922_ -> { | |
this.stopRecordingMetrics(); | |
p_177924_.accept(p_212922_); | |
}; | |
this.onMetricsRecordingFinished = p_177925_; | |
this.willStartRecordingMetrics = true; | |
} | |
public void stopRecordingMetrics() { | |
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; | |
} | |
public void finishRecordingMetrics() { | |
this.metricsRecorder.end(); | |
} | |
public void cancelRecordingMetrics() { | |
this.metricsRecorder.cancel(); | |
} | |
public Path getWorldPath(LevelResource p_129844_) { | |
return this.storageSource.getLevelPath(p_129844_); | |
} | |
public boolean forceSynchronousWrites() { | |
return true; | |
} | |
public StructureTemplateManager getStructureManager() { | |
return this.structureTemplateManager; | |
} | |
public WorldData getWorldData() { | |
return this.worldData; | |
} | |
public RegistryAccess.Frozen registryAccess() { | |
return this.registries.compositeAccess(); | |
} | |
public LayeredRegistryAccess<RegistryLayer> registries() { | |
return this.registries; | |
} | |
public ReloadableServerRegistries.Holder reloadableRegistries() { | |
return this.resources.managers.fullRegistries(); | |
} | |
public TextFilter createTextFilterForPlayer(ServerPlayer p_129814_) { | |
return TextFilter.DUMMY; | |
} | |
public ServerPlayerGameMode createGameModeForPlayer(ServerPlayer p_177934_) { | |
return (ServerPlayerGameMode)(this.isDemo() ? new DemoMode(p_177934_) : new ServerPlayerGameMode(p_177934_)); | |
} | |
public GameType getForcedGameType() { | |
return null; | |
} | |
public ResourceManager getResourceManager() { | |
return this.resources.resourceManager; | |
} | |
public boolean isCurrentlySaving() { | |
return this.isSaving; | |
} | |
public boolean isTimeProfilerRunning() { | |
return this.debugCommandProfilerDelayStart || this.debugCommandProfiler != null; | |
} | |
public void startTimeProfiler() { | |
this.debugCommandProfilerDelayStart = true; | |
} | |
public ProfileResults stopTimeProfiler() { | |
if (this.debugCommandProfiler == null) { | |
return EmptyProfileResults.EMPTY; | |
} else { | |
ProfileResults profileresults = this.debugCommandProfiler.stop(Util.getNanos(), this.tickCount); | |
this.debugCommandProfiler = null; | |
return profileresults; | |
} | |
} | |
public int getMaxChainedNeighborUpdates() { | |
return 1000000; | |
} | |
public void logChatMessage(Component p_241503_, ChatType.Bound p_241402_, { String p_241481_) | |
String s = p_241402_.decorate(p_241503_).getString(); | |
if (p_241481_ != null) { | |
LOGGER.info("[{}] {}", p_241481_, s); | |
} else { | |
LOGGER.info("{}", s); | |
} | |
} | |
public ChatDecorator getChatDecorator() { | |
return ChatDecorator.PLAIN; | |
} | |
public boolean logIPs() { | |
return true; | |
} | |
public void subscribeToDebugSample(ServerPlayer p_333749_, RemoteDebugSampleType p_336217_) { | |
} | |
public boolean acceptsTransfers() { | |
return false; | |
} | |
private void storeChunkIoError(CrashReport p_344874_, ChunkPos p_342523_, RegionStorageInfo p_343084_) { | |
Util.ioPool().execute(() -> { | |
try { | |
Path path = this.getFile("debug"); | |
FileUtil.createDirectoriesSafe(path); | |
String s = FileUtil.sanitizeName(p_343084_.level()); | |
Path path1 = path.resolve("chunk-" + s + "-" + Util.getFilenameFormattedDateTime() + "-server.txt"); | |
FileStore filestore = Files.getFileStore(path); | |
long i = filestore.getUsableSpace(); | |
if (i < 8192L) { | |
LOGGER.warn("Not storing chunk IO report due to low space on drive {}", filestore.name()); | |
return; | |
} | |
CrashReportCategory crashreportcategory = p_344874_.addCategory("Chunk Info"); | |
crashreportcategory.setDetail("Level", p_343084_::level); | |
crashreportcategory.setDetail("Dimension", () -> p_343084_.dimension().location().toString()); | |
crashreportcategory.setDetail("Storage", p_343084_::type); | |
crashreportcategory.setDetail("Position", p_342523_::toString); | |
p_344874_.saveToFile(path1, ReportType.CHUNK_IO_ERROR); | |
LOGGER.info("Saved details to {}", p_344874_.getSaveFile()); | |
} catch (Exception exception) { | |
LOGGER.warn("Failed to store chunk IO exception", (Throwable)exception); | |
} | |
}); | |
} | |
public void reportChunkLoadFailure(Throwable p_345315_, RegionStorageInfo p_344502_, ChunkPos p_330022_) { | |
LOGGER.error("Failed to load chunk {},{}", p_330022_.x, p_330022_.z, p_345315_); | |
this.suppressedExceptions.addEntry("chunk/load", p_345315_); | |
this.storeChunkIoError(CrashReport.forThrowable(p_345315_, "Chunk load failure"), p_330022_, p_344502_); | |
} | |
public void reportChunkSaveFailure(Throwable p_343979_, RegionStorageInfo p_345051_, ChunkPos p_333073_) { | |
LOGGER.error("Failed to save chunk {},{}", p_333073_.x, p_333073_.z, p_343979_); | |
this.suppressedExceptions.addEntry("chunk/save", p_343979_); | |
this.storeChunkIoError(CrashReport.forThrowable(p_343979_, "Chunk save failure"), p_333073_, p_345051_); | |
} | |
public void reportPacketHandlingException(Throwable p_366196_, PacketType<?> p_362971_) { | |
this.suppressedExceptions.addEntry("packet/" + p_362971_.toString(), p_366196_); | |
} | |
public PotionBrewing potionBrewing() { | |
return this.potionBrewing; | |
} | |
public FuelValues fuelValues() { | |
return this.fuelValues; | |
} | |
public ServerLinks serverLinks() { | |
return ServerLinks.EMPTY; | |
} | |
protected int pauseWhileEmptySeconds() { | |
return 0; | |
} | |
static record ReloadableResources(CloseableResourceManager resourceManager, ReloadableServerResources managers) implements AutoCloseable { | |
public void close() { | |
this.resourceManager.close(); | |
} | |
} | |
public static record ServerResourcePackInfo(UUID id, String url, String hash, boolean isRequired, @Nullable Component prompt) { | |
} | |
static class TimeProfiler { | |
final long startNanos; | |
final int startTick; | |
TimeProfiler(long p_177958_, int p_177959_) { | |
this.startNanos = p_177958_; | |
this.startTick = p_177959_; | |
} | |
ProfileResults stop(final long p_177961_, final int p_177962_) { | |
return new ProfileResults() { | |
public List<ResultField> getTimes(String p_177972_) { | |
return Collections.emptyList(); | |
} | |
public boolean saveResults(Path p_177974_) { | |
return false; | |
} | |
public long getStartTimeNano() { | |
return TimeProfiler.this.startNanos; | |
} | |
public int getStartTimeTicks() { | |
return TimeProfiler.this.startTick; | |
} | |
public long getEndTimeNano() { | |
return p_177961_; | |
} | |
public int getEndTimeTicks() { | |
return p_177962_; | |
} | |
public String getProfilerResults() { | |
return ""; | |
} | |
}; | |
} | |
} | |
} | |