diff options
| author | shedaniel <daniel@shedaniel.me> | 2022-08-05 01:30:08 +0800 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2022-08-26 10:53:55 +0900 |
| commit | 8c13c015031a0de865d2e767cd8e879754f803e2 (patch) | |
| tree | 2bb6fa6578b63d1c216b863a6c4206295c044b36 /runtime-engine/initialization/src/main/java/me/shedaniel | |
| parent | 8f5d3ef632f3d1a733c98ce5607c9fd5a0fd7567 (diff) | |
| download | RoughlyEnoughItems-8c13c015031a0de865d2e767cd8e879754f803e2.tar.gz RoughlyEnoughItems-8c13c015031a0de865d2e767cd8e879754f803e2.tar.bz2 RoughlyEnoughItems-8c13c015031a0de865d2e767cd8e879754f803e2.zip | |
More work
Diffstat (limited to 'runtime-engine/initialization/src/main/java/me/shedaniel')
2 files changed, 272 insertions, 0 deletions
diff --git a/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/client/init/CoreClientInitialization.java b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/client/init/CoreClientInitialization.java new file mode 100644 index 000000000..44df96bc4 --- /dev/null +++ b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/client/init/CoreClientInitialization.java @@ -0,0 +1,159 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.client.init; + +import dev.architectury.event.Event; +import dev.architectury.event.EventFactory; +import dev.architectury.event.EventResult; +import dev.architectury.event.events.client.ClientGuiEvent; +import dev.architectury.event.events.client.ClientRecipeUpdateEvent; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.config.ConfigManager; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.config.addon.ConfigAddonRegistry; +import me.shedaniel.rei.api.client.entry.renderer.EntryRendererRegistry; +import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; +import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; +import me.shedaniel.rei.api.client.search.SearchProvider; +import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; +import me.shedaniel.rei.api.client.subsets.SubsetsRegistry; +import me.shedaniel.rei.api.client.view.Views; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.PluginView; +import me.shedaniel.rei.api.common.plugins.REIPluginProvider; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import me.shedaniel.rei.impl.client.ClientInternals; +import me.shedaniel.rei.impl.common.InternalLogger; +import me.shedaniel.rei.impl.common.init.CoreInitialization; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import org.apache.commons.lang3.mutable.MutableLong; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.concurrent.*; + +@ApiStatus.Internal +public class CoreClientInitialization { + public static final Event<ClientRecipeUpdateEvent> PRE_UPDATE_RECIPES = EventFactory.createLoop(); + private static final ExecutorService RELOAD_PLUGINS = Executors.newSingleThreadScheduledExecutor(task -> { + Thread thread = new Thread(task, "REI-ReloadPlugins"); + thread.setDaemon(true); + thread.setUncaughtExceptionHandler(($, exception) -> { + InternalLogger.getInstance().throwException(exception); + }); + return thread; + }); + private static final List<Future<?>> RELOAD_TASKS = new CopyOnWriteArrayList<>(); + + public void onInitializeClient() { + attachClientInternals(); + loadTestPlugins(); + + MutableLong startReload = new MutableLong(-1); + MutableLong endReload = new MutableLong(-1); + PRE_UPDATE_RECIPES.register(recipeManager -> { + PluginReloaderImpl.PERFORMANCE_LOGGER.clear(); + CoreInitialization.reloadPlugins(startReload, ReloadStage.START); + }); + ClientRecipeUpdateEvent.EVENT.register(recipeManager -> { + CoreInitialization.reloadPlugins(endReload, ReloadStage.END); + }); + ClientGuiEvent.INIT_PRE.register((screen, access) -> { + List<ReloadStage> stages = PluginManager.getInstance().view().getObservedStages(); + + if (Minecraft.getInstance().level != null && Minecraft.getInstance().player != null && stages.contains(ReloadStage.START) + && !stages.contains(ReloadStage.END) && !PluginManager.areAnyReloading() && screen instanceof AbstractContainerScreen) { + for (Future<?> task : RELOAD_TASKS) { + if (!task.isDone()) { + return EventResult.pass(); + } + } + + InternalLogger.getInstance().error("Detected missing stage: END! This is possibly due to issues during client recipe reload! REI will force a reload of the recipes now!"); + CoreInitialization.reloadPlugins(endReload, ReloadStage.END); + } + + return EventResult.pass(); + }); + } + + public static void attachClientInternals() { + PluginManager<REIClientPlugin> manager = ClientInternals.getPluginManager(); + manager.registerReloadable(EntryRendererRegistry.class); + manager.registerReloadable(Views.class); + manager.registerReloadable(InputMethodRegistry.class); + manager.registerReloadable(SearchProvider.class); + manager.registerReloadable(ConfigManager.class); + manager.registerReloadable(EntryRegistry.class); + manager.registerReloadable(CollapsibleEntryRegistry.class); + manager.registerReloadable(CategoryRegistry.class); + manager.registerReloadable(DisplayRegistry.class); + manager.registerReloadable(ScreenRegistry.class); + manager.registerReloadable(FavoriteEntryType.Registry.class); + manager.registerReloadable(SubsetsRegistry.class); + manager.registerReloadable(TransferHandlerRegistry.class); + manager.registerReloadable(REIRuntime.class); + manager.registerReloadable(ConfigAddonRegistry.class); + } + + private void loadTestPlugins() { + if (System.getProperty("rei.test", "false").equals("true")) { + try { + PluginView.getClientInstance().registerPlugin((REIPluginProvider<? extends REIClientPlugin>) Class.forName("me.shedaniel.rei.plugin.test.REITestPlugin") + .getDeclaredConstructor() + .newInstance()); + } catch (InstantiationException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + + public static boolean reloadPluginsClient(@Nullable ReloadStage start) { + if (ConfigObject.getInstance().doesRegisterRecipesInAnotherThread()) { + Future<?>[] futures = new Future<?>[1]; + CompletableFuture<Void> future = CompletableFuture.runAsync(() -> CoreInitialization._reloadPlugins(start), RELOAD_PLUGINS) + .whenComplete((unused, throwable) -> { + // Remove the future from the list of futures + if (futures[0] != null) { + RELOAD_TASKS.remove(futures[0]); + futures[0] = null; + } + }); + futures[0] = future; + RELOAD_TASKS.add(future); + return true; + } + + return false; + } +} diff --git a/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/common/init/CoreInitialization.java b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/common/init/CoreInitialization.java new file mode 100644 index 000000000..c5945ead1 --- /dev/null +++ b/runtime-engine/initialization/src/main/java/me/shedaniel/rei/impl/common/init/CoreInitialization.java @@ -0,0 +1,113 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.common.init; + +import dev.architectury.platform.Platform; +import dev.architectury.registry.ReloadListenerRegistry; +import dev.architectury.utils.Env; +import me.shedaniel.rei.api.common.display.DisplaySerializerRegistry; +import me.shedaniel.rei.api.common.entry.comparison.FluidComparatorRegistry; +import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry; +import me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapterRegistry; +import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry; +import me.shedaniel.rei.api.common.fluid.FluidSupportProvider; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.api.common.plugins.REIServerPlugin; +import me.shedaniel.rei.api.common.registry.RecipeManagerContext; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry; +import me.shedaniel.rei.impl.common.Internals; +import me.shedaniel.rei.impl.client.init.CoreClientInitialization; +import me.shedaniel.rei.impl.common.InternalLogger; +import net.minecraft.server.packs.PackType; +import net.minecraft.util.Unit; +import org.apache.commons.lang3.mutable.MutableLong; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public class CoreInitialization { + public void onInitialize() { + attachCommonInternals(); + + if (Platform.getEnvironment() == Env.SERVER) { + MutableLong lastReload = new MutableLong(-1); + ReloadListenerRegistry.register(PackType.SERVER_DATA, (preparationBarrier, resourceManager, profilerFiller, profilerFiller2, executor, executor2) -> { + return preparationBarrier.wait(Unit.INSTANCE).thenRunAsync(PluginManager::reloadAll, executor2); + }); + } + } + + public static void attachCommonInternals() { + PluginManager<REIPlugin<?>> manager = PluginManager.getInstance(); + manager.registerReloadable(EntryTypeRegistry.class); + manager.registerReloadable(EntrySettingsAdapterRegistry.class); + manager.registerReloadable(RecipeManagerContext.class); + manager.registerReloadable(ItemComparatorRegistry.class); + manager.registerReloadable(FluidComparatorRegistry.class); + manager.registerReloadable(DisplaySerializerRegistry.class); + manager.registerReloadable(FluidSupportProvider.class); + PluginManager<REIServerPlugin> serverManager = PluginManager.getServerInstance(); + serverManager.registerReloadable(MenuInfoRegistry.class); + Internals.attachInstanceSupplier((Runnable) () -> reloadPlugins(null, null), "reloadREI"); + } + + public static void _reloadPlugins(@Nullable ReloadStage stage) { + if (stage == null) { + for (ReloadStage reloadStage : ReloadStage.values()) { + _reloadPlugins(reloadStage); + } + return; + } + try { + for (PluginManager<? extends REIPlugin<?>> instance : PluginManager.getActiveInstances()) { + instance.view().pre(stage); + } + for (PluginManager<? extends REIPlugin<?>> instance : PluginManager.getActiveInstances()) { + instance.startReload(stage); + } + for (PluginManager<? extends REIPlugin<?>> instance : PluginManager.getActiveInstances()) { + instance.view().post(stage); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + public static void reloadPlugins(MutableLong lastReload, @Nullable ReloadStage start) { + if (lastReload != null) { + if (lastReload.getValue() > 0 && System.currentTimeMillis() - lastReload.getValue() <= 5000) { + InternalLogger.getInstance().warn("Suppressing Reload Plugins of stage " + start); + return; + } + lastReload.setValue(System.currentTimeMillis()); + } + if (start == null) PluginReloaderImpl.PERFORMANCE_LOGGER.clear(); + if (Platform.getEnvironment() == Env.CLIENT) { + if (CoreClientInitialization.reloadPluginsClient(start)) return; + } + _reloadPlugins(start); + } +} |
