minecraft-src/net/minecraft/client/server/IntegratedServer.java
2025-07-04 03:45:38 +03:00

318 lines
9.2 KiB
Java

package net.minecraft.client.server;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import com.mojang.authlib.GameProfile;
import com.mojang.logging.LogUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.UUID;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.CrashReport;
import net.minecraft.SharedConstants;
import net.minecraft.SystemReport;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.toasts.SystemToast;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.Services;
import net.minecraft.server.WorldStem;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.stats.Stats;
import net.minecraft.util.ModCheck;
import net.minecraft.util.debugchart.LocalSampleLogger;
import net.minecraft.util.profiling.Profiler;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@Environment(EnvType.CLIENT)
public class IntegratedServer extends MinecraftServer {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int MIN_SIM_DISTANCE = 2;
private final Minecraft minecraft;
private boolean paused = true;
private int publishedPort = -1;
@Nullable
private GameType publishedGameType;
@Nullable
private LanServerPinger lanPinger;
@Nullable
private UUID uuid;
private int previousSimulationDistance = 0;
public IntegratedServer(
Thread serverThread,
Minecraft minecraft,
LevelStorageSource.LevelStorageAccess storageSource,
PackRepository packRepository,
WorldStem worldStem,
Services services,
ChunkProgressListenerFactory progressListenerFactory
) {
super(serverThread, storageSource, packRepository, worldStem, minecraft.getProxy(), minecraft.getFixerUpper(), services, progressListenerFactory);
this.setSingleplayerProfile(minecraft.getGameProfile());
this.setDemo(minecraft.isDemo());
this.setPlayerList(new IntegratedPlayerList(this, this.registries(), this.playerDataStorage));
this.minecraft = minecraft;
}
@Override
public boolean initServer() {
LOGGER.info("Starting integrated minecraft server version {}", SharedConstants.getCurrentVersion().getName());
this.setUsesAuthentication(true);
this.setPvpAllowed(true);
this.setFlightAllowed(true);
this.initializeKeyPair();
this.loadLevel();
GameProfile gameProfile = this.getSingleplayerProfile();
String string = this.getWorldData().getLevelName();
this.setMotd(gameProfile != null ? gameProfile.getName() + " - " + string : string);
return true;
}
@Override
public boolean isPaused() {
return this.paused;
}
@Override
public void tickServer(BooleanSupplier hasTimeLeft) {
boolean bl = this.paused;
this.paused = Minecraft.getInstance().isPaused();
ProfilerFiller profilerFiller = Profiler.get();
if (!bl && this.paused) {
profilerFiller.push("autoSave");
LOGGER.info("Saving and pausing game...");
this.saveEverything(false, false, false);
profilerFiller.pop();
}
boolean bl2 = Minecraft.getInstance().getConnection() != null;
if (bl2 && this.paused) {
this.tickPaused();
} else {
if (bl && !this.paused) {
this.forceTimeSynchronization();
}
super.tickServer(hasTimeLeft);
int i = Math.max(2, this.minecraft.options.renderDistance().get());
if (i != this.getPlayerList().getViewDistance()) {
LOGGER.info("Changing view distance to {}, from {}", i, this.getPlayerList().getViewDistance());
this.getPlayerList().setViewDistance(i);
}
int j = Math.max(2, this.minecraft.options.simulationDistance().get());
if (j != this.previousSimulationDistance) {
LOGGER.info("Changing simulation distance to {}, from {}", j, this.previousSimulationDistance);
this.getPlayerList().setSimulationDistance(j);
this.previousSimulationDistance = j;
}
}
}
protected LocalSampleLogger getTickTimeLogger() {
return this.minecraft.getDebugOverlay().getTickTimeLogger();
}
@Override
public boolean isTickTimeLoggingEnabled() {
return true;
}
private void tickPaused() {
for (ServerPlayer serverPlayer : this.getPlayerList().getPlayers()) {
serverPlayer.awardStat(Stats.TOTAL_WORLD_TIME);
}
}
@Override
public boolean shouldRconBroadcast() {
return true;
}
@Override
public boolean shouldInformAdmins() {
return true;
}
@Override
public Path getServerDirectory() {
return this.minecraft.gameDirectory.toPath();
}
@Override
public boolean isDedicatedServer() {
return false;
}
@Override
public int getRateLimitPacketsPerSecond() {
return 0;
}
@Override
public boolean isEpollEnabled() {
return false;
}
@Override
public void onServerCrash(CrashReport report) {
this.minecraft.delayCrashRaw(report);
}
@Override
public SystemReport fillServerSystemReport(SystemReport report) {
report.setDetail("Type", "Integrated Server (map_client.txt)");
report.setDetail("Is Modded", (Supplier<String>)(() -> this.getModdedStatus().fullDescription()));
report.setDetail("Launched Version", this.minecraft::getLaunchedVersion);
return report;
}
@Override
public ModCheck getModdedStatus() {
return Minecraft.checkModStatus().merge(super.getModdedStatus());
}
@Override
public boolean publishServer(@Nullable GameType gameMode, boolean commands, int port) {
try {
this.minecraft.prepareForMultiplayer();
this.minecraft.getConnection().prepareKeyPair();
this.getConnection().startTcpServerListener(null, port);
LOGGER.info("Started serving on {}", port);
this.publishedPort = port;
this.lanPinger = new LanServerPinger(this.getMotd(), port + "");
this.lanPinger.start();
this.publishedGameType = gameMode;
this.getPlayerList().setAllowCommandsForAllPlayers(commands);
int i = this.getProfilePermissions(this.minecraft.player.getGameProfile());
this.minecraft.player.setPermissionLevel(i);
for (ServerPlayer serverPlayer : this.getPlayerList().getPlayers()) {
this.getCommands().sendCommands(serverPlayer);
}
return true;
} catch (IOException var7) {
return false;
}
}
@Override
public void stopServer() {
super.stopServer();
if (this.lanPinger != null) {
this.lanPinger.interrupt();
this.lanPinger = null;
}
}
@Override
public void halt(boolean waitForServer) {
this.executeBlocking(() -> {
for (ServerPlayer serverPlayer : Lists.newArrayList(this.getPlayerList().getPlayers())) {
if (!serverPlayer.getUUID().equals(this.uuid)) {
this.getPlayerList().remove(serverPlayer);
}
}
});
super.halt(waitForServer);
if (this.lanPinger != null) {
this.lanPinger.interrupt();
this.lanPinger = null;
}
}
@Override
public boolean isPublished() {
return this.publishedPort > -1;
}
@Override
public int getPort() {
return this.publishedPort;
}
@Override
public void setDefaultGameType(GameType gameMode) {
super.setDefaultGameType(gameMode);
this.publishedGameType = null;
}
@Override
public boolean isCommandBlockEnabled() {
return true;
}
@Override
public int getOperatorUserPermissionLevel() {
return 2;
}
@Override
public int getFunctionCompilationLevel() {
return 2;
}
public void setUUID(UUID uuid) {
this.uuid = uuid;
}
@Override
public boolean isSingleplayerOwner(GameProfile profile) {
return this.getSingleplayerProfile() != null && profile.getName().equalsIgnoreCase(this.getSingleplayerProfile().getName());
}
@Override
public int getScaledTrackingDistance(int trackingDistance) {
return (int)(this.minecraft.options.entityDistanceScaling().get() * trackingDistance);
}
@Override
public boolean forceSynchronousWrites() {
return this.minecraft.options.syncWrites;
}
@Nullable
@Override
public GameType getForcedGameType() {
return this.isPublished() && !this.isHardcore() ? MoreObjects.firstNonNull(this.publishedGameType, this.worldData.getGameType()) : null;
}
@Override
public boolean saveEverything(boolean suppressLog, boolean flush, boolean forced) {
boolean bl = super.saveEverything(suppressLog, flush, forced);
this.warnOnLowDiskSpace();
return bl;
}
private void warnOnLowDiskSpace() {
if (this.storageSource.checkForLowDiskSpace()) {
this.minecraft.execute(() -> SystemToast.onLowDiskSpace(this.minecraft));
}
}
@Override
public void reportChunkLoadFailure(Throwable throwable, RegionStorageInfo regionStorageInfo, ChunkPos chunkPos) {
super.reportChunkLoadFailure(throwable, regionStorageInfo, chunkPos);
this.warnOnLowDiskSpace();
this.minecraft.execute(() -> SystemToast.onChunkLoadFailure(this.minecraft, chunkPos));
}
@Override
public void reportChunkSaveFailure(Throwable throwable, RegionStorageInfo regionStorageInfo, ChunkPos chunkPos) {
super.reportChunkSaveFailure(throwable, regionStorageInfo, chunkPos);
this.warnOnLowDiskSpace();
this.minecraft.execute(() -> SystemToast.onChunkSaveFailure(this.minecraft, chunkPos));
}
}