2018-06-21 15:37:32 -04:00
/*
2022-04-14 03:42:00 +00:00
* Copyright (c) Forge Development LLC and contributors
2022-02-28 13:41:23 -08:00
* 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
2019-10-04 17:16:36 -04:00
import static net.minecraftforge.fml.Logging.CORE ;
2023-05-14 15:26:24 -05:00
import java.io.IOException ;
import java.nio.file.Files ;
2019-10-04 17:16:36 -04:00
import java.nio.file.Path ;
2022-06-07 15:31:26 -05:00
import java.util.List ;
2019-10-04 17:16:36 -04:00
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 ;
2019-10-04 17:16:36 -04:00
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 ;
2022-02-24 19:06:32 -06:00
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 ;
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 ;
2021-10-05 00:10:05 +02:00
import net.minecraft.server.packs.repository.RepositorySource ;
2021-07-17 00:08:49 -05:00
import net.minecraft.world.level.storage.LevelResource ;
2022-06-14 14:05:07 -05:00
import net.minecraftforge.common.world.StructureModifier ;
2020-06-29 22:08:50 -04:00
import net.minecraftforge.fml.DistExecutor ;
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 ;
2020-06-29 22:08:50 -04:00
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 ;
2022-06-14 14:05:07 -05:00
import net.minecraftforge.registries.ForgeRegistries.Keys ;
2022-07-11 20:27:48 -05:00
import net.minecraftforge.resource.PathPackResources ;
2021-12-20 19:34:57 +01:00
import net.minecraftforge.server.permission.PermissionAPI ;
2019-10-04 17:16:36 -04:00
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 ;
2018-06-21 15:37:32 -04:00
import net.minecraft.server.MinecraftServer ;
2018-10-05 21:42:15 -04:00
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 ;
2019-10-04 15:24:15 -04:00
import net.minecraftforge.forgespi.language.IModInfo ;
2022-06-07 15:31:26 -05:00
import net.minecraftforge.registries.ForgeRegistries ;
2020-02-03 21:21:10 +01:00
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 ;
2020-05-13 00:11:45 +02:00
private static Path getServerConfigPath ( final MinecraftServer server )
{
2021-03-09 13:37:23 -08:00
final Path serverConfig = server . getWorldPath ( SERVERCONFIG );
2023-05-14 15:26:24 -05:00
if ( ! Files . isDirectory ( serverConfig )) {
try {
Files . createDirectories ( serverConfig );
} catch ( IOException e ) {
throw new RuntimeException ( e );
}
}
2020-05-13 00:11:45 +02:00
return serverConfig ;
}
2018-06-21 15:37:32 -04:00
public static boolean handleServerAboutToStart ( final MinecraftServer server )
{
currentServer = server ;
2020-06-29 22:08:50 -04:00
// on the dedi server we need to force the stuff to setup properly
2018-06-22 22:45:01 -04:00
LogicalSidedProvider . setServer (() -> server );
2020-05-13 00:11:45 +02:00
ConfigTracker . INSTANCE . loadConfigs ( ModConfig . Type . SERVER , getServerConfigPath ( server ));
2022-06-14 14:05:07 -05:00
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 )
{
2022-02-24 19:06:32 -06:00
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
}
2018-07-01 16:10:13 -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 );
}
2018-07-01 16:10:13 -04:00
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 )
{
2020-02-03 21:21:10 +01:00
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 ;
}
2020-05-13 00:11:45 +02:00
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." );
2021-03-09 13:37:23 -08:00
LOGGER . info ( SERVERHOOKS , "Disconnecting Player (server is still starting): {}" , text . getContents ());
2021-07-17 00:08:49 -05:00
manager . send ( new ClientboundLoginDisconnectPacket ( text ));
2021-03-09 13:37:23 -08:00
manager . disconnect ( text );
2018-06-21 15:37:32 -04:00
return false ;
}
2021-07-17 00:08:49 -05:00
if ( packet . getIntention () == ConnectionProtocol . LOGIN ) {
2019-02-28 00:59:27 -05:00
final ConnectionType connectionType = ConnectionType . forVersionFlag ( packet . getFMLVersion ());
final int versionNumber = connectionType . getFMLVersionNumber ( packet . getFMLVersion ());
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 ;
2019-02-28 00:59:27 -05:00
}
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
}
2021-07-17 00:08:49 -05:00
if ( packet . getIntention () == ConnectionProtocol . STATUS ) return true ;
2019-02-15 21:45:28 -05:00
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 ) {
manager . setProtocol ( ConnectionProtocol . LOGIN );
2023-07-03 16:54:40 -07:00
String ip = "local" ;
if ( manager . getRemoteAddress () != null )
ip = manager . getRemoteAddress (). toString ();
LOGGER . info ( SERVERHOOKS , "[{}] Disconnecting {} connection attempt: {}" , ip , type , message );
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 ));
2021-03-09 13:37:23 -08:00
manager . disconnect ( text );
2019-02-28 00:59:27 -05:00
}
2018-11-28 22:15:05 -08:00
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
2022-07-11 20:27:48 -05:00
public static RepositorySource buildPackFinder ( Map < IModFile , ? extends PathPackResources > modResourcePacks ) {
2022-11-22 13:32:47 -06:00
return packAcceptor -> serverPackFinder ( modResourcePacks , packAcceptor );
2019-10-04 15:24:15 -04:00
}
2022-11-22 13:32:47 -06:00
private static void serverPackFinder ( Map < IModFile , ? extends PathPackResources > modResourcePacks , Consumer < Pack > packAcceptor ) {
2022-07-11 20:27:48 -05:00
for ( Entry < IModFile , ? extends PathPackResources > e : modResourcePacks . entrySet ())
2019-10-04 15:24:15 -04:00
{
IModInfo mod = e . getKey (). getModInfos (). get ( 0 );
if ( Objects . equals ( mod . getModId (), "minecraft" )) continue ; // skip the minecraft "mod"
final String name = "mod:" + mod . getModId ();
2022-11-22 13:32:47 -06:00
final Pack modPack = Pack . readMetaAndCreate ( name , Component . literal ( e . getValue (). packId ()), false , id -> e . getValue (), PackType . SERVER_DATA , Pack . Position . BOTTOM , PackSource . DEFAULT );
if ( modPack == null ) {
2019-10-04 15:24:15 -04:00
// 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 ( CORE , "Generating PackInfo named {} for mod file {}" , name , e . getKey (). getFilePath ());
2022-11-22 13:32:47 -06:00
packAcceptor . accept ( modPack );
2019-10-04 15:24:15 -04:00
}
}
2022-07-11 20:27:48 -05:00
2022-06-14 14:05:07 -05:00
private static void runModifiers ( final MinecraftServer server )
2022-06-07 15:31:26 -05:00
{
final RegistryAccess registries = server . registryAccess ();
2022-06-14 14:05:07 -05:00
2022-06-07 15:31:26 -05:00
// The order of holders() is the order modifiers were loaded in.
2022-06-14 14:05:07 -05:00
final List < BiomeModifier > biomeModifiers = registries . registryOrThrow ( ForgeRegistries . Keys . BIOME_MODIFIERS )
2022-06-07 15:31:26 -05:00
. holders ()
. map ( Holder :: value )
. toList ();
2022-06-14 14:05:07 -05:00
final List < StructureModifier > structureModifiers = registries . registryOrThrow ( Keys . STRUCTURE_MODIFIERS )
. holders ()
. map ( Holder :: value )
. toList ();
2022-07-11 20:27:48 -05:00
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
{
2022-06-14 14:05:07 -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 ->
2022-06-14 14:05:07 -05:00
{
structureHolder . value (). modifiableStructureInfo (). applyStructureModifiers ( structureHolder , structureModifiers );
2022-06-07 15:31:26 -05:00
});
}
2018-06-21 15:37:32 -04:00
}