From 23c820ea583052744232e84a6c99114223c43a69 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Thu, 25 Mar 2021 02:50:16 +0800 Subject: Refactor MenuInfo, split client and server apis, new dual PluginManager system, remove @NotNull Signed-off-by: shedaniel --- .../main/java/me/shedaniel/rei/PluginDetector.java | 5 + .../me/shedaniel/rei/REIModMenuEntryPoint.java | 2 +- .../me/shedaniel/rei/RoughlyEnoughItemsCore.java | 231 ++++++--- .../shedaniel/rei/RoughlyEnoughItemsNetwork.java | 30 +- .../gui/config/entry/FilteringAddRuleScreen.java | 195 ++++++++ .../client/gui/config/entry/FilteringEntry.java | 110 +++++ .../config/entry/FilteringRuleOptionsScreen.java | 240 +++++++++ .../gui/config/entry/FilteringRulesScreen.java | 247 +++++++++ .../client/gui/config/entry/FilteringScreen.java | 518 +++++++++++++++++++ .../client/gui/config/entry/NoFilteringEntry.java | 90 ++++ .../gui/config/entry/RecipeScreenTypeEntry.java | 112 +++++ .../gui/config/entry/ReloadPluginsEntry.java | 96 ++++ .../entry/SearchFilterSyntaxHighlightingEntry.java | 114 +++++ .../gui/config/entry/FilteringAddRuleScreen.java | 195 -------- .../rei/api/gui/config/entry/FilteringEntry.java | 110 ----- .../config/entry/FilteringRuleOptionsScreen.java | 240 --------- .../api/gui/config/entry/FilteringRulesScreen.java | 247 --------- .../rei/api/gui/config/entry/FilteringScreen.java | 520 ------------------- .../rei/api/gui/config/entry/NoFilteringEntry.java | 90 ---- .../gui/config/entry/RecipeScreenTypeEntry.java | 112 ----- .../api/gui/config/entry/ReloadPluginsEntry.java | 96 ---- .../entry/SearchFilterSyntaxHighlightingEntry.java | 114 ----- .../shedaniel/rei/api/server/InputSlotCrafter.java | 166 +++---- .../me/shedaniel/rei/compat/LBASupportPlugin.java | 8 +- .../rei/gui/AbstractDisplayViewingScreen.java | 28 +- .../rei/gui/CompositeDisplayViewingScreen.java | 42 +- .../shedaniel/rei/gui/ConfigReloadingScreen.java | 5 +- .../shedaniel/rei/gui/ContainerScreenOverlay.java | 100 ++-- .../me/shedaniel/rei/gui/CurrentDraggingStack.java | 12 +- .../rei/gui/DefaultDisplayViewingScreen.java | 51 +- .../java/me/shedaniel/rei/gui/DelegateScreen.java | 4 +- .../me/shedaniel/rei/gui/OverlaySearchField.java | 6 +- .../shedaniel/rei/gui/RecipeDisplayExporter.java | 2 +- .../java/me/shedaniel/rei/gui/RecipeScreen.java | 6 +- .../rei/gui/UncertainDisplayViewingScreen.java | 26 +- .../shedaniel/rei/gui/credits/CreditsScreen.java | 16 +- .../java/me/shedaniel/rei/gui/modules/Menu.java | 17 +- .../me/shedaniel/rei/gui/modules/MenuEntry.java | 2 +- .../entries/EntryStackSubsetsMenuEntry.java | 14 +- .../rei/gui/modules/entries/GameModeMenuEntry.java | 6 +- .../gui/modules/entries/SubSubsetsMenuEntry.java | 14 +- .../rei/gui/modules/entries/WeatherMenuEntry.java | 6 +- .../rei/gui/plugin/DefaultClientRuntimePlugin.java | 250 ++++++++++ .../rei/gui/plugin/DefaultRuntimePlugin.java | 250 ---------- .../rei/gui/plugin/entry/FluidEntryDefinition.java | 59 ++- .../rei/gui/plugin/entry/ItemEntryDefinition.java | 40 +- .../gui/widget/DefaultDisplayChoosePageWidget.java | 12 +- .../shedaniel/rei/gui/widget/DraggableWidget.java | 2 +- .../rei/gui/widget/EntryListEntryWidget.java | 8 +- .../shedaniel/rei/gui/widget/EntryListWidget.java | 50 +- .../me/shedaniel/rei/gui/widget/EntryWidget.java | 44 +- .../rei/gui/widget/FavoritesListWidget.java | 62 ++- .../me/shedaniel/rei/gui/widget/QueuedTooltip.java | 9 +- .../me/shedaniel/rei/gui/widget/TabWidget.java | 24 +- .../me/shedaniel/rei/impl/AbstractEntryStack.java | 137 ----- .../me/shedaniel/rei/impl/ClientHelperImpl.java | 436 ---------------- .../me/shedaniel/rei/impl/ConfigManagerImpl.java | 336 ------------- .../me/shedaniel/rei/impl/ConfigObjectImpl.java | 542 -------------------- .../rei/impl/DynamicErrorFreeEntryListWidget.java | 2 +- .../me/shedaniel/rei/impl/EntryRegistryImpl.java | 211 -------- .../me/shedaniel/rei/impl/EntryTypeDeferred.java | 65 --- .../shedaniel/rei/impl/EntryTypeRegistryImpl.java | 98 ---- .../me/shedaniel/rei/impl/ExclusionZonesImpl.java | 131 ----- .../rei/impl/FavoriteEntryTypeRegistryImpl.java | 109 ---- .../rei/impl/FluidSupportProviderImpl.java | 78 --- .../rei/impl/HashedEntryStackWrapper.java | 62 --- .../me/shedaniel/rei/impl/InternalWidgets.java | 64 ++- .../impl/OverlaySearchFieldSyntaxHighlighter.java | 2 +- .../me/shedaniel/rei/impl/PluginManagerImpl.java | 198 ++++---- .../java/me/shedaniel/rei/impl/REIHelperImpl.java | 16 +- .../me/shedaniel/rei/impl/ScreenRegistryImpl.java | 235 --------- .../me/shedaniel/rei/impl/SimpleFluidRenderer.java | 78 --- .../me/shedaniel/rei/impl/TypedEntryStack.java | 113 ----- .../common/category/CategoryIdentifierImpl.java | 65 +++ .../display/DisplaySerializerRegistryImpl.java | 79 +++ .../impl/common/transfer/MenuInfoRegistryImpl.java | 72 +++ .../rei/impl/config/ConfigManagerImpl.java | 337 +++++++++++++ .../rei/impl/config/ConfigObjectImpl.java | 550 +++++++++++++++++++++ .../rei/impl/entry/EmptyEntryDefinition.java | 188 ------- .../rei/impl/entry/EntryIngredientImpl.java | 31 +- .../impl/entry/FavoriteEntryTypeRegistryImpl.java | 106 ++++ .../rei/impl/entry/ItemComparatorRegistryImpl.java | 8 +- .../rei/impl/entry/NbtHasherProviderImpl.java | 100 ++++ .../entry/filtering/AbstractFilteringRule.java | 40 ++ .../rei/impl/entry/filtering/FilteringContext.java | 47 ++ .../impl/entry/filtering/FilteringContextImpl.java | 104 ++++ .../impl/entry/filtering/FilteringContextType.java | 34 ++ .../rei/impl/entry/filtering/FilteringResult.java | 93 ++++ .../impl/entry/filtering/FilteringResultImpl.java | 55 +++ .../rei/impl/entry/filtering/FilteringRule.java | 89 ++++ .../entry/filtering/rules/ManualFilteringRule.java | 80 +++ .../entry/filtering/rules/SearchFilteringRule.java | 164 ++++++ .../rei/impl/entry/stack/AbstractEntryStack.java | 137 +++++ .../rei/impl/entry/stack/TypedEntryStack.java | 111 +++++ .../rei/impl/entry/type/EntryRegistryImpl.java | 209 ++++++++ .../rei/impl/entry/type/EntryTypeDeferred.java | 64 +++ .../rei/impl/entry/type/EntryTypeRegistryImpl.java | 96 ++++ .../entry/type/types/BuiltinEntryDefinition.java | 141 ++++++ .../entry/type/types/EmptyEntryDefinition.java | 55 +++ .../entry/type/types/RenderingEntryDefinition.java | 73 +++ .../rei/impl/filtering/AbstractFilteringRule.java | 40 -- .../rei/impl/filtering/FilteringContext.java | 47 -- .../rei/impl/filtering/FilteringContextImpl.java | 104 ---- .../rei/impl/filtering/FilteringContextType.java | 34 -- .../rei/impl/filtering/FilteringResult.java | 93 ---- .../rei/impl/filtering/FilteringResultImpl.java | 55 --- .../rei/impl/filtering/FilteringRule.java | 91 ---- .../impl/filtering/rules/ManualFilteringRule.java | 81 --- .../impl/filtering/rules/SearchFilteringRule.java | 169 ------- .../rei/impl/fluid/FluidSupportProviderImpl.java | 77 +++ .../rei/impl/nbt/NbtHasherProviderImpl.java | 100 ---- .../rei/impl/registry/CategoryRegistryImpl.java | 55 ++- .../rei/impl/registry/ClientHelperImpl.java | 430 ++++++++++++++++ .../rei/impl/registry/DisplayRegistryImpl.java | 32 +- .../impl/registry/RecipeManagerContextImpl.java | 5 +- .../impl/registry/screen/ExclusionZonesImpl.java | 131 +++++ .../impl/registry/screen/ScreenRegistryImpl.java | 233 +++++++++ .../rei/impl/search/AlternativeArgument.java | 23 + .../impl/search/AlwaysMatchingArgumentType.java | 2 +- .../me/shedaniel/rei/impl/search/Argument.java | 8 +- .../rei/impl/search/ArgumentApplicableResult.java | 11 +- .../me/shedaniel/rei/impl/search/ArgumentType.java | 4 +- .../rei/impl/search/CompoundArgument.java | 23 + .../rei/impl/search/IdentifierArgumentType.java | 6 +- .../shedaniel/rei/impl/search/ModArgumentType.java | 8 +- .../rei/impl/search/RegexArgumentType.java | 2 +- .../rei/impl/search/SearchProviderImpl.java | 29 +- .../shedaniel/rei/impl/search/TagArgumentType.java | 8 +- .../rei/impl/search/TextArgumentType.java | 2 +- .../rei/impl/search/TooltipArgumentType.java | 6 +- .../rei/impl/subsets/SubsetsRegistryImpl.java | 24 +- .../impl/transfer/TransferHandlerRegistryImpl.java | 10 +- .../rei/impl/utils/HashedEntryStackWrapper.java | 62 +++ .../java/me/shedaniel/rei/impl/view/ViewsImpl.java | 47 +- .../me/shedaniel/rei/impl/widgets/ArrowWidget.java | 9 +- .../rei/impl/widgets/BurningFireWidget.java | 9 +- .../shedaniel/rei/impl/widgets/ButtonWidget.java | 45 +- .../shedaniel/rei/impl/widgets/DrawableWidget.java | 8 +- .../widgets/FillRectangleDrawableConsumer.java | 8 +- .../me/shedaniel/rei/impl/widgets/LabelWidget.java | 24 +- .../me/shedaniel/rei/impl/widgets/PanelWidget.java | 21 +- .../rei/impl/widgets/TextFieldWidget.java | 8 +- .../rei/impl/widgets/TexturedDrawableConsumer.java | 8 +- .../autocrafting/DefaultCategoryHandler.java | 136 ++--- .../shedaniel/rei/tests/plugin/REITestPlugin.java | 11 +- 145 files changed, 6881 insertions(+), 6554 deletions(-) create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringAddRuleScreen.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringRuleOptionsScreen.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringRulesScreen.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringScreen.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/NoFilteringEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/RecipeScreenTypeEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/ReloadPluginsEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/SearchFilterSyntaxHighlightingEntry.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/FilteringAddRuleScreen.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/FilteringEntry.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/FilteringRuleOptionsScreen.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/FilteringRulesScreen.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/FilteringScreen.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/NoFilteringEntry.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/RecipeScreenTypeEntry.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/ReloadPluginsEntry.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/api/gui/config/entry/SearchFilterSyntaxHighlightingEntry.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/gui/plugin/DefaultClientRuntimePlugin.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/gui/plugin/DefaultRuntimePlugin.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/AbstractEntryStack.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/ClientHelperImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/EntryTypeDeferred.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/EntryTypeRegistryImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/ExclusionZonesImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/FavoriteEntryTypeRegistryImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/FluidSupportProviderImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/HashedEntryStackWrapper.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/ScreenRegistryImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/SimpleFluidRenderer.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/TypedEntryStack.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/category/CategoryIdentifierImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/display/DisplaySerializerRegistryImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/MenuInfoRegistryImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/config/ConfigManagerImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/config/ConfigObjectImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/EmptyEntryDefinition.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/FavoriteEntryTypeRegistryImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/NbtHasherProviderImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/AbstractFilteringRule.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/FilteringContext.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/FilteringContextImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/FilteringContextType.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/FilteringResult.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/FilteringResultImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/FilteringRule.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/rules/ManualFilteringRule.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/filtering/rules/SearchFilteringRule.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/stack/AbstractEntryStack.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/stack/TypedEntryStack.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/type/EntryRegistryImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/type/EntryTypeDeferred.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/type/EntryTypeRegistryImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/type/types/BuiltinEntryDefinition.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/type/types/EmptyEntryDefinition.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/entry/type/types/RenderingEntryDefinition.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/AbstractFilteringRule.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContext.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringContextType.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResult.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringResultImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/FilteringRule.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/rules/ManualFilteringRule.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/filtering/rules/SearchFilteringRule.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/fluid/FluidSupportProviderImpl.java delete mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/nbt/NbtHasherProviderImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/registry/ClientHelperImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/registry/screen/ExclusionZonesImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/registry/screen/ScreenRegistryImpl.java create mode 100644 runtime/src/main/java/me/shedaniel/rei/impl/utils/HashedEntryStackWrapper.java (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/PluginDetector.java b/runtime/src/main/java/me/shedaniel/rei/PluginDetector.java index 528e279a6..3b808ce89 100644 --- a/runtime/src/main/java/me/shedaniel/rei/PluginDetector.java +++ b/runtime/src/main/java/me/shedaniel/rei/PluginDetector.java @@ -33,6 +33,11 @@ public class PluginDetector { throw new AssertionError(); } + @ExpectPlatform + public static void detectCommonPlugins() { + throw new AssertionError(); + } + @Environment(EnvType.CLIENT) @ExpectPlatform public static void detectClientPlugins() { diff --git a/runtime/src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java b/runtime/src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java index 24012586a..60ac59223 100644 --- a/runtime/src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java +++ b/runtime/src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java @@ -24,7 +24,7 @@ package me.shedaniel.rei; import me.shedaniel.architectury.platform.Platform; -import me.shedaniel.rei.api.config.ConfigManager; +import me.shedaniel.rei.api.client.config.ConfigManager; public class REIModMenuEntryPoint { public void onInitializeClient() { diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index 20fe06192..eee235266 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java @@ -30,35 +30,59 @@ import me.shedaniel.architectury.event.events.GuiEvent; import me.shedaniel.architectury.event.events.RecipeUpdateEvent; import me.shedaniel.architectury.event.events.client.ClientScreenInputEvent; import me.shedaniel.architectury.networking.NetworkManager; +import me.shedaniel.architectury.platform.Platform; +import me.shedaniel.architectury.utils.Env; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; -import me.shedaniel.rei.api.REIHelper; -import me.shedaniel.rei.api.REIOverlay; -import me.shedaniel.rei.api.config.ConfigObject; -import me.shedaniel.rei.api.favorites.FavoriteEntry; -import me.shedaniel.rei.api.favorites.FavoriteEntryType; -import me.shedaniel.rei.api.favorites.FavoriteMenuEntry; -import me.shedaniel.rei.api.gui.DrawableConsumer; -import me.shedaniel.rei.api.gui.Renderer; -import me.shedaniel.rei.api.gui.widgets.*; -import me.shedaniel.rei.api.ingredient.EntryStack; -import me.shedaniel.rei.api.ingredient.entry.renderer.EntryRenderer; -import me.shedaniel.rei.api.ingredient.entry.type.BuiltinEntryTypes; -import me.shedaniel.rei.api.ingredient.entry.type.EntryDefinition; -import me.shedaniel.rei.api.ingredient.entry.type.EntryType; -import me.shedaniel.rei.api.ingredient.util.EntryStacks; -import me.shedaniel.rei.api.plugins.PluginManager; -import me.shedaniel.rei.api.registry.screen.ClickArea; -import me.shedaniel.rei.api.registry.screen.OverlayDecider; -import me.shedaniel.rei.api.registry.screen.ScreenRegistry; -import me.shedaniel.rei.api.view.Views; +import me.shedaniel.rei.api.client.REIHelper; +import me.shedaniel.rei.api.client.REIOverlay; +import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.favorites.FavoriteEntry; +import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; +import me.shedaniel.rei.api.client.gui.DrawableConsumer; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.widgets.*; +import me.shedaniel.rei.api.client.ingredient.entry.renderer.EntryRenderer; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.screen.ClickArea; +import me.shedaniel.rei.api.client.registry.screen.OverlayDecider; +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; +import me.shedaniel.rei.api.client.view.Views; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.ingredient.EntryStack; +import me.shedaniel.rei.api.common.ingredient.entry.type.BuiltinEntryTypes; +import me.shedaniel.rei.api.common.ingredient.entry.type.EntryDefinition; +import me.shedaniel.rei.api.common.ingredient.entry.type.EntryType; +import me.shedaniel.rei.api.common.ingredient.util.EntryStacks; +import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.plugins.PluginView; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.api.common.plugins.REIServerPlugin; import me.shedaniel.rei.gui.ContainerScreenOverlay; import me.shedaniel.rei.gui.widget.EntryWidget; import me.shedaniel.rei.gui.widget.QueuedTooltip; import me.shedaniel.rei.impl.*; -import me.shedaniel.rei.impl.entry.EmptyEntryDefinition; +import me.shedaniel.rei.impl.common.category.CategoryIdentifierImpl; +import me.shedaniel.rei.impl.common.transfer.MenuInfoRegistryImpl; +import me.shedaniel.rei.impl.config.ConfigManagerImpl; import me.shedaniel.rei.impl.entry.EntryIngredientImpl; -import me.shedaniel.rei.impl.nbt.NbtHasherProviderImpl; +import me.shedaniel.rei.impl.entry.FavoriteEntryTypeRegistryImpl; +import me.shedaniel.rei.impl.entry.ItemComparatorRegistryImpl; +import me.shedaniel.rei.impl.entry.NbtHasherProviderImpl; +import me.shedaniel.rei.impl.entry.stack.TypedEntryStack; +import me.shedaniel.rei.impl.entry.type.EntryRegistryImpl; +import me.shedaniel.rei.impl.entry.type.EntryTypeDeferred; +import me.shedaniel.rei.impl.entry.type.EntryTypeRegistryImpl; +import me.shedaniel.rei.impl.entry.type.types.EmptyEntryDefinition; +import me.shedaniel.rei.impl.entry.type.types.RenderingEntryDefinition; +import me.shedaniel.rei.impl.fluid.FluidSupportProviderImpl; +import me.shedaniel.rei.impl.registry.CategoryRegistryImpl; +import me.shedaniel.rei.impl.registry.DisplayRegistryImpl; +import me.shedaniel.rei.impl.registry.screen.ScreenRegistryImpl; +import me.shedaniel.rei.impl.search.SearchProviderImpl; +import me.shedaniel.rei.impl.subsets.SubsetsRegistryImpl; +import me.shedaniel.rei.impl.transfer.TransferHandlerRegistryImpl; import me.shedaniel.rei.impl.view.ViewsImpl; import me.shedaniel.rei.impl.widgets.*; import me.shedaniel.rei.tests.plugin.REITestPlugin; @@ -86,10 +110,10 @@ import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; +import org.apache.commons.lang3.mutable.MutableLong; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -100,10 +124,9 @@ import java.util.concurrent.Executors; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import java.util.stream.Stream; -import static me.shedaniel.rei.impl.Internals.attachInstance; - @ApiStatus.Internal @Environment(EnvType.CLIENT) public class RoughlyEnoughItemsCore { @@ -113,73 +136,110 @@ public class RoughlyEnoughItemsCore { public static boolean isLeftModePressed = false; static { - Map> typeCache = new ConcurrentHashMap<>(); - attachInstance((Function>) id -> { - if (id.equals(BuiltinEntryTypes.EMPTY_ID)) { - return BuiltinEntryTypes.EMPTY; - } else if (id.equals(BuiltinEntryTypes.RENDERING_ID)) { - return BuiltinEntryTypes.RENDERING; - } - return typeCache.computeIfAbsent(id, EntryTypeDeferred::new); - }, "entryTypeDeferred"); - attachInstance(new PluginManagerImpl(), PluginManager.class); - attachInstance(new Internals.EntryStackProvider() { + attachCommonInternals(); + if (Platform.getEnvironment() == Env.CLIENT) { + attachClientInternals(); + } + } + + public static void attachCommonInternals() { + CategoryIdentifierImpl.attach(); + Internals.attachInstance(new PluginManagerImpl>( + UnaryOperator.identity(), + new EntryTypeRegistryImpl(), + new ItemComparatorRegistryImpl(), + new FluidSupportProviderImpl()), "commonPluginManager"); + Internals.attachInstance(new PluginManagerImpl( + view -> view.then(PluginView.getInstance()), + new MenuInfoRegistryImpl()), "serverPluginManager"); + Internals.attachInstance((Function>) new Function>() { + ResourceLocation RENDERING_ID = new ResourceLocation("rendering"); + private Map> typeCache = new ConcurrentHashMap<>(); private EntryType empty; + @Environment(EnvType.CLIENT) private EntryType render; @Override - public EntryStack empty() { - return TypedEntryStack.EMPTY; - } - - @Override - public EntryStack of(EntryDefinition definition, T value) { - if (Objects.equals(definition.getType().getId(), BuiltinEntryTypes.EMPTY_ID)) { - return empty().cast(); + public EntryType apply(ResourceLocation id) { + if (id.equals(BuiltinEntryTypes.EMPTY_ID)) { + return typeCache.computeIfAbsent(id, this::emptyType); + } else if (id.equals(RENDERING_ID) && Platform.getEnv() == EnvType.CLIENT) { + return typeCache.computeIfAbsent(id, this::renderingType); } - - return new TypedEntryStack<>(definition, value); + return typeCache.computeIfAbsent(id, EntryTypeDeferred::new); } - @Override public EntryType emptyType(ResourceLocation id) { if (empty == null) { empty = new EntryType() { @Override - public @NotNull ResourceLocation getId() { + public ResourceLocation getId() { return id; } - @SuppressWarnings("rawtypes") @Override - public @NotNull EntryDefinition getDefinition() { - return (EntryDefinition) EmptyEntryDefinition.EMPTY; + public EntryDefinition getDefinition() { + return EmptyEntryDefinition.EMPTY; } }; } return empty; } - @Override + @Environment(EnvType.CLIENT) public EntryType renderingType(ResourceLocation id) { if (render == null) { render = new EntryType() { @Override - public @NotNull ResourceLocation getId() { + public ResourceLocation getId() { return id; } @SuppressWarnings("rawtypes") @Override - public @NotNull EntryDefinition getDefinition() { - return (EntryDefinition) EmptyEntryDefinition.RENDERING; + public EntryDefinition getDefinition() { + return RenderingEntryDefinition.RENDERING; } }; } return render; } + }, "entryTypeDeferred"); + Internals.attachInstance(new Internals.EntryStackProvider() { + @Override + public EntryStack empty() { + return TypedEntryStack.EMPTY; + } + + @Override + public EntryStack of(EntryDefinition definition, T value) { + if (Objects.equals(definition.getType().getId(), BuiltinEntryTypes.EMPTY_ID)) { + return empty().cast(); + } + + return new TypedEntryStack<>(definition, value); + } }, Internals.EntryStackProvider.class); - attachInstance(new Internals.WidgetsProvider() { + Internals.attachInstance(new NbtHasherProviderImpl(), Internals.NbtHasherProvider.class); + Internals.attachInstance(EntryIngredientImpl.provide(), Internals.EntryIngredientProvider.class); + } + + @Environment(EnvType.CLIENT) + public static void attachClientInternals() { + ClientInternals.attachInstance(new PluginManagerImpl( + view -> view.then(PluginView.getInstance()), + new ViewsImpl(), + new SearchProviderImpl(), + new ConfigManagerImpl(), + new CategoryRegistryImpl(), + new DisplayRegistryImpl(), + new ScreenRegistryImpl(), + new EntryRegistryImpl(), + new FavoriteEntryTypeRegistryImpl(), + new SubsetsRegistryImpl(), + new TransferHandlerRegistryImpl(), + new REIHelperImpl()), "clientPluginManager"); + ClientInternals.attachInstance(new ClientInternals.WidgetsProvider() { @Override public boolean isRenderingPanel(Panel panel) { return PanelWidget.isRendering(panel); @@ -191,10 +251,15 @@ public class RoughlyEnoughItemsCore { } @Override - public me.shedaniel.rei.api.gui.widgets.Slot createSlot(Point point) { + public me.shedaniel.rei.api.client.gui.widgets.Slot createSlot(Point point) { return new EntryWidget(point); } + @Override + public me.shedaniel.rei.api.client.gui.widgets.Slot createSlot(Rectangle bounds) { + return new EntryWidget(bounds); + } + @Override public Button createButton(Rectangle bounds, Component text) { return new ButtonWidget(bounds, text); @@ -229,12 +294,10 @@ public class RoughlyEnoughItemsCore { public DrawableConsumer createFillRectangleConsumer(Rectangle rectangle, int color) { return new FillRectangleDrawableConsumer(rectangle, color); } - }, Internals.WidgetsProvider.class); - attachInstance(new ViewsImpl(), Views.class); - attachInstance(new NbtHasherProviderImpl(), Internals.NbtHasherProvider.class); - attachInstance(EntryIngredientImpl.provide(), Internals.EntryIngredientProvider.class); - attachInstance((Supplier>) () -> EmptyEntryDefinition.EmptyRenderer.INSTANCE, "emptyEntryRenderer"); - attachInstance((BiFunction, Supplier, FavoriteEntry>) (supplier, toJson) -> new FavoriteEntry() { + }, ClientInternals.WidgetsProvider.class); + ClientInternals.attachInstance(new ViewsImpl(), Views.class); + ClientInternals.attachInstance((Supplier>) () -> EmptyEntryDefinition.EmptyRenderer.INSTANCE, "emptyEntryRenderer"); + ClientInternals.attachInstance((BiFunction, Supplier, FavoriteEntry>) (supplier, toJson) -> new FavoriteEntry() { FavoriteEntry value = null; @Override @@ -270,7 +333,7 @@ public class RoughlyEnoughItemsCore { } @Override - public @NotNull Optional>> getMenuEntries() { + public Optional>> getMenuEntries() { return getUnwrapped().getMenuEntries(); } @@ -290,7 +353,7 @@ public class RoughlyEnoughItemsCore { } @Override - public @NotNull JsonObject toJson(@NotNull JsonObject to) { + public JsonObject toJson(JsonObject to) { if (toJson == null) { return getUnwrapped().toJson(to); } @@ -307,7 +370,7 @@ public class RoughlyEnoughItemsCore { return getUnwrapped().isSame(other.getUnwrapped()); } }, "delegateFavoriteEntry"); - attachInstance((Function) (object) -> { + ClientInternals.attachInstance((Function) (object) -> { String type = GsonHelper.getAsString(object, FavoriteEntry.TYPE_KEY); switch (type) { case "stack": @@ -320,12 +383,12 @@ public class RoughlyEnoughItemsCore { return Objects.requireNonNull(Objects.requireNonNull(FavoriteEntryType.registry().get(id)).fromJson(object)); } }, "favoriteEntryFromJson"); - attachInstance((BiFunction<@Nullable Point, Collection, Tooltip>) QueuedTooltip::create, "tooltipProvider"); - attachInstance((Function<@Nullable Boolean, ClickArea.Result>) successful -> new ClickArea.Result() { - private List categories = Lists.newArrayList(); + ClientInternals.attachInstance((BiFunction<@Nullable Point, Collection, Tooltip>) QueuedTooltip::create, "tooltipProvider"); + ClientInternals.attachInstance((Function<@Nullable Boolean, ClickArea.Result>) successful -> new ClickArea.Result() { + private List> categories = Lists.newArrayList(); @Override - public ClickArea.Result category(ResourceLocation category) { + public ClickArea.Result category(CategoryIdentifier category) { this.categories.add(category); return this; } @@ -336,7 +399,7 @@ public class RoughlyEnoughItemsCore { } @Override - public Stream getCategories() { + public Stream> getCategories() { return categories.stream(); } }, "clickAreaHandlerResult"); @@ -364,18 +427,24 @@ public class RoughlyEnoughItemsCore { } @ApiStatus.Internal - public static void syncRecipes(long[] lastSync) { - if (lastSync != null) { - if (lastSync[0] > 0 && System.currentTimeMillis() - lastSync[0] <= 5000) { - RoughlyEnoughItemsCore.LOGGER.warn("Suppressing Sync Recipes!"); + public static void reloadPlugins(MutableLong lastReload) { + if (lastReload != null) { + if (lastReload.getValue() > 0 && System.currentTimeMillis() - lastReload.getValue() <= 5000) { + RoughlyEnoughItemsCore.LOGGER.warn("Suppressing Reload Plugins!"); return; } - lastSync[0] = System.currentTimeMillis(); + lastReload.setValue(System.currentTimeMillis()); } if (ConfigObject.getInstance().doesRegisterRecipesInAnotherThread()) { - CompletableFuture.runAsync(() -> ((PluginManagerImpl) PluginManager.getInstance()).tryResetData(), SYNC_RECIPES); + CompletableFuture.runAsync(RoughlyEnoughItemsCore::_reloadPlugins, SYNC_RECIPES); } else { - ((PluginManagerImpl) PluginManager.getInstance()).tryResetData(); + _reloadPlugins(); + } + } + + private static void _reloadPlugins() { + for (PluginManager> instance : PluginManager.getActiveInstances()) { + instance.startReload(); } } @@ -435,7 +504,7 @@ public class RoughlyEnoughItemsCore { private void loadTestPlugins() { if (isDebugModeEnabled()) { - PluginManager.getInstance().registerPlugin(new REITestPlugin()); + PluginView.getClientInstance().registerPlugin(new REITestPlugin()); } } @@ -465,8 +534,8 @@ public class RoughlyEnoughItemsCore { private void registerClothEvents() { Minecraft client = Minecraft.getInstance(); final ResourceLocation recipeButtonTex = new ResourceLocation("textures/gui/recipe_button.png"); - long[] lastSync = {-1}; - RecipeUpdateEvent.EVENT.register(recipeManager -> syncRecipes(lastSync)); + MutableLong lastReload = new MutableLong(-1); + RecipeUpdateEvent.EVENT.register(recipeManager -> reloadPlugins(lastReload)); GuiEvent.INIT_POST.register((screen, widgets, children) -> { REIHelperImpl.getInstance().setPreviousScreen(screen); if (ConfigObject.getInstance().doesDisableRecipeBook() && screen instanceof AbstractContainerScreen) { diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java index 4013f6210..852471faa 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java @@ -23,26 +23,25 @@ package me.shedaniel.rei; -import com.google.common.collect.Lists; import io.netty.buffer.Unpooled; import me.shedaniel.architectury.networking.NetworkManager; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.server.InputSlotCrafter; import net.minecraft.ChatFormatting; import net.minecraft.Util; -import net.minecraft.core.NonNullList; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; +import net.minecraft.world.Container; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.inventory.RecipeBookMenu; import net.minecraft.world.item.ItemStack; -import java.util.List; - public class RoughlyEnoughItemsNetwork { public static final ResourceLocation DELETE_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "delete_item"); public static final ResourceLocation CREATE_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "create_item"); @@ -52,6 +51,7 @@ public class RoughlyEnoughItemsNetwork { public static final ResourceLocation NOT_ENOUGH_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "og_not_enough"); public void onInitialize() { + PluginDetector.detectCommonPlugins(); PluginDetector.detectServerPlugins(); NetworkManager.registerReceiver(NetworkManager.c2s(), DELETE_ITEMS_PACKET, (buf, context) -> { ServerPlayer player = (ServerPlayer) context.getPlayer(); @@ -98,27 +98,19 @@ public class RoughlyEnoughItemsNetwork { }); NetworkManager.registerReceiver(NetworkManager.c2s(), MOVE_ITEMS_PACKET, (packetByteBuf, context) -> { ServerPlayer player = (ServerPlayer) context.getPlayer(); - ResourceLocation category = packetByteBuf.readResourceLocation(); + CategoryIdentifier category = CategoryIdentifier.of(packetByteBuf.readResourceLocation()); AbstractContainerMenu container = player.containerMenu; InventoryMenu playerContainer = player.inventoryMenu; try { boolean shift = packetByteBuf.readBoolean(); - NonNullList> input = NonNullList.create(); - int mapSize = packetByteBuf.readInt(); - for (int i = 0; i < mapSize; i++) { - List list = Lists.newArrayList(); - int count = packetByteBuf.readInt(); - for (int j = 0; j < count; j++) { - list.add(packetByteBuf.readItem()); - } - input.add(list); - } try { - InputSlotCrafter.start(category, container, player, input, shift); + InputSlotCrafter crafter = InputSlotCrafter.start(category, container, player, packetByteBuf.readNbt(), shift); } catch (InputSlotCrafter.NotEnoughMaterialsException e) { - if (!(container instanceof RecipeBookMenu)) + if (!(container instanceof RecipeBookMenu)) { return; - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + } + // TODO Implement Ghost Recipes + /*FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); buf.writeInt(input.size()); for (List stacks : input) { buf.writeInt(stacks.size()); @@ -126,7 +118,7 @@ public class RoughlyEnoughItemsNetwork { buf.writeItem(stack); } } - NetworkManager.sendToPlayer(player, NOT_ENOUGH_ITEMS_PACKET, buf); + NetworkManager.sendToPlayer(player, NOT_ENOUGH_ITEMS_PACKET, buf);*/ } catch (IllegalStateException e) { player.sendMessage(new TranslatableComponent(e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); } catch (Exception e) { diff --git a/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringAddRuleScreen.java b/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringAddRuleScreen.java new file mode 100644 index 000000000..5b023b246 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringAddRuleScreen.java @@ -0,0 +1,195 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 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.api.client.gui.config.entry; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; +import me.shedaniel.rei.impl.entry.filtering.FilteringRule; +import me.shedaniel.rei.impl.entry.filtering.rules.ManualFilteringRule; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.locale.Language; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.BiFunction; + +public class FilteringAddRuleScreen extends Screen { + private final FilteringEntry entry; + private RulesList rulesList; + Screen parent; + + public FilteringAddRuleScreen(FilteringEntry entry) { + super(new TranslatableComponent("config.roughlyenoughitems.filteringRulesScreen.new")); + this.entry = entry; + } + + @Override + public void init() { + super.init(); + { + Component backText = new TextComponent("↩ ").append(new TranslatableComponent("gui.back")); + addButton(new Button(4, 4, Minecraft.getInstance().font.width(backText) + 10, 20, backText, button -> { + minecraft.setScreen(parent); + this.parent = null; + })); + } + rulesList = addWidget(new RulesList(minecraft, width, height, 30, height, BACKGROUND_LOCATION)); + for (FilteringRule rule : FilteringRule.REGISTRY) { + if (!(rule instanceof ManualFilteringRule)) + rulesList.addItem(new DefaultRuleEntry(parent, entry, rule.createNew(), null)); + } + rulesList.selectItem(rulesList.children().get(0)); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + this.rulesList.render(matrices, mouseX, mouseY, delta); + super.render(matrices, mouseX, mouseY, delta); + this.font.drawShadow(matrices, this.title.getVisualOrderText(), this.width / 2.0F - this.font.width(this.title) / 2.0F, 12.0F, -1); + } + + public static class RulesList extends DynamicElementListWidget { + private boolean inFocus; + + public RulesList(Minecraft client, int width, int height, int top, int bottom, ResourceLocation backgroundLocation) { + super(client, width, height, top, bottom, backgroundLocation); + } + + @Override + public boolean changeFocus(boolean lookForwards) { + if (!this.inFocus && this.getItemCount() == 0) { + return false; + } else { + this.inFocus = !this.inFocus; + if (this.inFocus && this.getSelectedItem() == null && this.getItemCount() > 0) { + this.moveSelection(1); + } else if (this.inFocus && this.getSelectedItem() != null) { + this.getSelectedItem(); + } + + return this.inFocus; + } + } + + @Override + protected boolean isSelected(int index) { + return Objects.equals(this.getSelectedItem(), this.children().get(index)); + } + + @Override + protected int addItem(RuleEntry item) { + return super.addItem(item); + } + + @Override + public int getItemWidth() { + return width - 40; + } + + @Override + protected int getScrollbarPosition() { + return width - 14; + } + } + + public static abstract class RuleEntry extends DynamicElementListWidget.ElementEntry { + private final FilteringRule rule; + + public RuleEntry(FilteringRule rule) { + this.rule = rule; + } + + public FilteringRule getRule() { + return rule; + } + + @Override + public int getItemHeight() { + return 26; + } + + @Override + public boolean changeFocus(boolean lookForwards) { + return false; + } + } + + public static class DefaultRuleEntry extends RuleEntry { + private final Button addButton; + private final BiFunction screenFunction; + + public DefaultRuleEntry(Screen parent, FilteringEntry entry, FilteringRule rule, BiFunction screenFunction) { + super(rule); + this.screenFunction = (screenFunction == null ? rule.createEntryScreen().orElse(null) : screenFunction); + addButton = new Button(0, 0, 20, 20, Component.nullToEmpty(" + "), button -> { + entry.edited = true; + Minecraft.getInstance().setScreen(this.screenFunction.apply(entry, parent)); + entry.rules.add(0, rule); + }); + addButton.active = this.screenFunction != null; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + Minecraft client = Minecraft.getInstance(); + { + Component title = getRule().getTitle(); + int i = client.font.width(title); + if (i > entryWidth - 28) { + FormattedText titleTrimmed = FormattedText.composite(client.font.substrByWidth(title, entryWidth - 28 - client.font.width("...")), FormattedText.of("...")); + client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(titleTrimmed), x + 2, y + 1, 16777215); + } else { + client.font.drawShadow(matrices, title.getVisualOrderText(), x + 2, y + 1, 16777215); + } + } + { + Component subtitle = getRule().getSubtitle(); + int i = client.font.width(subtitle); + if (i > entryWidth - 28) { + FormattedText subtitleTrimmed = FormattedText.composite(client.font.substrByWidth(subtitle, entryWidth - 28 - client.font.width("...")), FormattedText.of("...")); + client.font.drawShadow(matrices, Language.getInstance().getVisualOrder(subtitleTrimmed), x + 2, y + 12, 8421504); + } else { + client.font.drawShadow(matrices, subtitle.getVisualOrderText(), x + 2, y + 12, 8421504); + } + } + addButton.x = x + entryWidth - 25; + addButton.y = y + 1; + addButton.render(matrices, mouseX, mouseY, delta); + } + + @Override + public List children() { + return Collections.singletonList(addButton); + } + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringEntry.java b/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringEntry.java new file mode 100644 index 000000000..c79cab5c9 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringEntry.java @@ -0,0 +1,110 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 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.api.client.gui.config.entry; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; +import me.shedaniel.rei.api.common.ingredient.EntryStack; +import me.shedaniel.rei.api.common.ingredient.util.EntryStacks; +import me.shedaniel.rei.impl.entry.filtering.FilteringRule; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.chat.NarratorChatListener; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.network.chat.TranslatableComponent; +import org.jetbrains.annotations.ApiStatus; + +import java.util.*; +import java.util.function.Consumer; + +@ApiStatus.Internal +public class FilteringEntry extends AbstractConfigListEntry> { + private int width; + Consumer> saveConsumer; + Consumer>> rulesSaveConsumer; + List defaultValue; + Set configFiltered; + List> rules; + boolean edited = false; + final FilteringScreen filteringScreen = new FilteringScreen(this); + final FilteringRulesScreen filteringRulesScreen = new FilteringRulesScreen(this); + private final AbstractWidget buttonWidget = new Button(0, 0, 0, 20, new TranslatableComponent("config.roughlyenoughitems.filteringScreen"), button -> { + filteringRulesScreen.parent = Minecraft.getInstance().screen; + Minecraft.getInstance().setScreen(filteringRulesScreen); + }); + private final List children = ImmutableList.of(buttonWidget); + + public FilteringEntry(int width, List configFiltered, List> rules, List defaultValue, Consumer> saveConsumer, Consumer>> rulesSaveConsumer) { + super(NarratorChatListener.NO_TITLE, false); + this.width = width; + this.configFiltered = new TreeSet<>(Comparator.comparing(EntryStacks::hashExact)); + this.configFiltered.addAll(configFiltered); + this.rules = Lists.newArrayList(rules); + this.defaultValue = defaultValue; + this.saveConsumer = saveConsumer; + this.rulesSaveConsumer = rulesSaveConsumer; + } + + @Override + public List getValue() { + return Lists.newArrayList(configFiltered); + } + + @Override + public Optional> getDefaultValue() { + return Optional.ofNullable(defaultValue); + } + + @Override + public void save() { + saveConsumer.accept(getValue()); + rulesSaveConsumer.accept(rules); + this.edited = false; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { + super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta); + Window window = Minecraft.getInstance().getWindow(); + this.buttonWidget.active = this.isEditable(); + this.buttonWidget.y = y; + this.buttonWidget.x = x + entryWidth / 2 - width / 2; + this.buttonWidget.setWidth(width); + this.buttonWidget.render(matrices, mouseX, mouseY, delta); + } + + @Override + public List children() { + return children; + } + + @Override + public boolean isEdited() { + return super.isEdited() || edited; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringRuleOptionsScreen.java b/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringRuleOptionsScreen.java new file mode 100644 index 000000000..1d6cf4e67 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/api/client/gui/config/entry/FilteringRuleOptionsScreen.java @@ -0,0 +1,240 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 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.api.client.gui.config.entry; + +import com.mojang.blaze3d.vertex.PoseStack; +import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget; +import me.shedaniel.rei.impl.entry.filtering.FilteringRule; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; + +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public abstract class FilteringRuleOptionsScreen> extends Screen { + private final FilteringEntry entry; + private RulesList rulesList; + Screen parent; + public T rule; + + public FilteringRuleOptionsScreen(FilteringEntry entry, T rule, Screen screen) { + super(new TranslatableComponent("config.roughlyenoughitems.filteringRulesScreen")); + this.entry = entry; + this.rule = rule; + this.parent = screen; + } + + @Override + public void init() { + super.init(); + if (rulesList != null) save(); + { + Component doneText = new TranslatableComponent("gui.done"); + int width = Minecraft.getInstance().font.width(doneText); + addButton(new Button(this.width - 4 - width - 10, 4, width + 10, 20, doneText, button -> { + save(); + minecraft.setScreen(parent); + })); + } + rulesList = addWidget(new RulesList(minecraft, width, height, 30, height, BACKGROUND_LOCATION)); + addEntries(ruleEntry -> rulesList.addItem(ruleEntry)); + } + + public abstract void addEntries(Consumer entryConsumer); + + public abstract void save(); + + public void addText(Consumer entryConsumer, FormattedText text) { + for (FormattedCharSequence s : font.split(text, width - 80)) { + entryConsumer.accept(new TextRuleEntry(rule, s)); + } + } + + public void addEmpty(Consumer entryConsumer, int height) { + entryConsumer.accept(new EmptyRuleEntry(rule, height)); + } + + @Override + public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { + this.rulesList.render(matrices, mouseX, mouseY, delta); + super.render(matrices, mouseX, mouseY, delta); + this.font.drawShadow(matrices, this.title.getVisualOrderText(), this.width / 2.0F - this.font.width(this.title) / 2.0F, 12.0F, -1); + } + + public static class RulesList extends DynamicElementListWidget { + public RulesList(Minecraft client, int width, int height, int top, int bottom, ResourceLocation backgroundLocation) { + super(client, width, height, top, bottom, backgroundLocation); + } + + @Override + protected int addItem(RuleEntry item) { + return super.addItem(item); + } + + @Override + public int getItemWidth() { + return width - 40; + } + + @Override + protected int getScrollbarPosition() { + return width - 14; + } + } + + public static abstract class RuleEntry extends DynamicElementListWidget.ElementEntry { + private final FilteringRule rule; + + public RuleEntry(FilteringRule rule) { + this.rule = rule; + } + + public FilteringRule getRule() { + return rule; + } + } + + public static class TextRuleEntry extends RuleEntry { + private final FormattedCharSequence text; + + public TextRuleEntry(FilteringRule rule, FormattedCharSequence text) { + super(rule); + this.text = text; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + Minecraft.getInstance().font.drawShadow(matrices, text, x + 5, y, -1); + } + + @Override + public int getItemHeight() { + return 12; + } + + @Override + public List children() { + return Collections.emptyList(); + } + } + + public static class EmptyRuleEntry extends RuleEntry { + private final int height; + + public EmptyRuleEntry(FilteringRule rule, int height) { + super(rule); + this.height = height; + } + + @Override + public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + } + + @Override + public int getItemHeight() { + return height; + } + + @Override + public List children() { + return Collections.emptyList(); + } + } + + public static class TextFieldRuleEntry extends RuleEntry { + private final EditBox widget; + + public TextFieldRuleEntry(int width, FilteringRule rule, Consumer widgetConsumer) { + super(rule); + this.widget = new EditBox(Minecraft.getInstance().font, 0, 0, width, 18, Component.nullToEmpty("")); + widgetConsumer.accept(widget); + } + + @Override + public void render(PoseStack mat