diff options
| author | shedaniel <daniel@shedaniel.me> | 2021-02-21 22:33:45 +0800 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2021-02-21 22:33:45 +0800 |
| commit | a56baa875630ffac06e421a7389854b5301ed7f0 (patch) | |
| tree | 9469ff3f61f2aca622d6f86dbe8044769198e639 /runtime/src/main/java/me | |
| parent | 5eae235995583e378a884a14118095c1fda08fab (diff) | |
| download | RoughlyEnoughItems-a56baa875630ffac06e421a7389854b5301ed7f0.tar.gz RoughlyEnoughItems-a56baa875630ffac06e421a7389854b5301ed7f0.tar.bz2 RoughlyEnoughItems-a56baa875630ffac06e421a7389854b5301ed7f0.zip | |
More
Signed-off-by: shedaniel <daniel@shedaniel.me>
Diffstat (limited to 'runtime/src/main/java/me')
36 files changed, 1169 insertions, 320 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index c5baedb59..fcc8492f3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java @@ -28,7 +28,6 @@ import com.google.common.collect.Lists; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import me.shedaniel.cloth.api.client.events.v0.ClothClientHooks; -import me.shedaniel.clothconfig2.api.LazyResettable; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.math.api.Executor; @@ -40,7 +39,10 @@ import me.shedaniel.rei.api.favorites.FavoriteEntryType; import me.shedaniel.rei.api.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.fluid.FluidSupportProvider; import me.shedaniel.rei.api.ingredient.util.EntryStacks; -import me.shedaniel.rei.api.plugins.REIPluginV0; +import me.shedaniel.rei.api.plugins.REIPlugin; +import me.shedaniel.rei.api.registry.EntryRegistry; +import me.shedaniel.rei.api.registry.screens.OverlayDecider; +import me.shedaniel.rei.api.registry.screens.ScreenRegistry; import me.shedaniel.rei.api.subsets.SubsetsRegistry; import me.shedaniel.rei.api.gui.DrawableConsumer; import me.shedaniel.rei.api.gui.Renderer; @@ -124,9 +126,9 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { } return typeCache.computeIfAbsent(id, EntryTypeDeferred::new); }, "entryTypeDeferred"); - attachInstance(new RecipeRegistryImpl(), RecipeRegistry.class); + attachInstance(new PluginManager(), DisplayRegistry.class); attachInstance(new EntryRegistryImpl(), EntryRegistry.class); - attachInstance(new DisplayBoundsRegistryImpl(), DisplayBoundsRegistry.class); + attachInstance(new ScreenRegistryImpl(), ScreenRegistry.class); attachInstance(new FluidSupportProviderImpl(), FluidSupportProvider.class); attachInstance(new SubsetsRegistryImpl(), SubsetsRegistry.class); attachInstance(new Internals.EntryStackProvider() { @@ -225,15 +227,14 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { }, Internals.WidgetsProvider.class); attachInstance((Supplier<FavoriteEntryType.Registry>) FavoriteEntryTypeRegistryImpl::getInstance, "favoriteEntryTypeRegistry"); attachInstance((BiFunction<Supplier<FavoriteEntry>, Supplier<JsonObject>, FavoriteEntry>) (supplier, toJson) -> new FavoriteEntry() { - LazyResettable<FavoriteEntry> value = new LazyResettable<>(supplier); - + FavoriteEntry value = null; + @Override public FavoriteEntry getUnwrapped() { - FavoriteEntry entry = value.get(); - if (entry == null) { - value.reset(); + if (this.value == null) { + this.value = supplier.get(); } - return Objects.requireNonNull(entry).getUnwrapped(); + return Objects.requireNonNull(value).getUnwrapped(); } @Override @@ -382,9 +383,9 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { } RecipeManager recipeManager = Minecraft.getInstance().getConnection().getRecipeManager(); if (ConfigObject.getInstance().doesRegisterRecipesInAnotherThread()) { - CompletableFuture.runAsync(() -> ((RecipeRegistryImpl) RecipeRegistry.getInstance()).tryRecipesLoaded(recipeManager), SYNC_RECIPES); + CompletableFuture.runAsync(() -> ((PluginManager) DisplayRegistry.getInstance()).tryRecipesLoaded(recipeManager), SYNC_RECIPES); } else { - ((RecipeRegistryImpl) RecipeRegistry.getInstance()).tryRecipesLoaded(recipeManager); + ((PluginManager) DisplayRegistry.getInstance()).tryRecipesLoaded(recipeManager); } } @@ -452,20 +453,18 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { } private void discoverPluginEntries() { - for (REIPlugin reiPlugin : Iterables.concat( + for (REIPlugin plugin : Iterables.concat( FabricLoader.getInstance().getEntrypoints("rei_plugins", REIPlugin.class), FabricLoader.getInstance().getEntrypoints("rei", REIPlugin.class) )) { try { - if (!REIPluginV0.class.isAssignableFrom(reiPlugin.getClass())) - throw new IllegalArgumentException("REI plugin is too old!"); - registerPlugin(reiPlugin); + registerPlugin(plugin); } catch (Exception e) { e.printStackTrace(); - RoughlyEnoughItemsCore.LOGGER.error("Can't load REI plugins from %s: %s", reiPlugin.getClass(), e.getLocalizedMessage()); + RoughlyEnoughItemsCore.LOGGER.error("Can't load REI plugins from %s: %s", plugin.getClass(), e.getLocalizedMessage()); } } - for (REIPluginV0 reiPlugin : FabricLoader.getInstance().getEntrypoints("rei_plugins_v0", REIPluginV0.class)) { + for (REIPlugin reiPlugin : FabricLoader.getInstance().getEntrypoints("rei_plugins_v0", REIPlugin.class)) { try { registerPlugin(reiPlugin); } catch (Exception e) { @@ -484,7 +483,7 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { } if (FabricLoader.getInstance().isModLoaded("libblockattributes-fluids")) { try { - registerPlugin((REIPlugin) Class.forName("me.shedaniel.rei.compat.LBASupportPlugin").getConstructor().newInstance()); + registerPlugin((REIPluginEntry) Class.forName("me.shedaniel.rei.compat.LBASupportPlugin").getConstructor().newInstance()); } catch (Throwable throwable) { throwable.printStackTrace(); } @@ -499,7 +498,7 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { private boolean shouldReturn(Class<?> screen) { try { - for (OverlayDecider decider : DisplayBoundsRegistry.getInstance().getAllOverlayDeciders()) { + for (OverlayDecider decider : ScreenRegistry.getInstance().getAllOverlayDeciders()) { if (!decider.isHandingScreen(screen)) continue; InteractionResult result = decider.shouldScreenBeOverlaid(screen); diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsInitializer.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsInitializer.java new file mode 100644 index 000000000..84c9c3c29 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsInitializer.java @@ -0,0 +1,123 @@ +/* + * 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; + +import com.google.common.collect.ImmutableSet; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.SemanticVersion; +import net.fabricmc.loader.api.VersionParsingException; + +import java.lang.reflect.InvocationTargetException; + +public class RoughlyEnoughItemsInitializer implements ModInitializer, ClientModInitializer { + @Override + public void onInitialize() { + checkRequiredFabricModules(); + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + checkClothConfig(); + checkModMenu(); + } + + if (RoughlyEnoughItemsState.getErrors().isEmpty()) { + initializeEntryPoint("me.shedaniel.rei.RoughlyEnoughItemsNetwork"); + } + } + + @Override + public void onInitializeClient() { + if (RoughlyEnoughItemsState.getErrors().isEmpty()) { + initializeEntryPoint("me.shedaniel.rei.RoughlyEnoughItemsCore"); + initializeEntryPoint("me.shedaniel.rei.impl.ClientHelperImpl"); + initializeEntryPoint("me.shedaniel.rei.impl.ScreenHelper"); + } + + initializeEntryPoint("me.shedaniel.rei.impl.ErrorDisplayer"); + } + + public void initializeEntryPoint(String className) { + try { + Object instance = Class.forName(className).getConstructor().newInstance(); + if (instance instanceof ModInitializer) { + ((ModInitializer) instance).onInitialize(); + } else if (instance instanceof ClientModInitializer) { + ((ClientModInitializer) instance).onInitializeClient(); + } + } catch (InstantiationException | InvocationTargetException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public static void checkRequiredFabricModules() { + ImmutableSet<String> requiredModules = FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT ? + ImmutableSet.<String>builder() + .add("fabric-api-base") + .add("fabric-resource-loader-v0") + .add("fabric-networking-v0") + .add("fabric-lifecycle-events-v1") + .add("fabric-rendering-fluids-v1") + .build() : + ImmutableSet.<String>builder() + .add("fabric-api-base") + .add("fabric-resource-loader-v0") + .add("fabric-networking-v0") + .add("fabric-lifecycle-events-v1") + .build(); + for (String module : requiredModules) { + boolean moduleLoaded = FabricLoader.getInstance().isModLoaded(module); + if (!moduleLoaded) { + RoughlyEnoughItemsState.error("Fabric API is not installed!", "https://www.curseforge.com/minecraft/mc-mods/fabric-api/files/all"); + break; + } + } + } + + public static void checkClothConfig() { + try { + if (!FabricLoader.getInstance().isModLoaded("cloth-config2")) { + RoughlyEnoughItemsState.error("Cloth Config is not installed!", "https://www.curseforge.com/minecraft/mc-mods/cloth-config/files/all"); + } else if (SemanticVersion.parse(FabricLoader.getInstance().getModContainer("cloth-config2").get().getMetadata().getVersion().getFriendlyString()).compareTo(SemanticVersion.parse("4.10.9")) < 0) { + RoughlyEnoughItemsState.error("Your Cloth Config version is too old!", "https://www.curseforge.com/minecraft/mc-mods/cloth-config/files/all"); + } + } catch (VersionParsingException e) { + RoughlyEnoughItemsState.error("Failed to parse Cloth Config version: " + e.getMessage()); + e.printStackTrace(); + } + } + + public static void checkModMenu() { + try { + if (FabricLoader.getInstance().isModLoaded("modmenu")) { + if (SemanticVersion.parse(FabricLoader.getInstance().getModContainer("modmenu").get().getMetadata().getVersion().getFriendlyString()).compareTo(SemanticVersion.parse("1.16.7")) < 0) { + RoughlyEnoughItemsState.error("Your Mod Menu version is too old!", "https://www.curseforge.com/minecraft/mc-mods/modmenu/files/all"); + } + } + } catch (VersionParsingException e) { + RoughlyEnoughItemsState.error("Failed to parse Mod Menu version: " + e.getMessage()); + e.printStackTrace(); + } + } +}
\ No newline at end of file diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java index 808116f6a..e1827b6a8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java @@ -25,7 +25,6 @@ package me.shedaniel.rei; import com.google.common.collect.Lists; import io.netty.buffer.Unpooled; -import me.shedaniel.math.api.Executor; import me.shedaniel.rei.api.server.InputSlotCrafter; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; @@ -55,89 +54,85 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer { @Override public void onInitialize() { - RoughlyEnoughItemsState.checkRequiredFabricModules(); - Executor.run(() -> () -> { - FabricLoader.getInstance().getEntrypoints("rei_containers", Runnable.class).forEach(Runnable::run); - ServerPlayNetworking.registerGlobalReceiver(DELETE_ITEMS_PACKET, (server, player, handler, buf, responseSender) -> { - if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { - player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); - return; - } - if (!player.getInventory().getCarried().isEmpty()) { - player.getInventory().setCarried(ItemStack.EMPTY); - player.broadcastCarriedItem(); - } - }); - ServerPlayNetworking.registerGlobalReceiver(CREATE_ITEMS_PACKET, (server, player, handler, buf, responseSender) -> { - if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { - player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); - return; - } - ItemStack stack = buf.readItem(); - if (player.getInventory().add(stack.copy())) { - responseSender.sendPacket(RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(stack.copy()).writeUtf(player.getScoreboardName(), 32767)); - } else - player.displayClientMessage(new TranslatableComponent("text.rei.failed_cheat_items"), false); - }); - ServerPlayNetworking.registerGlobalReceiver(CREATE_ITEMS_GRAB_PACKET, (server, player, handler, buf, responseSender) -> { - if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { - player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); - return; - } - - Inventory inventory = player.getInventory(); - ItemStack itemStack = buf.readItem(); - ItemStack stack = itemStack.copy(); - if (!inventory.getCarried().isEmpty() && ItemStack.isSameIgnoreDurability(inventory.getCarried(), stack) && ItemStack.tagMatches(inventory.getCarried(), stack)) { - stack.setCount(Mth.clamp(stack.getCount() + inventory.getCarried().getCount(), 1, stack.getMaxStackSize())); - } else if (!inventory.getCarried().isEmpty()) { - return; - } - inventory.setCarried(stack.copy()); + FabricLoader.getInstance().getEntrypoints("rei_containers", Runnable.class).forEach(Runnable::run); + ServerPlayNetworking.registerGlobalReceiver(DELETE_ITEMS_PACKET, (server, player, handler, buf, responseSender) -> { + if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { + player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); + return; + } + if (!player.getInventory().getCarried().isEmpty()) { + player.getInventory().setCarried(ItemStack.EMPTY); player.broadcastCarriedItem(); - responseSender.sendPacket(RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(itemStack.copy()).writeUtf(player.getScoreboardName(), 32767)); - }); - ServerPlayNetworking.registerGlobalReceiver(MOVE_ITEMS_PACKET, (server, player, handler, packetByteBuf, responseSender) -> { - ResourceLocation category = packetByteBuf.readResourceLocation(); - AbstractContainerMenu container = player.containerMenu; - InventoryMenu playerContainer = player.inventoryMenu; - try { - boolean shift = packetByteBuf.readBoolean(); - NonNullList<List<ItemStack>> input = NonNullList.create(); - int mapSize = packetByteBuf.readInt(); - for (int i = 0; i < mapSize; i++) { - List<ItemStack> list = Lists.newArrayList(); - int count = packetByteBuf.readInt(); - for (int j = 0; j < count; j++) { - list.add(packetByteBuf.readItem()); - } - input.add(list); + } + }); + ServerPlayNetworking.registerGlobalReceiver(CREATE_ITEMS_PACKET, (server, player, handler, buf, responseSender) -> { + if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { + player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); + return; + } + ItemStack stack = buf.readItem(); + if (player.getInventory().add(stack.copy())) { + responseSender.sendPacket(RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(stack.copy()).writeUtf(player.getScoreboardName(), 32767)); + } else + player.displayClientMessage(new TranslatableComponent("text.rei.failed_cheat_items"), false); + }); + ServerPlayNetworking.registerGlobalReceiver(CREATE_ITEMS_GRAB_PACKET, (server, player, handler, buf, responseSender) -> { + if (player.getServer().getProfilePermissions(player.getGameProfile()) < player.getServer().getOperatorUserPermissionLevel()) { + player.displayClientMessage(new TranslatableComponent("text.rei.no_permission_cheat").withStyle(ChatFormatting.RED), false); + return; + } + + Inventory inventory = player.getInventory(); + ItemStack itemStack = buf.readItem(); + ItemStack stack = itemStack.copy(); + if (!inventory.getCarried().isEmpty() && ItemStack.isSameIgnoreDurability(inventory.getCarried(), stack) && ItemStack.tagMatches(inventory.getCarried(), stack)) { + stack.setCount(Mth.clamp(stack.getCount() + inventory.getCarried().getCount(), 1, stack.getMaxStackSize())); + } else if (!inventory.getCarried().isEmpty()) { + return; + } + inventory.setCarried(stack.copy()); + player.broadcastCarriedItem(); + responseSender.sendPacket(RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new FriendlyByteBuf(Unpooled.buffer()).writeItem(itemStack.copy()).writeUtf(player.getScoreboardName(), 32767)); + }); + ServerPlayNetworking.registerGlobalReceiver(MOVE_ITEMS_PACKET, (server, player, handler, packetByteBuf, responseSender) -> { + ResourceLocation category = packetByteBuf.readResourceLocation(); + AbstractContainerMenu container = player.containerMenu; + InventoryMenu playerContainer = player.inventoryMenu; + try { + boolean shift = packetByteBuf.readBoolean(); + NonNullList<List<ItemStack>> input = NonNullList.create(); + int mapSize = packetByteBuf.readInt(); + for (int i = 0; i < mapSize; i++) { + List<ItemStack> list = Lists.newArrayList(); + int count = packetByteBuf.readInt(); + for (int j = 0; j < count; j++) { + list.add(packetByteBuf.readItem()); } - try { - InputSlotCrafter.start(category, container, player, input, shift); - } catch (InputSlotCrafter.NotEnoughMaterialsException e) { - if (!(container instanceof RecipeBookMenu)) - return; - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); - buf.writeInt(input.size()); - for (List<ItemStack> stacks : input) { - buf.writeInt(stacks.size()); - for (ItemStack stack : stacks) { - buf.writeItem(stack); - } + input.add(list); + } + try { + InputSlotCrafter.start(category, container, player, input, shift); + } catch (InputSlotCrafter.NotEnoughMaterialsException e) { + if (!(container instanceof RecipeBookMenu)) + return; + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeInt(input.size()); + for (List<ItemStack> stacks : input) { + buf.writeInt(stacks.size()); + for (ItemStack stack : stacks) { + buf.writeItem(stack); } - responseSender.sendPacket(NOT_ENOUGH_ITEMS_PACKET, buf); - } catch (IllegalStateException e) { - player.sendMessage(new TranslatableComponent(e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); - } catch (Exception e) { - player.sendMessage(new TranslatableComponent("error.rei.internal.error", e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); - e.printStackTrace(); } + responseSender.sendPacket(NOT_ENOUGH_ITEMS_PACKET, buf); + } catch (IllegalStateException e) { + player.sendMessage(new TranslatableComponent(e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); } catch (Exception e) { + player.sendMessage(new TranslatableComponent("error.rei.internal.error", e.getMessage()).withStyle(ChatFormatting.RED), Util.NIL_UUID); e.printStackTrace(); } - }); + } catch (Exception e) { + e.printStackTrace(); + } }); } - } diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsState.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsState.java index 9378fafaf..cd5b8c1e2 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsState.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsState.java @@ -57,30 +57,6 @@ public class RoughlyEnoughItemsState { } } - public static void checkRequiredFabricModules() { - ImmutableSet<String> requiredModules = FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT ? - ImmutableSet.<String>builder() - .add("fabric-api-base") - .add("fabric-resource-loader-v0") - .add("fabric-networking-api-v1") - .add("fabric-lifecycle-events-v1") - .add("fabric-rendering-fluids-v1") - .build() : - ImmutableSet.<String>bu |
