mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-27 03:27:56 +01:00
Server process (#550)
This commit is contained in:
parent
0bd736d837
commit
5bbf4642e8
@ -21,6 +21,7 @@ import net.minestom.server.event.player.PlayerDeathEvent;
|
|||||||
import net.minestom.server.event.player.PlayerDisconnectEvent;
|
import net.minestom.server.event.player.PlayerDisconnectEvent;
|
||||||
import net.minestom.server.event.player.PlayerLoginEvent;
|
import net.minestom.server.event.player.PlayerLoginEvent;
|
||||||
import net.minestom.server.event.player.PlayerSpawnEvent;
|
import net.minestom.server.event.player.PlayerSpawnEvent;
|
||||||
|
import net.minestom.server.event.server.ServerTickMonitorEvent;
|
||||||
import net.minestom.server.instance.Instance;
|
import net.minestom.server.instance.Instance;
|
||||||
import net.minestom.server.instance.InstanceContainer;
|
import net.minestom.server.instance.InstanceContainer;
|
||||||
import net.minestom.server.instance.InstanceManager;
|
import net.minestom.server.instance.InstanceManager;
|
||||||
@ -133,7 +134,7 @@ public class PlayerInit {
|
|||||||
var eventHandler = MinecraftServer.getGlobalEventHandler();
|
var eventHandler = MinecraftServer.getGlobalEventHandler();
|
||||||
eventHandler.addChild(DEMO_NODE);
|
eventHandler.addChild(DEMO_NODE);
|
||||||
|
|
||||||
MinecraftServer.getUpdateManager().addTickMonitor(LAST_TICK::set);
|
eventHandler.addListener(ServerTickMonitorEvent.class, event -> LAST_TICK.set(event.getTickMonitor()));
|
||||||
|
|
||||||
BenchmarkManager benchmarkManager = MinecraftServer.getBenchmarkManager();
|
BenchmarkManager benchmarkManager = MinecraftServer.getBenchmarkManager();
|
||||||
MinecraftServer.getSchedulerManager().buildTask(() -> {
|
MinecraftServer.getSchedulerManager().buildTask(() -> {
|
||||||
|
@ -4,17 +4,12 @@ import net.minestom.server.advancements.AdvancementManager;
|
|||||||
import net.minestom.server.adventure.bossbar.BossBarManager;
|
import net.minestom.server.adventure.bossbar.BossBarManager;
|
||||||
import net.minestom.server.command.CommandManager;
|
import net.minestom.server.command.CommandManager;
|
||||||
import net.minestom.server.data.DataManager;
|
import net.minestom.server.data.DataManager;
|
||||||
import net.minestom.server.data.DataType;
|
|
||||||
import net.minestom.server.data.SerializableData;
|
|
||||||
import net.minestom.server.event.GlobalEventHandler;
|
import net.minestom.server.event.GlobalEventHandler;
|
||||||
import net.minestom.server.exception.ExceptionManager;
|
import net.minestom.server.exception.ExceptionManager;
|
||||||
import net.minestom.server.extensions.Extension;
|
|
||||||
import net.minestom.server.extensions.ExtensionManager;
|
import net.minestom.server.extensions.ExtensionManager;
|
||||||
import net.minestom.server.fluid.Fluid;
|
|
||||||
import net.minestom.server.gamedata.tags.TagManager;
|
import net.minestom.server.gamedata.tags.TagManager;
|
||||||
import net.minestom.server.instance.InstanceManager;
|
import net.minestom.server.instance.InstanceManager;
|
||||||
import net.minestom.server.instance.block.BlockManager;
|
import net.minestom.server.instance.block.BlockManager;
|
||||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
|
||||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||||
import net.minestom.server.monitoring.BenchmarkManager;
|
import net.minestom.server.monitoring.BenchmarkManager;
|
||||||
import net.minestom.server.network.ConnectionManager;
|
import net.minestom.server.network.ConnectionManager;
|
||||||
@ -25,10 +20,8 @@ import net.minestom.server.network.socket.Server;
|
|||||||
import net.minestom.server.ping.ResponseDataConsumer;
|
import net.minestom.server.ping.ResponseDataConsumer;
|
||||||
import net.minestom.server.recipe.RecipeManager;
|
import net.minestom.server.recipe.RecipeManager;
|
||||||
import net.minestom.server.scoreboard.TeamManager;
|
import net.minestom.server.scoreboard.TeamManager;
|
||||||
import net.minestom.server.storage.StorageLocation;
|
|
||||||
import net.minestom.server.storage.StorageManager;
|
import net.minestom.server.storage.StorageManager;
|
||||||
import net.minestom.server.terminal.MinestomTerminal;
|
import net.minestom.server.thread.TickSchedulerThread;
|
||||||
import net.minestom.server.thread.MinestomThreadPool;
|
|
||||||
import net.minestom.server.timer.SchedulerManager;
|
import net.minestom.server.timer.SchedulerManager;
|
||||||
import net.minestom.server.utils.MathUtils;
|
import net.minestom.server.utils.MathUtils;
|
||||||
import net.minestom.server.utils.PacketUtils;
|
import net.minestom.server.utils.PacketUtils;
|
||||||
@ -36,8 +29,10 @@ import net.minestom.server.utils.validate.Check;
|
|||||||
import net.minestom.server.world.Difficulty;
|
import net.minestom.server.world.Difficulty;
|
||||||
import net.minestom.server.world.DimensionTypeManager;
|
import net.minestom.server.world.DimensionTypeManager;
|
||||||
import net.minestom.server.world.biomes.BiomeManager;
|
import net.minestom.server.world.biomes.BiomeManager;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -75,40 +70,9 @@ public final class MinecraftServer {
|
|||||||
// Network monitoring
|
// Network monitoring
|
||||||
private static int rateLimit = 300;
|
private static int rateLimit = 300;
|
||||||
private static int maxPacketSize = 30_000;
|
private static int maxPacketSize = 30_000;
|
||||||
// Network
|
|
||||||
private static PacketListenerManager packetListenerManager;
|
|
||||||
private static PacketProcessor packetProcessor;
|
|
||||||
private static Server server;
|
|
||||||
|
|
||||||
private static ExceptionManager exceptionManager;
|
|
||||||
|
|
||||||
// In-Game Manager
|
// In-Game Manager
|
||||||
private static ConnectionManager connectionManager;
|
private static volatile ServerProcess serverProcess;
|
||||||
private static InstanceManager instanceManager;
|
|
||||||
private static BlockManager blockManager;
|
|
||||||
private static CommandManager commandManager;
|
|
||||||
private static RecipeManager recipeManager;
|
|
||||||
private static StorageManager storageManager;
|
|
||||||
private static DataManager dataManager;
|
|
||||||
private static TeamManager teamManager;
|
|
||||||
private static SchedulerManager schedulerManager;
|
|
||||||
private static BenchmarkManager benchmarkManager;
|
|
||||||
private static DimensionTypeManager dimensionTypeManager;
|
|
||||||
private static BiomeManager biomeManager;
|
|
||||||
private static AdvancementManager advancementManager;
|
|
||||||
private static BossBarManager bossBarManager;
|
|
||||||
|
|
||||||
private static ExtensionManager extensionManager;
|
|
||||||
|
|
||||||
private static final GlobalEventHandler GLOBAL_EVENT_HANDLER = new GlobalEventHandler();
|
|
||||||
|
|
||||||
private static UpdateManager updateManager;
|
|
||||||
private static MinecraftServer minecraftServer;
|
|
||||||
|
|
||||||
// Data
|
|
||||||
private static boolean initialized;
|
|
||||||
private static boolean started;
|
|
||||||
private static volatile boolean stopping;
|
|
||||||
|
|
||||||
private static int chunkViewDistance = Integer.getInteger("minestom.chunk-view-distance", 8);
|
private static int chunkViewDistance = Integer.getInteger("minestom.chunk-view-distance", 8);
|
||||||
private static int entityViewDistance = Integer.getInteger("minestom.entity-view-distance", 5);
|
private static int entityViewDistance = Integer.getInteger("minestom.entity-view-distance", 5);
|
||||||
@ -117,57 +81,22 @@ public final class MinecraftServer {
|
|||||||
private static ResponseDataConsumer responseDataConsumer;
|
private static ResponseDataConsumer responseDataConsumer;
|
||||||
private static String brandName = "Minestom";
|
private static String brandName = "Minestom";
|
||||||
private static Difficulty difficulty = Difficulty.NORMAL;
|
private static Difficulty difficulty = Difficulty.NORMAL;
|
||||||
private static TagManager tagManager;
|
|
||||||
|
|
||||||
public static MinecraftServer init() {
|
public static MinecraftServer init() {
|
||||||
if (minecraftServer != null) // don't init twice
|
updateProcess();
|
||||||
return minecraftServer;
|
return new MinecraftServer();
|
||||||
|
|
||||||
// Initialize the ExceptionManager at first
|
|
||||||
exceptionManager = new ExceptionManager();
|
|
||||||
|
|
||||||
extensionManager = new ExtensionManager();
|
|
||||||
|
|
||||||
// warmup/force-init registries
|
|
||||||
// without this line, registry types that are not loaded explicitly will have an internal empty registry in Registries
|
|
||||||
// That can happen with PotionType for instance, if no code tries to access a PotionType field
|
|
||||||
// TODO: automate (probably with code generation)
|
|
||||||
Fluid.values();
|
|
||||||
|
|
||||||
connectionManager = new ConnectionManager();
|
|
||||||
// Networking
|
|
||||||
packetProcessor = new PacketProcessor();
|
|
||||||
packetListenerManager = new PacketListenerManager();
|
|
||||||
|
|
||||||
instanceManager = new InstanceManager();
|
|
||||||
blockManager = new BlockManager();
|
|
||||||
commandManager = new CommandManager();
|
|
||||||
recipeManager = new RecipeManager();
|
|
||||||
storageManager = new StorageManager();
|
|
||||||
dataManager = new DataManager();
|
|
||||||
teamManager = new TeamManager();
|
|
||||||
schedulerManager = new SchedulerManager();
|
|
||||||
benchmarkManager = new BenchmarkManager();
|
|
||||||
dimensionTypeManager = new DimensionTypeManager();
|
|
||||||
biomeManager = new BiomeManager();
|
|
||||||
advancementManager = new AdvancementManager();
|
|
||||||
bossBarManager = new BossBarManager();
|
|
||||||
|
|
||||||
updateManager = new UpdateManager();
|
|
||||||
|
|
||||||
tagManager = new TagManager();
|
|
||||||
|
|
||||||
try {
|
|
||||||
server = new Server(packetProcessor);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
@ApiStatus.Internal
|
||||||
|
public static ServerProcess updateProcess() {
|
||||||
minecraftServer = new MinecraftServer();
|
ServerProcess process;
|
||||||
|
try {
|
||||||
return minecraftServer;
|
process = new ServerProcessImpl();
|
||||||
|
serverProcess = process;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -247,108 +176,51 @@ public final class MinecraftServer {
|
|||||||
PacketUtils.broadcastPacket(new ServerDifficultyPacket(difficulty, true));
|
PacketUtils.broadcastPacket(new ServerDifficultyPacket(difficulty, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@ApiStatus.Experimental
|
||||||
* Gets the global event handler.
|
public static @UnknownNullability ServerProcess process() {
|
||||||
* <p>
|
return serverProcess;
|
||||||
* Used to register event callback at a global scale.
|
}
|
||||||
*
|
|
||||||
* @return the global event handler
|
|
||||||
*/
|
|
||||||
public static @NotNull GlobalEventHandler getGlobalEventHandler() {
|
public static @NotNull GlobalEventHandler getGlobalEventHandler() {
|
||||||
return GLOBAL_EVENT_HANDLER;
|
return serverProcess.eventHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling all incoming packets
|
|
||||||
*
|
|
||||||
* @return the packet listener manager
|
|
||||||
*/
|
|
||||||
public static PacketListenerManager getPacketListenerManager() {
|
public static PacketListenerManager getPacketListenerManager() {
|
||||||
checkInitStatus(packetListenerManager);
|
return serverProcess.packetListener();
|
||||||
return packetListenerManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling all registered instances.
|
|
||||||
*
|
|
||||||
* @return the instance manager
|
|
||||||
*/
|
|
||||||
public static InstanceManager getInstanceManager() {
|
public static InstanceManager getInstanceManager() {
|
||||||
checkInitStatus(instanceManager);
|
return serverProcess.instance();
|
||||||
return instanceManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling {@link net.minestom.server.instance.block.BlockHandler block handlers}
|
|
||||||
* and {@link BlockPlacementRule placement rules}.
|
|
||||||
*
|
|
||||||
* @return the block manager
|
|
||||||
*/
|
|
||||||
public static BlockManager getBlockManager() {
|
public static BlockManager getBlockManager() {
|
||||||
checkInitStatus(blockManager);
|
return serverProcess.block();
|
||||||
return blockManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling commands.
|
|
||||||
*
|
|
||||||
* @return the command manager
|
|
||||||
*/
|
|
||||||
public static CommandManager getCommandManager() {
|
public static CommandManager getCommandManager() {
|
||||||
checkInitStatus(commandManager);
|
return serverProcess.command();
|
||||||
return commandManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling recipes show to the clients.
|
|
||||||
*
|
|
||||||
* @return the recipe manager
|
|
||||||
*/
|
|
||||||
public static RecipeManager getRecipeManager() {
|
public static RecipeManager getRecipeManager() {
|
||||||
checkInitStatus(recipeManager);
|
return serverProcess.recipe();
|
||||||
return recipeManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling storage.
|
|
||||||
*
|
|
||||||
* @return the storage manager
|
|
||||||
*/
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static StorageManager getStorageManager() {
|
public static StorageManager getStorageManager() {
|
||||||
checkInitStatus(storageManager);
|
return serverProcess.storage();
|
||||||
return storageManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling {@link DataType} used by {@link SerializableData}.
|
|
||||||
*
|
|
||||||
* @return the data manager
|
|
||||||
*/
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static DataManager getDataManager() {
|
public static DataManager getDataManager() {
|
||||||
checkInitStatus(dataManager);
|
return serverProcess.data();
|
||||||
return dataManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling teams.
|
|
||||||
*
|
|
||||||
* @return the team manager
|
|
||||||
*/
|
|
||||||
public static TeamManager getTeamManager() {
|
public static TeamManager getTeamManager() {
|
||||||
checkInitStatus(teamManager);
|
return serverProcess.team();
|
||||||
return teamManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling scheduled tasks.
|
|
||||||
*
|
|
||||||
* @return the scheduler manager
|
|
||||||
*/
|
|
||||||
public static SchedulerManager getSchedulerManager() {
|
public static SchedulerManager getSchedulerManager() {
|
||||||
checkInitStatus(schedulerManager);
|
return serverProcess.scheduler();
|
||||||
return schedulerManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -357,68 +229,31 @@ public final class MinecraftServer {
|
|||||||
* @return the benchmark manager
|
* @return the benchmark manager
|
||||||
*/
|
*/
|
||||||
public static BenchmarkManager getBenchmarkManager() {
|
public static BenchmarkManager getBenchmarkManager() {
|
||||||
checkInitStatus(benchmarkManager);
|
return serverProcess.benchmark();
|
||||||
return benchmarkManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the exception manager for exception handling.
|
|
||||||
*
|
|
||||||
* @return the exception manager
|
|
||||||
*/
|
|
||||||
public static ExceptionManager getExceptionManager() {
|
public static ExceptionManager getExceptionManager() {
|
||||||
checkInitStatus(exceptionManager);
|
return serverProcess.exception();
|
||||||
return exceptionManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling server connections.
|
|
||||||
*
|
|
||||||
* @return the connection manager
|
|
||||||
*/
|
|
||||||
public static ConnectionManager getConnectionManager() {
|
public static ConnectionManager getConnectionManager() {
|
||||||
checkInitStatus(connectionManager);
|
return serverProcess.connection();
|
||||||
return connectionManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the boss bar manager.
|
|
||||||
*
|
|
||||||
* @return the boss bar manager
|
|
||||||
*/
|
|
||||||
public static BossBarManager getBossBarManager() {
|
public static BossBarManager getBossBarManager() {
|
||||||
checkInitStatus(bossBarManager);
|
return serverProcess.bossBar();
|
||||||
return bossBarManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the object handling the client packets processing.
|
|
||||||
* <p>
|
|
||||||
* Can be used if you want to convert a buffer to a client packet object.
|
|
||||||
*
|
|
||||||
* @return the packet processor
|
|
||||||
*/
|
|
||||||
public static PacketProcessor getPacketProcessor() {
|
public static PacketProcessor getPacketProcessor() {
|
||||||
checkInitStatus(packetProcessor);
|
return serverProcess.packetProcessor();
|
||||||
return packetProcessor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets if the server is up and running.
|
|
||||||
*
|
|
||||||
* @return true if the server is started
|
|
||||||
*/
|
|
||||||
public static boolean isStarted() {
|
public static boolean isStarted() {
|
||||||
return started;
|
return serverProcess.isAlive();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets if the server is currently being shutdown using {@link #stopCleanly()}.
|
|
||||||
*
|
|
||||||
* @return true if the server is being stopped
|
|
||||||
*/
|
|
||||||
public static boolean isStopping() {
|
public static boolean isStopping() {
|
||||||
return stopping;
|
return !isStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -439,7 +274,7 @@ public final class MinecraftServer {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static void setChunkViewDistance(int chunkViewDistance) {
|
public static void setChunkViewDistance(int chunkViewDistance) {
|
||||||
Check.stateCondition(started, "You cannot change the chunk view distance after the server has been started.");
|
Check.stateCondition(serverProcess.isAlive(), "You cannot change the chunk view distance after the server has been started.");
|
||||||
Check.argCondition(!MathUtils.isBetween(chunkViewDistance, 2, 32),
|
Check.argCondition(!MathUtils.isBetween(chunkViewDistance, 2, 32),
|
||||||
"The chunk view distance must be between 2 and 32");
|
"The chunk view distance must be between 2 and 32");
|
||||||
MinecraftServer.chunkViewDistance = chunkViewDistance;
|
MinecraftServer.chunkViewDistance = chunkViewDistance;
|
||||||
@ -463,7 +298,7 @@ public final class MinecraftServer {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static void setEntityViewDistance(int entityViewDistance) {
|
public static void setEntityViewDistance(int entityViewDistance) {
|
||||||
Check.stateCondition(started, "You cannot change the entity view distance after the server has been started.");
|
Check.stateCondition(serverProcess.isAlive(), "You cannot change the entity view distance after the server has been started.");
|
||||||
Check.argCondition(!MathUtils.isBetween(entityViewDistance, 0, 32),
|
Check.argCondition(!MathUtils.isBetween(entityViewDistance, 0, 32),
|
||||||
"The entity view distance must be between 0 and 32");
|
"The entity view distance must be between 0 and 32");
|
||||||
MinecraftServer.entityViewDistance = entityViewDistance;
|
MinecraftServer.entityViewDistance = entityViewDistance;
|
||||||
@ -487,7 +322,7 @@ public final class MinecraftServer {
|
|||||||
* @throws IllegalStateException if this is called after the server started
|
* @throws IllegalStateException if this is called after the server started
|
||||||
*/
|
*/
|
||||||
public static void setCompressionThreshold(int compressionThreshold) {
|
public static void setCompressionThreshold(int compressionThreshold) {
|
||||||
Check.stateCondition(started, "The compression threshold cannot be changed after the server has been started.");
|
Check.stateCondition(serverProcess.isAlive(), "The compression threshold cannot be changed after the server has been started.");
|
||||||
MinecraftServer.compressionThreshold = compressionThreshold;
|
MinecraftServer.compressionThreshold = compressionThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +341,7 @@ public final class MinecraftServer {
|
|||||||
* @param enabled true to enable, false to disable
|
* @param enabled true to enable, false to disable
|
||||||
*/
|
*/
|
||||||
public static void setTerminalEnabled(boolean enabled) {
|
public static void setTerminalEnabled(boolean enabled) {
|
||||||
Check.stateCondition(started, "Terminal settings may not be changed after starting the server.");
|
Check.stateCondition(serverProcess.isAlive(), "Terminal settings may not be changed after starting the server.");
|
||||||
MinecraftServer.terminalEnabled = enabled;
|
MinecraftServer.terminalEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,73 +353,31 @@ public final class MinecraftServer {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static ResponseDataConsumer getResponseDataConsumer() {
|
public static ResponseDataConsumer getResponseDataConsumer() {
|
||||||
checkInitStatus(responseDataConsumer);
|
|
||||||
return responseDataConsumer;
|
return responseDataConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling dimensions.
|
|
||||||
*
|
|
||||||
* @return the dimension manager
|
|
||||||
*/
|
|
||||||
public static DimensionTypeManager getDimensionTypeManager() {
|
public static DimensionTypeManager getDimensionTypeManager() {
|
||||||
checkInitStatus(dimensionTypeManager);
|
return serverProcess.dimension();
|
||||||
return dimensionTypeManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling biomes.
|
|
||||||
*
|
|
||||||
* @return the biome manager
|
|
||||||
*/
|
|
||||||
public static BiomeManager getBiomeManager() {
|
public static BiomeManager getBiomeManager() {
|
||||||
checkInitStatus(biomeManager);
|
return serverProcess.biome();
|
||||||
return biomeManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling advancements.
|
|
||||||
*
|
|
||||||
* @return the advancement manager
|
|
||||||
*/
|
|
||||||
public static AdvancementManager getAdvancementManager() {
|
public static AdvancementManager getAdvancementManager() {
|
||||||
checkInitStatus(advancementManager);
|
return serverProcess.advancement();
|
||||||
return advancementManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the manager handling {@link Extension}.
|
|
||||||
*
|
|
||||||
* @return the extension manager
|
|
||||||
*/
|
|
||||||
public static ExtensionManager getExtensionManager() {
|
public static ExtensionManager getExtensionManager() {
|
||||||
checkInitStatus(extensionManager);
|
return serverProcess.extension();
|
||||||
return extensionManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling tags.
|
|
||||||
*
|
|
||||||
* @return the tag manager
|
|
||||||
*/
|
|
||||||
public static TagManager getTagManager() {
|
public static TagManager getTagManager() {
|
||||||
checkInitStatus(tagManager);
|
return serverProcess.tag();
|
||||||
return tagManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the manager handling the server ticks.
|
|
||||||
*
|
|
||||||
* @return the update manager
|
|
||||||
*/
|
|
||||||
public static UpdateManager getUpdateManager() {
|
|
||||||
checkInitStatus(updateManager);
|
|
||||||
return updateManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Server getServer() {
|
public static Server getServer() {
|
||||||
checkInitStatus(server);
|
return serverProcess.server();
|
||||||
return server;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -614,67 +407,15 @@ public final class MinecraftServer {
|
|||||||
* @throws IllegalStateException if called before {@link #init()} or if the server is already running
|
* @throws IllegalStateException if called before {@link #init()} or if the server is already running
|
||||||
*/
|
*/
|
||||||
public void start(@NotNull String address, int port) {
|
public void start(@NotNull String address, int port) {
|
||||||
Check.stateCondition(!initialized, "#start can only be called after #init");
|
serverProcess.start(new InetSocketAddress(address, port));
|
||||||
Check.stateCondition(started, "The server is already started");
|
new TickSchedulerThread(serverProcess).start();
|
||||||
|
|
||||||
extensionManager.start();
|
|
||||||
extensionManager.gotoPreInit();
|
|
||||||
|
|
||||||
MinecraftServer.started = true;
|
|
||||||
|
|
||||||
LOGGER.info("Starting Minestom server.");
|
|
||||||
|
|
||||||
updateManager.start();
|
|
||||||
|
|
||||||
extensionManager.gotoInit();
|
|
||||||
|
|
||||||
// Init server
|
|
||||||
try {
|
|
||||||
server.init(new InetSocketAddress(address, port));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start server
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
extensionManager.gotoPostInit();
|
|
||||||
|
|
||||||
LOGGER.info("Minestom server started successfully.");
|
|
||||||
|
|
||||||
if (terminalEnabled) {
|
|
||||||
MinestomTerminal.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop the server on SIGINT
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(MinecraftServer::stopCleanly));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops this server properly (saves if needed, kicking players, etc.)
|
* Stops this server properly (saves if needed, kicking players, etc.)
|
||||||
*/
|
*/
|
||||||
public static void stopCleanly() {
|
public static void stopCleanly() {
|
||||||
if (stopping) return;
|
serverProcess.stop();
|
||||||
stopping = true;
|
|
||||||
LOGGER.info("Stopping Minestom server.");
|
|
||||||
LOGGER.info("Unloading all extensions.");
|
|
||||||
extensionManager.shutdown();
|
|
||||||
updateManager.stop();
|
|
||||||
schedulerManager.shutdown();
|
|
||||||
connectionManager.shutdown();
|
|
||||||
server.stop();
|
|
||||||
storageManager.getLoadedLocations().forEach(StorageLocation::close);
|
|
||||||
LOGGER.info("Shutting down all thread pools.");
|
|
||||||
benchmarkManager.disable();
|
|
||||||
MinestomTerminal.stop();
|
|
||||||
MinestomThreadPool.shutdownAll();
|
|
||||||
LOGGER.info("Minestom server stopped successfully.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkInitStatus(@Nullable Object object) {
|
|
||||||
/*Check.stateCondition(Objects.isNull(object),
|
|
||||||
"You cannot access the manager before MinecraftServer#init, " +
|
|
||||||
"if you are developing an extension be sure to retrieve them at least after Extension#preInitialize");*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getThreadCount(@NotNull String property, int count) {
|
private static int getThreadCount(@NotNull String property, int count) {
|
||||||
|
158
src/main/java/net/minestom/server/ServerProcess.java
Normal file
158
src/main/java/net/minestom/server/ServerProcess.java
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package net.minestom.server;
|
||||||
|
|
||||||
|
import net.minestom.server.advancements.AdvancementManager;
|
||||||
|
import net.minestom.server.adventure.bossbar.BossBarManager;
|
||||||
|
import net.minestom.server.command.CommandManager;
|
||||||
|
import net.minestom.server.data.DataManager;
|
||||||
|
import net.minestom.server.event.GlobalEventHandler;
|
||||||
|
import net.minestom.server.exception.ExceptionManager;
|
||||||
|
import net.minestom.server.extensions.ExtensionManager;
|
||||||
|
import net.minestom.server.gamedata.tags.TagManager;
|
||||||
|
import net.minestom.server.instance.Chunk;
|
||||||
|
import net.minestom.server.instance.InstanceManager;
|
||||||
|
import net.minestom.server.instance.block.BlockManager;
|
||||||
|
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||||
|
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||||
|
import net.minestom.server.monitoring.BenchmarkManager;
|
||||||
|
import net.minestom.server.network.ConnectionManager;
|
||||||
|
import net.minestom.server.network.PacketProcessor;
|
||||||
|
import net.minestom.server.network.socket.Server;
|
||||||
|
import net.minestom.server.recipe.RecipeManager;
|
||||||
|
import net.minestom.server.scoreboard.TeamManager;
|
||||||
|
import net.minestom.server.storage.StorageManager;
|
||||||
|
import net.minestom.server.thread.ThreadDispatcher;
|
||||||
|
import net.minestom.server.timer.SchedulerManager;
|
||||||
|
import net.minestom.server.world.DimensionTypeManager;
|
||||||
|
import net.minestom.server.world.biomes.BiomeManager;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
public interface ServerProcess {
|
||||||
|
/**
|
||||||
|
* Handles incoming connections/players.
|
||||||
|
*/
|
||||||
|
@NotNull ConnectionManager connection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered instances.
|
||||||
|
*/
|
||||||
|
@NotNull InstanceManager instance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles {@link net.minestom.server.instance.block.BlockHandler block handlers}
|
||||||
|
* and {@link BlockPlacementRule placement rules}.
|
||||||
|
*/
|
||||||
|
@NotNull BlockManager block();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered commands.
|
||||||
|
*/
|
||||||
|
@NotNull CommandManager command();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered recipes shown to clients.
|
||||||
|
*/
|
||||||
|
@NotNull RecipeManager recipe();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered teams.
|
||||||
|
*/
|
||||||
|
@NotNull TeamManager team();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the global event handler.
|
||||||
|
* <p>
|
||||||
|
* Used to register event callback at a global scale.
|
||||||
|
*/
|
||||||
|
@NotNull GlobalEventHandler eventHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main scheduler ticked at the server rate.
|
||||||
|
*/
|
||||||
|
@NotNull SchedulerManager scheduler();
|
||||||
|
|
||||||
|
@NotNull BenchmarkManager benchmark();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered dimensions.
|
||||||
|
*/
|
||||||
|
@NotNull DimensionTypeManager dimension();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered biomes.
|
||||||
|
*/
|
||||||
|
@NotNull BiomeManager biome();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered advancements.
|
||||||
|
*/
|
||||||
|
@NotNull AdvancementManager advancement();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registered boss bars.
|
||||||
|
*/
|
||||||
|
@NotNull BossBarManager bossBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and handle extensions.
|
||||||
|
*/
|
||||||
|
@NotNull ExtensionManager extension();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles registry tags.
|
||||||
|
*/
|
||||||
|
@NotNull TagManager tag();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles all thrown exceptions from the server.
|
||||||
|
*/
|
||||||
|
@NotNull ExceptionManager exception();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles incoming packets.
|
||||||
|
*/
|
||||||
|
@NotNull PacketListenerManager packetListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the object handling the client packets processing.
|
||||||
|
* <p>
|
||||||
|
* Can be used if you want to convert a buffer to a client packet object.
|
||||||
|
*/
|
||||||
|
@NotNull PacketProcessor packetProcessor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposed socket server.
|
||||||
|
*/
|
||||||
|
@NotNull Server server();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatcher for tickable game objects.
|
||||||
|
*/
|
||||||
|
@NotNull ThreadDispatcher<Chunk> dispatcher();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the server ticks.
|
||||||
|
*/
|
||||||
|
@NotNull Ticker ticker();
|
||||||
|
|
||||||
|
void start(@NotNull SocketAddress socketAddress);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
boolean isAlive();
|
||||||
|
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
interface Ticker {
|
||||||
|
void tick(long nanoTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@NotNull StorageManager storage();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@NotNull DataManager data();
|
||||||
|
}
|
324
src/main/java/net/minestom/server/ServerProcessImpl.java
Normal file
324
src/main/java/net/minestom/server/ServerProcessImpl.java
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
package net.minestom.server;
|
||||||
|
|
||||||
|
import net.minestom.server.acquirable.Acquirable;
|
||||||
|
import net.minestom.server.advancements.AdvancementManager;
|
||||||
|
import net.minestom.server.adventure.bossbar.BossBarManager;
|
||||||
|
import net.minestom.server.command.CommandManager;
|
||||||
|
import net.minestom.server.data.DataManager;
|
||||||
|
import net.minestom.server.event.GlobalEventHandler;
|
||||||
|
import net.minestom.server.event.GlobalHandles;
|
||||||
|
import net.minestom.server.event.server.ServerTickMonitorEvent;
|
||||||
|
import net.minestom.server.exception.ExceptionManager;
|
||||||
|
import net.minestom.server.extensions.ExtensionManager;
|
||||||
|
import net.minestom.server.gamedata.tags.TagManager;
|
||||||
|
import net.minestom.server.instance.Chunk;
|
||||||
|
import net.minestom.server.instance.Instance;
|
||||||
|
import net.minestom.server.instance.InstanceManager;
|
||||||
|
import net.minestom.server.instance.block.BlockManager;
|
||||||
|
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||||
|
import net.minestom.server.monitoring.BenchmarkManager;
|
||||||
|
import net.minestom.server.monitoring.TickMonitor;
|
||||||
|
import net.minestom.server.network.ConnectionManager;
|
||||||
|
import net.minestom.server.network.PacketProcessor;
|
||||||
|
import net.minestom.server.network.socket.Server;
|
||||||
|
import net.minestom.server.network.socket.Worker;
|
||||||
|
import net.minestom.server.recipe.RecipeManager;
|
||||||
|
import net.minestom.server.scoreboard.TeamManager;
|
||||||
|
import net.minestom.server.storage.StorageLocation;
|
||||||
|
import net.minestom.server.storage.StorageManager;
|
||||||
|
import net.minestom.server.terminal.MinestomTerminal;
|
||||||
|
import net.minestom.server.thread.MinestomThreadPool;
|
||||||
|
import net.minestom.server.thread.ThreadDispatcher;
|
||||||
|
import net.minestom.server.timer.SchedulerManager;
|
||||||
|
import net.minestom.server.utils.PacketUtils;
|
||||||
|
import net.minestom.server.world.DimensionTypeManager;
|
||||||
|
import net.minestom.server.world.biomes.BiomeManager;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
final class ServerProcessImpl implements ServerProcess {
|
||||||
|
private final static Logger LOGGER = LoggerFactory.getLogger(ServerProcessImpl.class);
|
||||||
|
|
||||||
|
private final ExceptionManager exception;
|
||||||
|
private final ExtensionManager extension;
|
||||||
|
private final ConnectionManager connection;
|
||||||
|
private final PacketProcessor packetProcessor;
|
||||||
|
private final PacketListenerManager packetListener;
|
||||||
|
private final InstanceManager instance;
|
||||||
|
private final BlockManager block;
|
||||||
|
private final CommandManager command;
|
||||||
|
private final RecipeManager recipe;
|
||||||
|
private final StorageManager storage;
|
||||||
|
private final DataManager data;
|
||||||
|
private final TeamManager team;
|
||||||
|
private final GlobalEventHandler eventHandler;
|
||||||
|
private final SchedulerManager scheduler;
|
||||||
|
private final BenchmarkManager benchmark;
|
||||||
|
private final DimensionTypeManager dimension;
|
||||||
|
private final BiomeManager biome;
|
||||||
|
private final AdvancementManager advancement;
|
||||||
|
private final BossBarManager bossBar;
|
||||||
|
private final TagManager tag;
|
||||||
|
private final Server server;
|
||||||
|
|
||||||
|
private final ThreadDispatcher<Chunk> dispatcher;
|
||||||
|
private final Ticker ticker;
|
||||||
|
|
||||||
|
private boolean terminalEnabled = System.getProperty("minestom.terminal.disabled") == null;
|
||||||
|
private final AtomicBoolean started = new AtomicBoolean();
|
||||||
|
private final AtomicBoolean stopped = new AtomicBoolean();
|
||||||
|
|
||||||
|
public ServerProcessImpl() throws IOException {
|
||||||
|
this.exception = new ExceptionManager();
|
||||||
|
this.extension = new ExtensionManager(this);
|
||||||
|
this.connection = new ConnectionManager();
|
||||||
|
this.packetProcessor = new PacketProcessor();
|
||||||
|
this.packetListener = new PacketListenerManager(this);
|
||||||
|
this.instance = new InstanceManager();
|
||||||
|
this.block = new BlockManager();
|
||||||
|
this.command = new CommandManager();
|
||||||
|
this.recipe = new RecipeManager();
|
||||||
|
this.storage = new StorageManager();
|
||||||
|
this.data = new DataManager();
|
||||||
|
this.team = new TeamManager();
|
||||||
|
this.eventHandler = new GlobalEventHandler();
|
||||||
|
this.scheduler = new SchedulerManager();
|
||||||
|
this.benchmark = new BenchmarkManager();
|
||||||
|
this.dimension = new DimensionTypeManager();
|
||||||
|
this.biome = new BiomeManager();
|
||||||
|
this.advancement = new AdvancementManager();
|
||||||
|
this.bossBar = new BossBarManager();
|
||||||
|
this.tag = new TagManager();
|
||||||
|
this.server = new Server(packetProcessor);
|
||||||
|
|
||||||
|
this.dispatcher = ThreadDispatcher.singleThread();
|
||||||
|
this.ticker = new TickerImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConnectionManager connection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull InstanceManager instance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull BlockManager block() {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull CommandManager command() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull RecipeManager recipe() {
|
||||||
|
return recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull StorageManager storage() {
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull DataManager data() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull TeamManager team() {
|
||||||
|
return team;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull GlobalEventHandler eventHandler() {
|
||||||
|
return eventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull SchedulerManager scheduler() {
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull BenchmarkManager benchmark() {
|
||||||
|
return benchmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull DimensionTypeManager dimension() {
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull BiomeManager biome() {
|
||||||
|
return biome;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull AdvancementManager advancement() {
|
||||||
|
return advancement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull BossBarManager bossBar() {
|
||||||
|
return bossBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ExtensionManager extension() {
|
||||||
|
return extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull TagManager tag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ExceptionManager exception() {
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull PacketListenerManager packetListener() {
|
||||||
|
return packetListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull PacketProcessor packetProcessor() {
|
||||||
|
return packetProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Server server() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ThreadDispatcher<Chunk> dispatcher() {
|
||||||
|
return dispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Ticker ticker() {
|
||||||
|
return ticker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(@NotNull SocketAddress socketAddress) {
|
||||||
|
if (!started.compareAndSet(false, true)) {
|
||||||
|
throw new IllegalStateException("Server already started");
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.start();
|
||||||
|
extension.gotoPreInit();
|
||||||
|
|
||||||
|
LOGGER.info("Starting Minestom server.");
|
||||||
|
|
||||||
|
extension.gotoInit();
|
||||||
|
|
||||||
|
// Init server
|
||||||
|
try {
|
||||||
|
server.init(socketAddress);
|
||||||
|
} catch (IOException e) {
|
||||||
|
exception.handleException(e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
extension.gotoPostInit();
|
||||||
|
|
||||||
|
LOGGER.info("Minestom server started successfully.");
|
||||||
|
|
||||||
|
if (terminalEnabled) {
|
||||||
|
MinestomTerminal.start();
|
||||||
|
}
|
||||||
|
// Stop the server on SIGINT
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (!stopped.compareAndSet(false, true))
|
||||||
|
return;
|
||||||
|
LOGGER.info("Stopping Minestom server.");
|
||||||
|
LOGGER.info("Unloading all extensions.");
|
||||||
|
extension.shutdown();
|
||||||
|
scheduler.shutdown();
|
||||||
|
connection.shutdown();
|
||||||
|
server.stop();
|
||||||
|
storage.getLoadedLocations().forEach(StorageLocation::close);
|
||||||
|
LOGGER.info("Shutting down all thread pools.");
|
||||||
|
benchmark.disable();
|
||||||
|
MinestomTerminal.stop();
|
||||||
|
MinestomThreadPool.shutdownAll();
|
||||||
|
dispatcher.shutdown();
|
||||||
|
LOGGER.info("Minestom server stopped successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlive() {
|
||||||
|
return started.get() && !stopped.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TickerImpl implements Ticker {
|
||||||
|
@Override
|
||||||
|
public void tick(long nanoTime) {
|
||||||
|
final long msTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
scheduler().processTick();
|
||||||
|
|
||||||
|
// Waiting players update (newly connected clients waiting to get into the server)
|
||||||
|
connection().updateWaitingPlayers();
|
||||||
|
|
||||||
|
// Keep Alive Handling
|
||||||
|
connection().handleKeepAlive(msTime);
|
||||||
|
|
||||||
|
// Server tick (chunks/entities)
|
||||||
|
serverTick(msTime);
|
||||||
|
|
||||||
|
// Flush all waiting packets
|
||||||
|
PacketUtils.flush();
|
||||||
|
server().workers().forEach(Worker::flush);
|
||||||
|
|
||||||
|
// Monitoring
|
||||||
|
{
|
||||||
|
final double acquisitionTimeMs = Acquirable.getAcquiringTime() / 1e6D;
|
||||||
|
final double tickTimeMs = (System.nanoTime() - nanoTime) / 1e6D;
|
||||||
|
final TickMonitor tickMonitor = new TickMonitor(tickTimeMs, acquisitionTimeMs);
|
||||||
|
GlobalHandles.SERVER_TICK_MONITOR_HANDLE.call(new ServerTickMonitorEvent(tickMonitor));
|
||||||
|
Acquirable.resetAcquiringTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serverTick(long tickStart) {
|
||||||
|
// Tick all instances
|
||||||
|
for (Instance instance : instance().getInstances()) {
|
||||||
|
try {
|
||||||
|
instance.tick(tickStart);
|
||||||
|
} catch (Exception e) {
|
||||||
|
exception().handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Tick all chunks (and entities inside)
|
||||||
|
dispatcher().updateAndAwait(tickStart);
|
||||||
|
|
||||||
|
// Clear removed entities & update threads
|
||||||
|
final long tickTime = System.currentTimeMillis() - tickStart;
|
||||||
|
dispatcher().refreshThreads(tickTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,249 +0,0 @@
|
|||||||
package net.minestom.server;
|
|
||||||
|
|
||||||
import net.minestom.server.acquirable.Acquirable;
|
|
||||||
import net.minestom.server.instance.Chunk;
|
|
||||||
import net.minestom.server.instance.Instance;
|
|
||||||
import net.minestom.server.instance.InstanceManager;
|
|
||||||
import net.minestom.server.monitoring.TickMonitor;
|
|
||||||
import net.minestom.server.network.ConnectionManager;
|
|
||||||
import net.minestom.server.network.socket.Worker;
|
|
||||||
import net.minestom.server.thread.MinestomThread;
|
|
||||||
import net.minestom.server.thread.ThreadDispatcher;
|
|
||||||
import net.minestom.server.timer.SchedulerManager;
|
|
||||||
import net.minestom.server.utils.PacketUtils;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.locks.LockSupport;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.LongConsumer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manager responsible for the server ticks.
|
|
||||||
* <p>
|
|
||||||
* The {@link ThreadDispatcher} manages the multi-thread aspect of chunk ticks.
|
|
||||||
*/
|
|
||||||
public final class UpdateManager {
|
|
||||||
private volatile boolean stopRequested;
|
|
||||||
|
|
||||||
// TODO make configurable
|
|
||||||
private final ThreadDispatcher<Chunk> threadDispatcher = ThreadDispatcher.singleThread();
|
|
||||||
|
|
||||||
private final Queue<LongConsumer> tickStartCallbacks = new ConcurrentLinkedQueue<>();
|
|
||||||
private final Queue<LongConsumer> tickEndCallbacks = new ConcurrentLinkedQueue<>();
|
|
||||||
private final List<Consumer<TickMonitor>> tickMonitors = new CopyOnWriteArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should only be created in MinecraftServer.
|
|
||||||
*/
|
|
||||||
UpdateManager() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the server loop in the update thread.
|
|
||||||
*/
|
|
||||||
void start() {
|
|
||||||
new TickSchedulerThread().start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current {@link ThreadDispatcher}.
|
|
||||||
*
|
|
||||||
* @return the current thread provider
|
|
||||||
*/
|
|
||||||
public @NotNull ThreadDispatcher<Chunk> getThreadProvider() {
|
|
||||||
return threadDispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals the {@link ThreadDispatcher} that an instance has been created.
|
|
||||||
* <p>
|
|
||||||
* WARNING: should be automatically done by the {@link InstanceManager}.
|
|
||||||
*
|
|
||||||
* @param instance the instance
|
|
||||||
*/
|
|
||||||
public void signalInstanceCreate(Instance instance) {
|
|
||||||
instance.getChunks().forEach(this::signalChunkLoad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals the {@link ThreadDispatcher} that an instance has been deleted.
|
|
||||||
* <p>
|
|
||||||
* WARNING: should be automatically done by the {@link InstanceManager}.
|
|
||||||
*
|
|
||||||
* @param instance the instance
|
|
||||||
*/
|
|
||||||
public void signalInstanceDelete(Instance instance) {
|
|
||||||
instance.getChunks().forEach(this::signalChunkUnload);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals the {@link ThreadDispatcher} that a chunk has been loaded.
|
|
||||||
* <p>
|
|
||||||
* WARNING: should be automatically done by the {@link Instance} implementation.
|
|
||||||
*
|
|
||||||
* @param chunk the loaded chunk
|
|
||||||
*/
|
|
||||||
public void signalChunkLoad(@NotNull Chunk chunk) {
|
|
||||||
this.threadDispatcher.createPartition(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals the {@link ThreadDispatcher} that a chunk has been unloaded.
|
|
||||||
* <p>
|
|
||||||
* WARNING: should be automatically done by the {@link Instance} implementation.
|
|
||||||
*
|
|
||||||
* @param chunk the unloaded chunk
|
|
||||||
*/
|
|
||||||
public void signalChunkUnload(@NotNull Chunk chunk) {
|
|
||||||
this.threadDispatcher.deletePartition(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a callback executed at the start of the next server tick.
|
|
||||||
* <p>
|
|
||||||
* The long in the consumer represents the starting time (in ms) of the tick.
|
|
||||||
*
|
|
||||||
* @param callback the tick start callback
|
|
||||||
*/
|
|
||||||
public void addTickStartCallback(@NotNull LongConsumer callback) {
|
|
||||||
this.tickStartCallbacks.add(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a tick start callback.
|
|
||||||
*
|
|
||||||
* @param callback the callback to remove
|
|
||||||
*/
|
|
||||||
public void removeTickStartCallback(@NotNull LongConsumer callback) {
|
|
||||||
this.tickStartCallbacks.remove(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a callback executed at the end of the next server tick.
|
|
||||||
* <p>
|
|
||||||
* The long in the consumer represents the duration (in ms) of the tick.
|
|
||||||
*
|
|
||||||
* @param callback the tick end callback
|
|
||||||
*/
|
|
||||||
public void addTickEndCallback(@NotNull LongConsumer callback) {
|
|
||||||
this.tickEndCallbacks.add(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a tick end callback.
|
|
||||||
*
|
|
||||||
* @param callback the callback to remove
|
|
||||||
*/
|
|
||||||
public void removeTickEndCallback(@NotNull LongConsumer callback) {
|
|
||||||
this.tickEndCallbacks.remove(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTickMonitor(@NotNull Consumer<TickMonitor> consumer) {
|
|
||||||
this.tickMonitors.add(consumer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeTickMonitor(@NotNull Consumer<TickMonitor> consumer) {
|
|
||||||
this.tickMonitors.remove(consumer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the server loop.
|
|
||||||
*/
|
|
||||||
public void stop() {
|
|
||||||
this.stopRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class TickSchedulerThread extends MinestomThread {
|
|
||||||
private final ThreadDispatcher threadDispatcher = UpdateManager.this.threadDispatcher;
|
|
||||||
|
|
||||||
TickSchedulerThread() {
|
|
||||||
super(MinecraftServer.THREAD_NAME_TICK_SCHEDULER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
final ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
|
|
||||||
final SchedulerManager schedulerManager = MinecraftServer.getSchedulerManager();
|
|
||||||
final List<Worker> workers = MinecraftServer.getServer().workers();
|
|
||||||
while (!stopRequested) {
|
|
||||||
try {
|
|
||||||
long currentTime = System.nanoTime();
|
|
||||||
final long tickStart = System.currentTimeMillis();
|
|
||||||
|
|
||||||
// Tick start callbacks
|
|
||||||
doTickCallback(tickStartCallbacks, tickStart);
|
|
||||||
|
|
||||||
schedulerManager.processTick();
|
|
||||||
|
|
||||||
// Waiting players update (newly connected clients waiting to get into the server)
|
|
||||||
connectionManager.updateWaitingPlayers();
|
|
||||||
|
|
||||||
// Keep Alive Handling
|
|
||||||
connectionManager.handleKeepAlive(tickStart);
|
|
||||||
|
|
||||||
// Server tick (chunks/entities)
|
|
||||||
serverTick(tickStart);
|
|
||||||
|
|
||||||
// Flush all waiting packets
|
|
||||||
PacketUtils.flush();
|
|
||||||
workers.forEach(Worker::flush);
|
|
||||||
|
|
||||||
// the time that the tick took in nanoseconds
|
|
||||||
final long tickTime = System.nanoTime() - currentTime;
|
|
||||||
|
|
||||||
// Tick end callbacks
|
|
||||||
doTickCallback(tickEndCallbacks, tickTime);
|
|
||||||
|
|
||||||
// Monitoring
|
|
||||||
if (!tickMonitors.isEmpty()) {
|
|
||||||
final double acquisitionTimeMs = Acquirable.getAcquiringTime() / 1e6D;
|
|
||||||
final double tickTimeMs = tickTime / 1e6D;
|
|
||||||
final TickMonitor tickMonitor = new TickMonitor(tickTimeMs, acquisitionTimeMs);
|
|
||||||
for (Consumer<TickMonitor> consumer : tickMonitors) {
|
|
||||||
consumer.accept(tickMonitor);
|
|
||||||
}
|
|
||||||
Acquirable.resetAcquiringTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable thread until next tick
|
|
||||||
LockSupport.parkNanos((long) ((MinecraftServer.TICK_MS * 1e6) - tickTime));
|
|
||||||
} catch (Exception e) {
|
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.threadDispatcher.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a server tick and returns only once all the futures are completed.
|
|
||||||
*
|
|
||||||
* @param tickStart the time of the tick in milliseconds
|
|
||||||
*/
|
|
||||||
private void serverTick(long tickStart) {
|
|
||||||
// Tick all instances
|
|
||||||
for (Instance instance : MinecraftServer.getInstanceManager().getInstances()) {
|
|
||||||
try {
|
|
||||||
instance.tick(tickStart);
|
|
||||||
} catch (Exception e) {
|
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Tick all chunks (and entities inside)
|
|
||||||
this.threadDispatcher.updateAndAwait(tickStart);
|
|
||||||
|
|
||||||
// Clear removed entities & update threads
|
|
||||||
this.threadDispatcher.refreshThreads();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doTickCallback(Queue<LongConsumer> callbacks, long value) {
|
|
||||||
LongConsumer callback;
|
|
||||||
while ((callback = callbacks.poll()) != null) {
|
|
||||||
callback.accept(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -784,7 +784,7 @@ public class Entity implements Viewable, Tickable, Schedulable, TagHandler, Perm
|
|||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
protected void refreshCurrentChunk(Chunk currentChunk) {
|
protected void refreshCurrentChunk(Chunk currentChunk) {
|
||||||
this.currentChunk = currentChunk;
|
this.currentChunk = currentChunk;
|
||||||
MinecraftServer.getUpdateManager().getThreadProvider().updateElement(this, currentChunk);
|
MinecraftServer.process().dispatcher().updateElement(this, currentChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1423,7 +1423,7 @@ public class Entity implements Viewable, Tickable, Schedulable, TagHandler, Perm
|
|||||||
if (!passengers.isEmpty()) passengers.forEach(this::removePassenger);
|
if (!passengers.isEmpty()) passengers.forEach(this::removePassenger);
|
||||||
final Entity vehicle = this.vehicle;
|
final Entity vehicle = this.vehicle;
|
||||||
if (vehicle != null) vehicle.removePassenger(this);
|
if (vehicle != null) vehicle.removePassenger(this);
|
||||||
MinecraftServer.getUpdateManager().getThreadProvider().removeElement(this);
|
MinecraftServer.process().dispatcher().removeElement(this);
|
||||||
this.removed = true;
|
this.removed = true;
|
||||||
Entity.ENTITY_BY_ID.remove(id);
|
Entity.ENTITY_BY_ID.remove(id);
|
||||||
Entity.ENTITY_BY_UUID.remove(uuid);
|
Entity.ENTITY_BY_UUID.remove(uuid);
|
||||||
|
@ -7,6 +7,7 @@ import net.minestom.server.event.instance.InstanceTickEvent;
|
|||||||
import net.minestom.server.event.inventory.InventoryItemChangeEvent;
|
import net.minestom.server.event.inventory.InventoryItemChangeEvent;
|
||||||
import net.minestom.server.event.inventory.PlayerInventoryItemChangeEvent;
|
import net.minestom.server.event.inventory.PlayerInventoryItemChangeEvent;
|
||||||
import net.minestom.server.event.player.*;
|
import net.minestom.server.event.player.*;
|
||||||
|
import net.minestom.server.event.server.ServerTickMonitorEvent;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,4 +26,6 @@ public final class GlobalHandles {
|
|||||||
public static final ListenerHandle<InstanceChunkLoadEvent> INSTANCE_CHUNK_LOAD = EventDispatcher.getHandle(InstanceChunkLoadEvent.class);
|
public static final ListenerHandle<InstanceChunkLoadEvent> INSTANCE_CHUNK_LOAD = EventDispatcher.getHandle(InstanceChunkLoadEvent.class);
|
||||||
public static final ListenerHandle<InventoryItemChangeEvent> INVENTORY_ITEM_CHANGE_EVENT = EventDispatcher.getHandle(InventoryItemChangeEvent.class);
|
public static final ListenerHandle<InventoryItemChangeEvent> INVENTORY_ITEM_CHANGE_EVENT = EventDispatcher.getHandle(InventoryItemChangeEvent.class);
|
||||||
public static final ListenerHandle<PlayerInventoryItemChangeEvent> PLAYER_INVENTORY_ITEM_CHANGE_EVENT = EventDispatcher.getHandle(PlayerInventoryItemChangeEvent.class);
|
public static final ListenerHandle<PlayerInventoryItemChangeEvent> PLAYER_INVENTORY_ITEM_CHANGE_EVENT = EventDispatcher.getHandle(PlayerInventoryItemChangeEvent.class);
|
||||||
|
|
||||||
|
public static final ListenerHandle<ServerTickMonitorEvent> SERVER_TICK_MONITOR_HANDLE = EventDispatcher.getHandle(ServerTickMonitorEvent.class);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package net.minestom.server.event.server;
|
||||||
|
|
||||||
|
import net.minestom.server.event.Event;
|
||||||
|
import net.minestom.server.monitoring.TickMonitor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public final class ServerTickMonitorEvent implements Event {
|
||||||
|
private final TickMonitor tickMonitor;
|
||||||
|
|
||||||
|
public ServerTickMonitorEvent(@NotNull TickMonitor tickMonitor) {
|
||||||
|
this.tickMonitor = tickMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull TickMonitor getTickMonitor() {
|
||||||
|
return tickMonitor;
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import com.google.gson.Gson;
|
|||||||
import net.minestom.dependencies.DependencyGetter;
|
import net.minestom.dependencies.DependencyGetter;
|
||||||
import net.minestom.dependencies.ResolvedDependency;
|
import net.minestom.dependencies.ResolvedDependency;
|
||||||
import net.minestom.dependencies.maven.MavenRepository;
|
import net.minestom.dependencies.maven.MavenRepository;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.ServerProcess;
|
||||||
import net.minestom.server.event.Event;
|
import net.minestom.server.event.Event;
|
||||||
import net.minestom.server.event.EventNode;
|
import net.minestom.server.event.EventNode;
|
||||||
import net.minestom.server.ping.ResponseDataConsumer;
|
import net.minestom.server.ping.ResponseDataConsumer;
|
||||||
@ -34,6 +34,8 @@ public class ExtensionManager {
|
|||||||
public final static String INDEV_RESOURCES_FOLDER = "minestom.extension.indevfolder.resources";
|
public final static String INDEV_RESOURCES_FOLDER = "minestom.extension.indevfolder.resources";
|
||||||
private final static Gson GSON = new Gson();
|
private final static Gson GSON = new Gson();
|
||||||
|
|
||||||
|
private final ServerProcess serverProcess;
|
||||||
|
|
||||||
// LinkedHashMaps are HashMaps that preserve order
|
// LinkedHashMaps are HashMaps that preserve order
|
||||||
private final Map<String, Extension> extensions = new LinkedHashMap<>();
|
private final Map<String, Extension> extensions = new LinkedHashMap<>();
|
||||||
private final Map<String, Extension> immutableExtensions = Collections.unmodifiableMap(extensions);
|
private final Map<String, Extension> immutableExtensions = Collections.unmodifiableMap(extensions);
|
||||||
@ -42,10 +44,11 @@ public class ExtensionManager {
|
|||||||
private final File dependenciesFolder = new File(extensionFolder, ".libs");
|
private final File dependenciesFolder = new File(extensionFolder, ".libs");
|
||||||
private Path extensionDataRoot = extensionFolder.toPath();
|
private Path extensionDataRoot = extensionFolder.toPath();
|
||||||
|
|
||||||
private enum State { DO_NOT_START, NOT_STARTED, STARTED, PRE_INIT, INIT, POST_INIT }
|
private enum State {DO_NOT_START, NOT_STARTED, STARTED, PRE_INIT, INIT, POST_INIT}
|
||||||
private State state = State.NOT_STARTED;
|
private State state = State.NOT_STARTED;
|
||||||
|
|
||||||
public ExtensionManager() {
|
public ExtensionManager(ServerProcess serverProcess) {
|
||||||
|
this.serverProcess = serverProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,7 +222,7 @@ public class ExtensionManager {
|
|||||||
discoveredExtension.createClassLoader();
|
discoveredExtension.createClassLoader();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
discoveredExtension.loadStatus = DiscoveredExtension.LoadStatus.FAILED_TO_SETUP_CLASSLOADER;
|
discoveredExtension.loadStatus = DiscoveredExtension.LoadStatus.FAILED_TO_SETUP_CLASSLOADER;
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
serverProcess.exception().handleException(e);
|
||||||
LOGGER.error("Failed to load extension {}", discoveredExtension.getName());
|
LOGGER.error("Failed to load extension {}", discoveredExtension.getName());
|
||||||
LOGGER.error("Failed to load extension", e);
|
LOGGER.error("Failed to load extension", e);
|
||||||
extensionIterator.remove();
|
extensionIterator.remove();
|
||||||
@ -239,7 +242,7 @@ public class ExtensionManager {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
discoveredExtension.loadStatus = DiscoveredExtension.LoadStatus.LOAD_FAILED;
|
discoveredExtension.loadStatus = DiscoveredExtension.LoadStatus.LOAD_FAILED;
|
||||||
LOGGER.error("Failed to load extension {}", discoveredExtension.getName());
|
LOGGER.error("Failed to load extension {}", discoveredExtension.getName());
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
serverProcess.exception().handleException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,7 +341,7 @@ public class ExtensionManager {
|
|||||||
loggerField.set(extension, LoggerFactory.getLogger(extensionClass));
|
loggerField.set(extension, LoggerFactory.getLogger(extensionClass));
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
// We made it accessible, should not occur
|
// We made it accessible, should not occur
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
serverProcess.exception().handleException(e);
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
// This should also not occur (unless someone changed the logger in Extension superclass).
|
// This should also not occur (unless someone changed the logger in Extension superclass).
|
||||||
LOGGER.error("Main class '{}' in '{}' has no logger field.", mainClass, extensionName, e);
|
LOGGER.error("Main class '{}' in '{}' has no logger field.", mainClass, extensionName, e);
|
||||||
@ -351,10 +354,10 @@ public class ExtensionManager {
|
|||||||
loggerField.setAccessible(true);
|
loggerField.setAccessible(true);
|
||||||
loggerField.set(extension, eventNode);
|
loggerField.set(extension, eventNode);
|
||||||
|
|
||||||
MinecraftServer.getGlobalEventHandler().addChild(eventNode);
|
serverProcess.eventHandler().addChild(eventNode);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
// We made it accessible, should not occur
|
// We made it accessible, should not occur
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
serverProcess.exception().handleException(e);
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
// This should also not occur
|
// This should also not occur
|
||||||
LOGGER.error("Main class '{}' in '{}' has no event node field.", mainClass, extensionName, e);
|
LOGGER.error("Main class '{}' in '{}' has no event node field.", mainClass, extensionName, e);
|
||||||
@ -430,7 +433,7 @@ public class ExtensionManager {
|
|||||||
extensions.add(extension);
|
extensions.add(extension);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
serverProcess.exception().handleException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return extensions;
|
return extensions;
|
||||||
@ -463,7 +466,7 @@ public class ExtensionManager {
|
|||||||
|
|
||||||
return extension;
|
return extension;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
MinecraftServer.getExceptionManager().handleException(e);
|
serverProcess.exception().handleException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -727,7 +730,7 @@ public class ExtensionManager {
|
|||||||
|
|
||||||
// Remove event node
|
// Remove event node
|
||||||
EventNode<Event> eventNode = ext.getEventNode();
|
EventNode<Event> eventNode = ext.getEventNode();
|
||||||
MinecraftServer.getGlobalEventHandler().removeChild(eventNode);
|
serverProcess.eventHandler().removeChild(eventNode);
|
||||||
|
|
||||||
ext.postTerminate();
|
ext.postTerminate();
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public final class MojangAuth {
|
|||||||
*/
|
*/
|
||||||
public static void init() {
|
public static void init() {
|
||||||
Check.stateCondition(enabled, "Mojang auth is already enabled!");
|
Check.stateCondition(enabled, "Mojang auth is already enabled!");
|
||||||
Check.stateCondition(MinecraftServer.isStarted(), "The server has already been started!");
|
Check.stateCondition(MinecraftServer.process().isAlive(), "The server has already been started!");
|
||||||
MojangAuth.enabled = true;
|
MojangAuth.enabled = true;
|
||||||
// Generate necessary fields...
|
// Generate necessary fields...
|
||||||
MojangAuth.keyPair = MojangCrypt.generateKeyPair();
|
MojangAuth.keyPair = MojangCrypt.generateKeyPair();
|
||||||
|
@ -5,7 +5,6 @@ import net.kyori.adventure.identity.Identity;
|
|||||||
import net.kyori.adventure.pointer.Pointers;
|
import net.kyori.adventure.pointer.Pointers;
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.Tickable;
|
import net.minestom.server.Tickable;
|
||||||
import net.minestom.server.UpdateManager;
|
|
||||||
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.data.Data;
|
import net.minestom.server.data.Data;
|
||||||
@ -23,6 +22,7 @@ import net.minestom.server.network.packet.server.play.BlockActionPacket;
|
|||||||
import net.minestom.server.network.packet.server.play.TimeUpdatePacket;
|
import net.minestom.server.network.packet.server.play.TimeUpdatePacket;
|
||||||
import net.minestom.server.tag.Tag;
|
import net.minestom.server.tag.Tag;
|
||||||
import net.minestom.server.tag.TagHandler;
|
import net.minestom.server.tag.TagHandler;
|
||||||
|
import net.minestom.server.thread.ThreadDispatcher;
|
||||||
import net.minestom.server.timer.Schedulable;
|
import net.minestom.server.timer.Schedulable;
|
||||||
import net.minestom.server.timer.Scheduler;
|
import net.minestom.server.timer.Scheduler;
|
||||||
import net.minestom.server.utils.PacketUtils;
|
import net.minestom.server.utils.PacketUtils;
|
||||||
@ -50,13 +50,11 @@ import java.util.stream.Collectors;
|
|||||||
* <p>
|
* <p>
|
||||||
* WARNING: when making your own implementation registering the instance manually is required
|
* WARNING: when making your own implementation registering the instance manually is required
|
||||||
* with {@link InstanceManager#registerInstance(Instance)}, and
|
* with {@link InstanceManager#registerInstance(Instance)}, and
|
||||||
* you need to be sure to signal the {@link UpdateManager} of the changes using
|
* you need to be sure to signal the {@link ThreadDispatcher} of every partition/element changes.
|
||||||
* {@link UpdateManager#signalChunkLoad(Chunk)} and {@link UpdateManager#signalChunkUnload(Chunk)}.
|
|
||||||
*/
|
*/
|
||||||
public abstract class Instance implements Block.Getter, Block.Setter, Tickable, Schedulable, TagHandler, PacketGroupingAudience {
|
public abstract class Instance implements Block.Getter, Block.Setter, Tickable, Schedulable, TagHandler, PacketGroupingAudience {
|
||||||
|
|
||||||
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||||
protected static final UpdateManager UPDATE_MANAGER = MinecraftServer.getUpdateManager();
|
|
||||||
|
|
||||||
private boolean registered;
|
private boolean registered;
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package net.minestom.server.instance;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.coordinate.Vec;
|
import net.minestom.server.coordinate.Vec;
|
||||||
import net.minestom.server.entity.Entity;
|
import net.minestom.server.entity.Entity;
|
||||||
@ -223,7 +224,8 @@ public class InstanceContainer extends Instance {
|
|||||||
// Clear cache
|
// Clear cache
|
||||||
this.chunks.remove(index);
|
this.chunks.remove(index);
|
||||||
chunk.unload();
|
chunk.unload();
|
||||||
UPDATE_MANAGER.signalChunkUnload(chunk);
|
var dispatcher = MinecraftServer.process().dispatcher();
|
||||||
|
dispatcher.deletePartition(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -525,6 +527,7 @@ public class InstanceContainer extends Instance {
|
|||||||
private void cacheChunk(@NotNull Chunk chunk) {
|
private void cacheChunk(@NotNull Chunk chunk) {
|
||||||
final long index = ChunkUtils.getChunkIndex(chunk);
|
final long index = ChunkUtils.getChunkIndex(chunk);
|
||||||
this.chunks.put(index, chunk);
|
this.chunks.put(index, chunk);
|
||||||
UPDATE_MANAGER.signalChunkLoad(chunk);
|
var dispatcher = MinecraftServer.process().dispatcher();
|
||||||
|
dispatcher.createPartition(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -118,7 +118,8 @@ public final class InstanceManager {
|
|||||||
// Unregister
|
// Unregister
|
||||||
instance.setRegistered(false);
|
instance.setRegistered(false);
|
||||||
this.instances.remove(instance);
|
this.instances.remove(instance);
|
||||||
MinecraftServer.getUpdateManager().signalInstanceDelete(instance);
|
var dispatcher = MinecraftServer.process().dispatcher();
|
||||||
|
instance.getChunks().forEach(dispatcher::deletePartition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +156,7 @@ public final class InstanceManager {
|
|||||||
private void UNSAFE_registerInstance(@NotNull Instance instance) {
|
private void UNSAFE_registerInstance(@NotNull Instance instance) {
|
||||||
instance.setRegistered(true);
|
instance.setRegistered(true);
|
||||||
this.instances.add(instance);
|
this.instances.add(instance);
|
||||||
MinecraftServer.getUpdateManager().signalInstanceCreate(instance);
|
var dispatcher = MinecraftServer.process().dispatcher();
|
||||||
|
instance.getChunks().forEach(dispatcher::createPartition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.minestom.server.listener.manager;
|
package net.minestom.server.listener.manager;
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.ServerProcess;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.GlobalHandles;
|
import net.minestom.server.event.GlobalHandles;
|
||||||
import net.minestom.server.event.player.PlayerPacketEvent;
|
import net.minestom.server.event.player.PlayerPacketEvent;
|
||||||
@ -21,11 +22,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
public final class PacketListenerManager {
|
public final class PacketListenerManager {
|
||||||
|
|
||||||
public final static Logger LOGGER = LoggerFactory.getLogger(PacketListenerManager.class);
|
public final static Logger LOGGER = LoggerFactory.getLogger(PacketListenerManager.class);
|
||||||
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
|
private final ServerProcess serverProcess;
|
||||||
|
|
||||||
private final Map<Class<? extends ClientPacket>, PacketListenerConsumer> listeners = new ConcurrentHashMap<>();
|
private final Map<Class<? extends ClientPacket>, PacketListenerConsumer> listeners = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public PacketListenerManager() {
|
public PacketListenerManager(ServerProcess serverProcess) {
|
||||||
|
this.serverProcess = serverProcess;
|
||||||
|
|
||||||
setListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
|
setListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
|
||||||
setListener(ClientChatMessagePacket.class, ChatMessageListener::listener);
|
setListener(ClientChatMessagePacket.class, ChatMessageListener::listener);
|
||||||
setListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
|
setListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
|
||||||
@ -79,7 +82,7 @@ public final class PacketListenerManager {
|
|||||||
// TODO remove legacy
|
// TODO remove legacy
|
||||||
{
|
{
|
||||||
final PacketController packetController = new PacketController();
|
final PacketController packetController = new PacketController();
|
||||||
for (ClientPacketConsumer clientPacketConsumer : CONNECTION_MANAGER.getReceivePacketConsumers()) {
|
for (ClientPacketConsumer clientPacketConsumer : serverProcess.connection().getReceivePacketConsumers()) {
|
||||||
clientPacketConsumer.accept(player, packetController, packet);
|
clientPacketConsumer.accept(player, packetController, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +116,7 @@ public final class PacketListenerManager {
|
|||||||
* @return true if the packet is not cancelled, false otherwise
|
* @return true if the packet is not cancelled, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean processServerPacket(@NotNull ServerPacket packet, @NotNull Collection<Player> players) {
|
public boolean processServerPacket(@NotNull ServerPacket packet, @NotNull Collection<Player> players) {
|
||||||
final List<ServerPacketConsumer> consumers = CONNECTION_MANAGER.getSendPacketConsumers();
|
final List<ServerPacketConsumer> consumers = serverProcess.connection().getSendPacketConsumers();
|
||||||
if (consumers.isEmpty()) {
|
if (consumers.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,8 @@ package net.minestom.server.scoreboard;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import net.minestom.server.MinecraftServer;
|
|
||||||
import net.minestom.server.entity.LivingEntity;
|
import net.minestom.server.entity.LivingEntity;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.network.ConnectionManager;
|
|
||||||
import net.minestom.server.utils.PacketUtils;
|
import net.minestom.server.utils.PacketUtils;
|
||||||
import net.minestom.server.utils.UniqueIdUtils;
|
import net.minestom.server.utils.UniqueIdUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -20,8 +18,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
*/
|
*/
|
||||||
public final class TeamManager {
|
public final class TeamManager {
|
||||||
|
|
||||||
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents all registered teams
|
* Represents all registered teams
|
||||||
*/
|
*/
|
||||||
|
@ -13,8 +13,6 @@ import org.jline.terminal.TerminalBuilder;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class MinestomTerminal {
|
public class MinestomTerminal {
|
||||||
|
|
||||||
private static final CommandManager COMMAND_MANAGER = MinecraftServer.getCommandManager();
|
|
||||||
private static final String PROMPT = "> ";
|
private static final String PROMPT = "> ";
|
||||||
|
|
||||||
private static volatile Terminal terminal;
|
private static volatile Terminal terminal;
|
||||||
@ -37,7 +35,8 @@ public class MinestomTerminal {
|
|||||||
String command;
|
String command;
|
||||||
try {
|
try {
|
||||||
command = reader.readLine(PROMPT);
|
command = reader.readLine(PROMPT);
|
||||||
COMMAND_MANAGER.execute(COMMAND_MANAGER.getConsoleSender(), command);
|
var commandManager = MinecraftServer.getCommandManager();
|
||||||
|
commandManager.execute(commandManager.getConsoleSender(), command);
|
||||||
} catch (UserInterruptException e) {
|
} catch (UserInterruptException e) {
|
||||||
// Handle Ctrl + C
|
// Handle Ctrl + C
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package net.minestom.server.thread;
|
||||||
|
|
||||||
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.ServerProcess;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public final class TickSchedulerThread extends MinestomThread {
|
||||||
|
private final ServerProcess serverProcess;
|
||||||
|
|
||||||
|
public TickSchedulerThread(ServerProcess serverProcess) {
|
||||||
|
super(MinecraftServer.THREAD_NAME_TICK_SCHEDULER);
|
||||||
|
this.serverProcess = serverProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (serverProcess.isAlive()) {
|
||||||
|
final long tickStart = System.nanoTime();
|
||||||
|
try {
|
||||||
|
serverProcess.ticker().tick(tickStart);
|
||||||
|
} catch (Exception e) {
|
||||||
|
serverProcess.exception().handleException(e);
|
||||||
|
}
|
||||||
|
final long tickTime = System.nanoTime() - tickStart;
|
||||||
|
LockSupport.parkNanos((long) ((MinecraftServer.TICK_MS * 1e6) - tickTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,6 @@ import net.minestom.server.Viewable;
|
|||||||
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
import net.minestom.server.adventure.audience.PacketGroupingAudience;
|
||||||
import net.minestom.server.entity.Entity;
|
import net.minestom.server.entity.Entity;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
|
||||||
import net.minestom.server.network.packet.server.CachedPacket;
|
import net.minestom.server.network.packet.server.CachedPacket;
|
||||||
import net.minestom.server.network.packet.server.FramedPacket;
|
import net.minestom.server.network.packet.server.FramedPacket;
|
||||||
import net.minestom.server.network.packet.server.SendablePacket;
|
import net.minestom.server.network.packet.server.SendablePacket;
|
||||||
@ -50,7 +49,6 @@ import java.util.zip.Inflater;
|
|||||||
* Be sure to check the implementation code.
|
* Be sure to check the implementation code.
|
||||||
*/
|
*/
|
||||||
public final class PacketUtils {
|
public final class PacketUtils {
|
||||||
private static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
|
||||||
private static final LocalCache<Deflater> LOCAL_DEFLATER = LocalCache.of(Deflater::new);
|
private static final LocalCache<Deflater> LOCAL_DEFLATER = LocalCache.of(Deflater::new);
|
||||||
|
|
||||||
public static final boolean GROUPED_PACKET = getBoolean("minestom.grouped-packet", true);
|
public static final boolean GROUPED_PACKET = getBoolean("minestom.grouped-packet", true);
|
||||||
@ -118,7 +116,7 @@ public final class PacketUtils {
|
|||||||
public static void sendGroupedPacket(@NotNull Collection<Player> players, @NotNull ServerPacket packet,
|
public static void sendGroupedPacket(@NotNull Collection<Player> players, @NotNull ServerPacket packet,
|
||||||
@NotNull Predicate<Player> predicate) {
|
@NotNull Predicate<Player> predicate) {
|
||||||
if (players.isEmpty()) return;
|
if (players.isEmpty()) return;
|
||||||
if (!PACKET_LISTENER_MANAGER.processServerPacket(packet, players)) return;
|
if (!MinecraftServer.getPacketListenerManager().processServerPacket(packet, players)) return;
|
||||||
// work out if the packet needs to be sent individually due to server-side translating
|
// work out if the packet needs to be sent individually due to server-side translating
|
||||||
final SendablePacket sendablePacket = GROUPED_PACKET ? new CachedPacket(packet) : packet;
|
final SendablePacket sendablePacket = GROUPED_PACKET ? new CachedPacket(packet) : packet;
|
||||||
players.forEach(player -> {
|
players.forEach(player -> {
|
||||||
|
30
src/test/java/net/minestom/server/ServerProcessTest.java
Normal file
30
src/test/java/net/minestom/server/ServerProcessTest.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package net.minestom.server;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
public class ServerProcessTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void init() {
|
||||||
|
AtomicReference<ServerProcess> process = new AtomicReference<>();
|
||||||
|
assertDoesNotThrow(() -> process.set(MinecraftServer.updateProcess()));
|
||||||
|
assertDoesNotThrow(() -> process.get().start(new InetSocketAddress("localhost", 25565)));
|
||||||
|
assertThrows(Exception.class, () -> process.get().start(new InetSocketAddress("localhost", 25566)));
|
||||||
|
assertDoesNotThrow(() -> process.get().stop());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tick() {
|
||||||
|
var process = MinecraftServer.updateProcess();
|
||||||
|
process.start(new InetSocketAddress("localhost", 25567));
|
||||||
|
var ticker = process.ticker();
|
||||||
|
assertDoesNotThrow(() -> ticker.tick(System.currentTimeMillis()));
|
||||||
|
assertDoesNotThrow(process::stop);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user