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
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.concurrent.CountDownLatch ;
import java.util.concurrent.atomic.AtomicBoolean ;
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 ;
2023-09-10 20:27:15 -07:00
import net.minecraft.network.Connection ;
import net.minecraft.network.ConnectionProtocol ;
2022-06-07 15:31:26 -05:00
import net.minecraft.network.chat.Component ;
2023-09-10 20:27:15 -07:00
import net.minecraft.network.protocol.handshake.ClientIntent ;
import net.minecraft.network.protocol.handshake.ClientIntentionPacket ;
import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket ;
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 ;
2021-11-26 18:57:41 +00:00
import net.minecraftforge.network.ConnectionType ;
2023-09-10 20:27:15 -07:00
import net.minecraftforge.network.NetworkContext ;
2021-11-26 18:57:41 +00:00
import net.minecraftforge.network.NetworkRegistry ;
2022-06-14 14:05:07 -05:00
import net.minecraftforge.registries.ForgeRegistries.Keys ;
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 ;
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 ;
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
2023-09-10 20:27:15 -07:00
@SuppressWarnings ( "deprecation" )
@ApiStatus.Internal
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" );
2023-09-10 20:27:15 -07:00
private static final AtomicBoolean allowLogins = new AtomicBoolean ( false );
2018-06-21 15:37:32 -04:00
private static volatile CountDownLatch exitLatch = null ;
private static MinecraftServer currentServer ;
2023-09-10 20:27:15 -07: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 ;
}
2023-09-10 20:27:15 -07:00
public static boolean handleServerAboutToStart ( final MinecraftServer server ) {
2018-06-21 15:37:32 -04:00
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
}
2023-09-10 20:27:15 -07: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
}
2023-09-10 20:27:15 -07:00
public static void expectServerStopped () {
2018-06-21 15:37:32 -04:00
exitLatch = new CountDownLatch ( 1 );
}
2023-09-10 20:27:15 -07:00
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 ;
2023-09-10 20:27:15 -07:00
if ( latch != null ) {
2018-06-21 15:37:32 -04:00
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
}
2023-09-10 20:27:15 -07:00
public static MinecraftServer getCurrentServer () {
2018-06-21 15:37:32 -04:00
return currentServer ;
}
2023-09-10 20:27:15 -07: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 ->
2023-09-10 20:27:15 -07:00
biomeHolder . value (). modifiableBiomeInfo (). applyBiomeModifiers ( biomeHolder , biomeModifiers )
);
2022-06-14 14:05:07 -05:00
// Apply sorted structure modifiers to each structure.
2022-11-22 13:32:47 -06:00
registries . registryOrThrow ( Registries . STRUCTURE ). holders (). forEach ( structureHolder ->
2023-09-10 20:27:15 -07:00
structureHolder . value (). modifiableStructureInfo (). applyStructureModifiers ( structureHolder , structureModifiers )
);
}
//==================================================================================================================================================================================
//==================================================================================================================================================================================
//==================================================================================================================================================================================
//==================================================================================================================================================================================
//==================================================================================================================================================================================
//==================================================================================================================================================================================
public static void handleServerStarted ( final MinecraftServer server ) {
MinecraftForge . EVENT_BUS . post ( new ServerStartedEvent ( server ));
allowLogins . set ( true );
}
public static void handleServerStopping ( final MinecraftServer server ) {
allowLogins . set ( false );
MinecraftForge . EVENT_BUS . post ( new ServerStoppingEvent ( server ));
}
public static boolean handleServerLogin ( final ClientIntentionPacket packet , final Connection connection ) {
var ctx = NetworkContext . get ( connection );
ctx . processIntention ( packet . hostName ());
if ( ! allowLogins . get ())
return rejectConnection ( connection , ctx . getType (), "Server is still starting! Please wait before reconnecting." );
if ( packet . nextProtocol () != ConnectionProtocol . LOGIN )
return true ;
if ( ctx . getType () == ConnectionType . MODDED && ctx . getNetVersion () != NetworkContext . NET_VERSION )
return rejectConnection ( connection , ctx . getType (), "This modded server is not impl compatible with your modded client. Please verify your Forge version closely matches the server. Got net version " + ctx . getNetVersion () + " this server is net version " + NetworkContext . NET_VERSION );
if ( ctx . getType () == ConnectionType . VANILLA && ! NetworkRegistry . acceptsVanillaClientConnections ())
return rejectConnection ( connection , ctx . getType (), "This server has mods that require Forge to be installed on the client. Contact your server admin for more details." );
NetworkRegistry . onConnectionStart ( connection );
return true ;
}
private static boolean rejectConnection ( final Connection connection , ConnectionType type , String message ) {
connection . setClientboundProtocolAfterHandshake ( ClientIntent . LOGIN );
LOGGER . info ( SERVERHOOKS , "[{}] Disconnecting {} connection attempt: {}" , connection . getLoggableAddress ( true ), type , message ); // TODO: Respect logIP setting
var text = Component . literal ( message );
connection . send ( new ClientboundLoginDisconnectPacket ( text ));
connection . disconnect ( text );
return false ;
2022-06-07 15:31:26 -05:00
}
2018-06-21 15:37:32 -04:00
}