Files
MinecraftForge/src/main/java/net/minecraftforge/server/ServerLifecycleHooks.java
T

261 lines
11 KiB
Java
Raw Normal View History

2018-06-21 15:37:32 -04:00
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
2018-06-21 15:37:32 -04:00
*/
2021-11-26 18:57:41 +00:00
package net.minecraftforge.server;
2018-06-21 15:37:32 -04:00
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
2022-06-07 15:31:26 -05:00
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
2020-06-19 10:58:45 -04:00
import java.util.function.Consumer;
2022-06-07 15:31:26 -05:00
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
2022-11-22 13:32:47 -06:00
import net.minecraft.core.registries.Registries;
import net.minecraft.gametest.framework.GameTestServer;
2022-06-07 15:31:26 -05:00
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
2023-09-07 20:23:27 -07:00
import net.minecraft.server.packs.PackResources;
2022-11-22 13:32:47 -06:00
import net.minecraft.server.packs.PackType;
2021-07-17 00:08:49 -05:00
import net.minecraft.server.packs.repository.PackSource;
import net.minecraft.server.packs.repository.RepositorySource;
2021-07-17 00:08:49 -05:00
import net.minecraft.world.level.storage.LevelResource;
import net.minecraftforge.common.world.StructureModifier;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.Logging;
2021-11-26 18:57:41 +00:00
import net.minecraftforge.common.util.LogicalSidedProvider;
2022-06-07 15:31:26 -05:00
import net.minecraftforge.common.world.BiomeModifier;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.ModLoadingStage;
import net.minecraftforge.fml.ModLoadingWarning;
2021-11-26 18:57:41 +00:00
import net.minecraftforge.network.ConnectionType;
import net.minecraftforge.network.NetworkConstants;
import net.minecraftforge.network.NetworkHooks;
import net.minecraftforge.network.NetworkRegistry;
2021-07-17 00:08:49 -05:00
import net.minecraftforge.forgespi.locating.IModFile;
import net.minecraftforge.registries.ForgeRegistries.Keys;
import net.minecraftforge.resource.PathPackResources;
2021-12-20 19:34:57 +01:00
import net.minecraftforge.server.permission.PermissionAPI;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
2021-07-17 00:08:49 -05:00
import net.minecraft.network.Connection;
import net.minecraft.network.ConnectionProtocol;
import net.minecraft.network.protocol.handshake.ClientIntentionPacket;
import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket;
import net.minecraft.server.packs.repository.Pack;
2023-09-07 20:23:27 -07:00
import net.minecraft.server.packs.repository.Pack.Info;
2018-06-21 15:37:32 -04:00
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.api.distmarker.Dist;
2018-06-21 15:37:32 -04:00
import net.minecraftforge.common.MinecraftForge;
2019-01-28 22:42:37 -05:00
import net.minecraftforge.fml.config.ConfigTracker;
import net.minecraftforge.fml.config.ModConfig;
2021-11-26 18:57:41 +00:00
import net.minecraftforge.event.server.ServerAboutToStartEvent;
import net.minecraftforge.event.server.ServerStartedEvent;
import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.event.server.ServerStoppedEvent;
import net.minecraftforge.event.server.ServerStoppingEvent;
import net.minecraftforge.forgespi.language.IModInfo;
2022-06-07 15:31:26 -05:00
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.GameData;
2022-11-22 13:32:47 -06:00
import org.jetbrains.annotations.ApiStatus;
2018-06-21 15:37:32 -04:00
public class ServerLifecycleHooks
{
2018-08-27 13:10:07 -04:00
private static final Logger LOGGER = LogManager.getLogger();
2018-06-21 15:37:32 -04:00
private static final Marker SERVERHOOKS = MarkerManager.getMarker("SERVERHOOKS");
2021-07-17 00:08:49 -05:00
private static final LevelResource SERVERCONFIG = new LevelResource("serverconfig");
2018-06-21 15:37:32 -04:00
private static volatile CountDownLatch exitLatch = null;
private static MinecraftServer currentServer;
private static Path getServerConfigPath(final MinecraftServer server)
{
final Path serverConfig = server.getWorldPath(SERVERCONFIG);
if (!Files.isDirectory(serverConfig)) {
try {
Files.createDirectories(serverConfig);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return serverConfig;
}
2018-06-21 15:37:32 -04:00
public static boolean handleServerAboutToStart(final MinecraftServer server)
{
currentServer = server;
// on the dedi server we need to force the stuff to setup properly
2018-06-22 22:45:01 -04:00
LogicalSidedProvider.setServer(()->server);
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.SERVER, getServerConfigPath(server));
runModifiers(server);
2021-11-26 18:57:41 +00:00
return !MinecraftForge.EVENT_BUS.post(new ServerAboutToStartEvent(server));
2018-06-21 15:37:32 -04:00
}
public static boolean handleServerStarting(final MinecraftServer server)
{
DistExecutor.runWhenOn(Dist.DEDICATED_SERVER, ()->()->{
LanguageHook.loadLanguagesOnServer(server);
// GameTestServer requires the gametests to be registered earlier, so it is done in main and should not be done twice.
if (!(server instanceof GameTestServer))
net.minecraftforge.gametest.ForgeGameTestHooks.registerGametests();
});
2021-12-20 19:34:57 +01:00
PermissionAPI.initializePermissionAPI();
2021-11-26 18:57:41 +00:00
return !MinecraftForge.EVENT_BUS.post(new ServerStartingEvent(server));
2018-06-21 15:37:32 -04:00
}
public static void handleServerStarted(final MinecraftServer server)
2018-06-21 15:37:32 -04:00
{
2021-11-26 18:57:41 +00:00
MinecraftForge.EVENT_BUS.post(new ServerStartedEvent(server));
2018-06-21 15:37:32 -04:00
allowLogins.set(true);
}
public static void handleServerStopping(final MinecraftServer server)
2018-06-21 15:37:32 -04:00
{
allowLogins.set(false);
2021-11-26 18:57:41 +00:00
MinecraftForge.EVENT_BUS.post(new ServerStoppingEvent(server));
2018-06-21 15:37:32 -04:00
}
public static void expectServerStopped()
{
exitLatch = new CountDownLatch(1);
}
public static void handleServerStopped(final MinecraftServer server)
{
if (!server.isDedicatedServer()) GameData.revertToFrozen();
2021-11-26 18:57:41 +00:00
MinecraftForge.EVENT_BUS.post(new ServerStoppedEvent(server));
2018-06-21 15:37:32 -04:00
currentServer = null;
2018-06-22 22:45:01 -04:00
LogicalSidedProvider.setServer(null);
2018-06-21 15:37:32 -04:00
CountDownLatch latch = exitLatch;
if (latch != null)
{
latch.countDown();
exitLatch = null;
}
ConfigTracker.INSTANCE.unloadConfigs(ModConfig.Type.SERVER, getServerConfigPath(server));
2018-06-21 15:37:32 -04:00
}
public static MinecraftServer getCurrentServer()
{
return currentServer;
}
private static AtomicBoolean allowLogins = new AtomicBoolean(false);
2021-07-17 00:08:49 -05:00
public static boolean handleServerLogin(final ClientIntentionPacket packet, final Connection manager) {
2018-06-21 15:37:32 -04:00
if (!allowLogins.get())
{
2022-06-07 15:31:26 -05:00
MutableComponent text = Component.literal("Server is still starting! Please wait before reconnecting.");
LOGGER.info(SERVERHOOKS,"Disconnecting Player (server is still starting): {}", text.getContents());
2021-07-17 00:08:49 -05:00
manager.send(new ClientboundLoginDisconnectPacket(text));
manager.disconnect(text);
2018-06-21 15:37:32 -04:00
return false;
}
2023-09-07 20:23:27 -07:00
if (packet.nextProtocol() == ConnectionProtocol.LOGIN) {
var fmlVersion = NetworkHooks.getFMLVersion(packet.hostName());
final ConnectionType connectionType = ConnectionType.forVersionFlag(fmlVersion);
final int versionNumber = connectionType.getFMLVersionNumber(fmlVersion);
2022-06-07 15:31:26 -05:00
if (connectionType == ConnectionType.MODDED && versionNumber != NetworkConstants.FMLNETVERSION) {
rejectConnection(manager, connectionType, "This modded server is not impl compatible with your modded client. Please verify your Forge version closely matches the server. Got net version " + versionNumber + " this server is net version " + NetworkConstants.FMLNETVERSION);
return false;
}
if (connectionType == ConnectionType.VANILLA && !NetworkRegistry.acceptsVanillaClientConnections()) {
rejectConnection(manager, connectionType, "This server has mods that require Forge to be installed on the client. Contact your server admin for more details.");
return false;
}
2018-06-21 15:37:32 -04:00
}
2023-09-07 20:23:27 -07:00
if (packet.nextProtocol() == ConnectionProtocol.STATUS) return true;
2018-09-04 20:23:45 -04:00
NetworkHooks.registerServerLoginChannel(manager, packet);
2018-06-21 15:37:32 -04:00
return true;
}
2021-07-17 00:08:49 -05:00
private static void rejectConnection(final Connection manager, ConnectionType type, String message) {
2023-09-07 20:23:27 -07:00
//manager.setProtocol(ConnectionProtocol.LOGIN); Pretty sure things auto swap in ProtocolSwapHandler
LOGGER.info(SERVERHOOKS, "[{}] Disconnecting {} connection attempt: {}", manager.getLoggableAddress(true), type, message); // TODO: Respect logIP setting
2022-06-07 15:31:26 -05:00
MutableComponent text = Component.literal(message);
2021-07-17 00:08:49 -05:00
manager.send(new ClientboundLoginDisconnectPacket(text));
manager.disconnect(text);
}
public static void handleExit(int retVal)
2018-06-21 15:37:32 -04:00
{
System.exit(retVal);
}
2022-11-22 13:32:47 -06:00
@ApiStatus.Internal
public static RepositorySource buildPackFinder(Map<IModFile, ? extends PathPackResources> modResourcePacks) {
2022-11-22 13:32:47 -06:00
return packAcceptor -> serverPackFinder(modResourcePacks, packAcceptor);
}
2022-11-22 13:32:47 -06:00
private static void serverPackFinder(Map<IModFile, ? extends PathPackResources> modResourcePacks, Consumer<Pack> packAcceptor) {
for (Entry<IModFile, ? extends PathPackResources> e : modResourcePacks.entrySet())
{
IModInfo mod = e.getKey().getModInfos().get(0);
if (Objects.equals(mod.getModId(), "minecraft")) continue; // skip the minecraft "mod"
final String name = "mod:" + mod.getModId();
2023-09-07 20:23:27 -07:00
var supplier = new Pack.ResourcesSupplier() {
@Override
public PackResources openPrimary(String path) {
return e.getValue();
}
@Override
public PackResources openFull(String path, Info info) {
return e.getValue(); // TODO: composite
}
};
final Pack modPack = Pack.readMetaAndCreate(name, Component.literal(e.getValue().packId()), false, supplier, PackType.SERVER_DATA, Pack.Position.BOTTOM, PackSource.DEFAULT);
2022-11-22 13:32:47 -06:00
if (modPack == null) {
// Vanilla only logs an error, instead of propagating, so handle null and warn that something went wrong
ModLoader.get().addWarning(new ModLoadingWarning(mod, ModLoadingStage.ERROR, "fml.modloading.brokenresources", e.getKey()));
continue;
}
LOGGER.debug(Logging.CORE, "Generating PackInfo named {} for mod file {}", name, e.getKey().getFilePath());
2022-11-22 13:32:47 -06:00
packAcceptor.accept(modPack);
}
}
private static void runModifiers(final MinecraftServer server)
2022-06-07 15:31:26 -05:00
{
final RegistryAccess registries = server.registryAccess();
2022-06-07 15:31:26 -05:00
// The order of holders() is the order modifiers were loaded in.
final List<BiomeModifier> biomeModifiers = registries.registryOrThrow(ForgeRegistries.Keys.BIOME_MODIFIERS)
2022-06-07 15:31:26 -05:00
.holders()
.map(Holder::value)
.toList();
final List<StructureModifier> structureModifiers = registries.registryOrThrow(Keys.STRUCTURE_MODIFIERS)
.holders()
.map(Holder::value)
.toList();
2022-06-07 15:31:26 -05:00
// Apply sorted biome modifiers to each biome.
2022-11-22 13:32:47 -06:00
registries.registryOrThrow(Registries.BIOME).holders().forEach(biomeHolder ->
2022-06-07 15:31:26 -05:00
{
biomeHolder.value().modifiableBiomeInfo().applyBiomeModifiers(biomeHolder, biomeModifiers);
});
// Apply sorted structure modifiers to each structure.
2022-11-22 13:32:47 -06:00
registries.registryOrThrow(Registries.STRUCTURE).holders().forEach(structureHolder ->
{
structureHolder.value().modifiableStructureInfo().applyStructureModifiers(structureHolder, structureModifiers);
2022-06-07 15:31:26 -05:00
});
}
2018-06-21 15:37:32 -04:00
}