318 lines
9.2 KiB
Java
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));
|
|
}
|
|
}
|