diff --git a/common/src/main/java/us/myles/ViaVersion/ViaManager.java b/common/src/main/java/us/myles/ViaVersion/ViaManager.java index 370885753..4b901cba0 100644 --- a/common/src/main/java/us/myles/ViaVersion/ViaManager.java +++ b/common/src/main/java/us/myles/ViaVersion/ViaManager.java @@ -2,6 +2,7 @@ package us.myles.ViaVersion; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; +import us.myles.ViaVersion.api.platform.TaskId; import us.myles.ViaVersion.api.platform.ViaConnectionManager; import us.myles.ViaVersion.api.platform.ViaInjector; import us.myles.ViaVersion.api.platform.ViaPlatform; @@ -27,6 +28,7 @@ public class ViaManager { private final ViaCommandHandler commandHandler; private final ViaPlatformLoader loader; private final Set subPlatforms = new HashSet<>(); + private TaskId mappingLoadingTask; private boolean debug; public ViaManager(ViaPlatform platform, ViaInjector injector, ViaCommandHandler commandHandler, ViaPlatformLoader loader) { @@ -86,6 +88,12 @@ public class ViaManager { // Load Platform loader.load(); // Common tasks + mappingLoadingTask = Via.getPlatform().runRepeatingSync(() -> { + if (ProtocolRegistry.checkForMappingCompletion()) { + platform.cancelTask(mappingLoadingTask); + mappingLoadingTask = null; + } + }, 10L); if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) { if (Via.getConfig().isSimulatePlayerTick()) { Via.getPlatform().runRepeatingSync(new ViaIdleThread(), 1L); diff --git a/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java b/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java index e2371aebf..651bcc2d8 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java +++ b/common/src/main/java/us/myles/ViaVersion/api/data/MappingDataLoader.java @@ -6,6 +6,7 @@ import com.google.gson.JsonIOException; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import us.myles.ViaVersion.api.Via; +import us.myles.ViaVersion.api.protocol.ProtocolRegistry; import us.myles.ViaVersion.util.GsonUtil; import java.io.File; @@ -33,6 +34,7 @@ public class MappingDataLoader { public static void enableMappingsCache() { cacheJsonMappings = true; + ProtocolRegistry.setKeepExecutorLoaded(true); } /** diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java index 184d2526f..29111251b 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java +++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java @@ -61,6 +61,7 @@ public class ProtocolRegistry { private static Map, CompletableFuture> mappingLoaderFutures = new HashMap<>(); private static ThreadPoolExecutor mappingLoaderExecutor; private static boolean mappingsLoaded; + private static boolean keepExecutorLoaded; static { mappingLoaderExecutor = new ThreadPoolExecutor(5, 16, 45L, TimeUnit.SECONDS, new SynchronousQueue<>()); @@ -70,11 +71,10 @@ public class ProtocolRegistry { registerBaseProtocol(BASE_PROTOCOL, Range.lessThan(Integer.MIN_VALUE)); registerBaseProtocol(new BaseProtocol1_7(), Range.all()); - // Register built in protocols registerProtocol(new Protocol1_9To1_8(), ProtocolVersion.v1_9, ProtocolVersion.v1_8); registerProtocol(new Protocol1_9_1To1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId()); registerProtocol(new Protocol1_9_3To1_9_1_2(), ProtocolVersion.v1_9_3, ProtocolVersion.v1_9_2); - // Only supported for 1.9.4 server to 1.9 (nothing else) + registerProtocol(new Protocol1_9To1_9_1(), ProtocolVersion.v1_9, ProtocolVersion.v1_9_2); registerProtocol(new Protocol1_9_1_2To1_9_3_4(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9_3.getId()); registerProtocol(new Protocol1_10To1_9_3_4(), ProtocolVersion.v1_10, ProtocolVersion.v1_9_3); @@ -320,15 +320,26 @@ public class ProtocolRegistry { if (future == null) return; future.get(); + } + /** + * Shuts down the executor and uncaches mappings if all futures have been completed. + * + * @return true if the executor has now been shut down + */ + public static boolean checkForMappingCompletion() { synchronized (MAPPING_LOADER_LOCK) { - if (mappingsLoaded) return; + if (mappingsLoaded || keepExecutorLoaded) return false; - // Remove only after execution to block other potential threads - mappingLoaderFutures.remove(protocolClass); - if (mappingLoaderFutures.isEmpty()) { - shutdownLoaderExecutor(); + for (CompletableFuture future : mappingLoaderFutures.values()) { + // Return if any future hasn't completed yet + if (!future.isDone()) { + return false; + } } + + shutdownLoaderExecutor(); + return true; } } @@ -336,6 +347,7 @@ public class ProtocolRegistry { mappingsLoaded = true; mappingLoaderExecutor.shutdown(); mappingLoaderExecutor = null; + mappingLoaderFutures.clear(); mappingLoaderFutures = null; if (MappingDataLoader.isCacheJsonMappings()) { MappingDataLoader.getMappingsCache().clear(); @@ -355,4 +367,13 @@ public class ProtocolRegistry { return mappingLoaderFutures.get(protocolClass); } } + + /** + * If set to true, the executor and mappings will stay loaded, even if all current futures have been completed. + * + * @param keepExecutorLoaded whether to keep the executor and mappings loaded, even if all current futures have been completed + */ + public static void setKeepExecutorLoaded(boolean keepExecutorLoaded) { + ProtocolRegistry.keepExecutorLoaded = keepExecutorLoaded; + } }