diff --git a/README.md b/README.md index 6a29d568..70dc0475 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,69 @@ Rendering 1700 chests: ![After](https://github.com/FoundationGames/EnhancedBlockEntities/raw/116_indev/img/after.png)
A 155% frame rate increase! -## Resource Packs -You can edit EBE's block entity models using resource packs, since they have been converted to conventional .json block models.
-To view EBE's built-in resources, click on -Here's an example of how you can customize chests with resource packs using EBE.

-![Custom Chest GIF](https://user-images.githubusercontent.com/55095883/112942134-f67fe780-912f-11eb-8b11-cf316544c22b.gif) +## Is your mod incompatible with EBE? +If you are the developer of a mod that makes changes to block entity rendering, your mod will be broken by EBE. Fortunately, EBE provides an API that allows you to force-disable its features, allowing your mod to function instead. +
+**You don't need to add EBE as a dependency in your development environment either!** + +### Add the Entrypoint +`fabric.mod.json`: +```json +{ + "entrypoints": { + "main": [...], + "client": [...], + "ebe_v1": [ + "my.mod.compat.EBECompatibility" + ] + } +} +``` + +### Need to modify config values? Implement `BiConsumer>` +`my.mod.compat.EBECompatibility`: +```java +public class EBECompatibility implements BiConsumer>, ... { + @Override + public void accept(Properties overrideConfigValues, Map overrideReasons) { + overrideConfigValues.setProperty("render_enhanced_chests", "false"); + + overrideReasons.put("render_enhanced_chests", + Text.literal("EBE Enhanced Chests are not compatible with my mod!") + .formatted(Formatting.YELLOW)); + } + + ... +} +``` +The `accept(Properties, Map)` function is called when EBE loads config values. You can override a desired config value by setting the corresponding property of `overrideConfigValues`. This will also gray out the option in the config menu. +
+To explain to users why your mod made that change, you can add a text component to the `overrideReasons` map corresponding to the key of the option you changed. +
+`Text` is `net.minecraft.text.Text` when using Yarn mappings. + +### Need to manually reload EBE? Implement `Consumer` +`my.mod.compat.EBECompatibility`: +```java +public class EBECompatibility implements Consumer, ... { + private static Runnable ebeReloader = () -> {}; + + ... + + @Override + public void accept(Runnable ebeConfigReloader) { + ebeReloader = ebeConfigReloader; + } +} +``` +If your mod needs to modify EBE's config values depending on loaded resources, it may encounter load order problems. This can be somewhat fixed by manually reloading EBE. +
+The `accept(Runnable)` function is called when EBE is first loaded. The `Runnable` executes `EnhancedBlockEntities.load()`. Store this in a field so you can execute it whenever necessary. +```java +void onMyModResourceReload() { + EBECompatibility.someParameter = true; + EBECompatibility.ebeReloader.run(); + // Your config modification handler in EBECompatibility can change + // its behavior based on EBECompatibility.someParameter. +} +``` \ No newline at end of file diff --git a/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java b/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java index c3f67eca..e4ed0190 100644 --- a/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java +++ b/src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java @@ -17,6 +17,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.function.Consumer; + public final class EnhancedBlockEntities implements ClientModInitializer { public static final String ID = "enhancedblockentities"; public static final String NAMESPACE = "ebe"; @@ -25,7 +27,10 @@ public final class EnhancedBlockEntities implements ClientModInitializer { public static final TemplateLoader TEMPLATE_LOADER = new TemplateLoader(); + public static final String API_V1 = "ebe_v1"; + @Override + @SuppressWarnings("unchecked") public void onInitializeClient() { FabricLoader.getInstance().getModContainer(ID).ifPresent(mod -> { var roots = mod.getRootPaths(); @@ -35,6 +40,11 @@ public void onInitializeClient() { } }); + var ebeCompatInitializers = FabricLoader.getInstance().getEntrypointContainers(API_V1, Consumer.class); + for (var init : ebeCompatInitializers) { + init.getEntrypoint().accept((Runnable) EnhancedBlockEntities::load); + } + WorldRenderEvents.END.register(SignRenderManager::endFrame); ClientTickEvents.END_WORLD_TICK.register(WorldUtil.EVENT_LISTENER); diff --git a/src/main/java/foundationgames/enhancedblockentities/config/EBEConfig.java b/src/main/java/foundationgames/enhancedblockentities/config/EBEConfig.java index 4ac26f73..7cfe30b5 100644 --- a/src/main/java/foundationgames/enhancedblockentities/config/EBEConfig.java +++ b/src/main/java/foundationgames/enhancedblockentities/config/EBEConfig.java @@ -3,11 +3,17 @@ import foundationgames.enhancedblockentities.EnhancedBlockEntities; import foundationgames.enhancedblockentities.util.ConvUtil; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; +import java.util.function.BiConsumer; public class EBEConfig { public static final String RENDER_ENHANCED_CHESTS_KEY = "render_enhanced_chests"; @@ -48,6 +54,8 @@ public class EBEConfig { public boolean experimentalSigns = true; public boolean forceResourcePackCompat = false; + public final Map overrides = new HashMap<>(); + public void writeTo(Properties properties) { properties.setProperty(RENDER_ENHANCED_CHESTS_KEY, Boolean.toString(renderEnhancedChests)); properties.setProperty(RENDER_ENHANCED_SIGNS_KEY, Boolean.toString(renderEnhancedSigns)); @@ -143,6 +151,32 @@ public void load() { e.printStackTrace(); return; } + + applyCompatConfigModifiers(properties); + readFrom(properties); } + + @SuppressWarnings("unchecked") + private void applyCompatConfigModifiers(Properties properties) { + this.overrides.clear(); + + var ebeCompatCfgModifiers = FabricLoader.getInstance() + .getEntrypointContainers(EnhancedBlockEntities.API_V1, BiConsumer.class); + for (var modifier : ebeCompatCfgModifiers) { + var mod = modifier.getProvider(); + var overrides = new Properties(); + var reasons = new HashMap(); + modifier.getEntrypoint().accept(overrides, reasons); + + for (var key : overrides.stringPropertyNames()) { + @Nullable Text reason = reasons.get(key); + this.overrides.put(key, new Override(mod, reason)); + } + + properties.putAll(overrides); + } + } + + public record Override(ModContainer modResponsible, @Nullable Text reason) {} } diff --git a/src/main/java/foundationgames/enhancedblockentities/config/gui/option/EBEOption.java b/src/main/java/foundationgames/enhancedblockentities/config/gui/option/EBEOption.java index f2cadca1..7abf8f2b 100644 --- a/src/main/java/foundationgames/enhancedblockentities/config/gui/option/EBEOption.java +++ b/src/main/java/foundationgames/enhancedblockentities/config/gui/option/EBEOption.java @@ -1,24 +1,31 @@ package foundationgames.enhancedblockentities.config.gui.option; import foundationgames.enhancedblockentities.ReloadType; +import foundationgames.enhancedblockentities.config.EBEConfig; import foundationgames.enhancedblockentities.util.GuiUtil; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.resource.language.I18n; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; +import java.util.Properties; public final class EBEOption { private static final Text NEWLINE = Text.of("\n"); private static final String OPTION_VALUE = "options.generic_value"; private static final String DIVIDER = "text.ebe.option_value_division"; + private static final String OVERRIDDEN = "warning.ebe.overridden"; public final String key; public final boolean hasValueComments; public final Text comment; public final ReloadType reloadType; public final TextPalette palette; + public final @Nullable EBEConfig.Override override; private final List values; private final int defaultValue; @@ -27,10 +34,11 @@ public final class EBEOption { private Tooltip tooltip = null; private Text text = null; - public EBEOption(String key, List values, int defaultValue, boolean hasValueComments, TextPalette palette, ReloadType reloadType) { + public EBEOption(String key, List values, ConfigView config, boolean hasValueComments, TextPalette palette, ReloadType reloadType) { this.key = key; this.values = values; - this.defaultValue = MathHelper.clamp(defaultValue, 0, values.size()); + this.defaultValue = MathHelper.clamp(values.indexOf(config.configValues.getProperty(key)), 0, values.size()); + this.override = config.overrides.get(key); this.selected = this.defaultValue; this.hasValueComments = hasValueComments; this.palette = palette; @@ -62,7 +70,16 @@ public Text getText() { public Tooltip getTooltip() { if (tooltip == null) { - if (hasValueComments) tooltip = Tooltip.of(Text.translatable(String.format("option.ebe.%s.valueComment.%s", key, getValue())).append(NEWLINE).append(comment.copyContentOnly())); + if (override != null) { + var text = Text.translatable(OVERRIDDEN, override.modResponsible().getMetadata().getId()) + .formatted(Formatting.RED, Formatting.UNDERLINE); + if (override.reason() != null) { + text.append(NEWLINE).append(override.reason()); + } + + tooltip = Tooltip.of(text); + } + else if (hasValueComments) tooltip = Tooltip.of(Text.translatable(String.format("option.ebe.%s.valueComment.%s", key, getValue())).append(NEWLINE).append(comment.copyContentOnly())); else tooltip = Tooltip.of(comment.copyContentOnly()); } return tooltip; @@ -78,4 +95,6 @@ public void next() { public boolean isDefault() { return selected == defaultValue; } + + public record ConfigView(Properties configValues, Map overrides) {} } diff --git a/src/main/java/foundationgames/enhancedblockentities/config/gui/screen/EBEConfigScreen.java b/src/main/java/foundationgames/enhancedblockentities/config/gui/screen/EBEConfigScreen.java index cab73881..647f02d8 100644 --- a/src/main/java/foundationgames/enhancedblockentities/config/gui/screen/EBEConfigScreen.java +++ b/src/main/java/foundationgames/enhancedblockentities/config/gui/screen/EBEConfigScreen.java @@ -125,71 +125,72 @@ public void addOptions() { Properties config = new Properties(); EnhancedBlockEntities.CONFIG.writeTo(config); + final var configView = new EBEOption.ConfigView(config, EnhancedBlockEntities.CONFIG.overrides); final var textRenderer = this.client.textRenderer; optionsWidget.add(new SectionTextWidget(CHEST_OPTIONS_TITLE, textRenderer)); optionsWidget.add(option( - new EBEOption(EBEConfig.RENDER_ENHANCED_CHESTS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.RENDER_ENHANCED_CHESTS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.RENDER_ENHANCED_CHESTS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(option( - new EBEOption(EBEConfig.CHEST_AO_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.CHEST_AO_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.CHEST_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(option( - new EBEOption(EBEConfig.EXPERIMENTAL_CHESTS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.EXPERIMENTAL_CHESTS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.EXPERIMENTAL_CHESTS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) ), option( - new EBEOption(EBEConfig.CHRISTMAS_CHESTS_KEY, ALLOWED_FORCED_DISABLED, ALLOWED_FORCED_DISABLED.indexOf(config.getProperty(EBEConfig.CHRISTMAS_CHESTS_KEY)), true, TextPalette.rainbow(0.35f), ReloadType.WORLD) + new EBEOption(EBEConfig.CHRISTMAS_CHESTS_KEY, ALLOWED_FORCED_DISABLED, configView, true, TextPalette.rainbow(0.35f), ReloadType.WORLD) )); optionsWidget.add(new SectionTextWidget(SIGN_OPTIONS_TITLE, textRenderer)); optionsWidget.add(option( - new EBEOption(EBEConfig.RENDER_ENHANCED_SIGNS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.RENDER_ENHANCED_SIGNS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.RENDER_ENHANCED_SIGNS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(option( - new EBEOption(EBEConfig.SIGN_TEXT_RENDERING_KEY, SIGN_TEXT_OPTIONS, SIGN_TEXT_OPTIONS.indexOf(config.getProperty(EBEConfig.SIGN_TEXT_RENDERING_KEY)), true, TextPalette.rainbow(0.45f), ReloadType.NONE) + new EBEOption(EBEConfig.SIGN_TEXT_RENDERING_KEY, SIGN_TEXT_OPTIONS, configView, true, TextPalette.rainbow(0.45f), ReloadType.NONE) )); optionsWidget.add(option( - new EBEOption(EBEConfig.EXPERIMENTAL_SIGNS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.EXPERIMENTAL_SIGNS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.EXPERIMENTAL_SIGNS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) ), option( - new EBEOption(EBEConfig.SIGN_AO_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.SIGN_AO_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.SIGN_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(new SectionTextWidget(BELL_OPTIONS_TITLE, textRenderer)); optionsWidget.add(option( - new EBEOption(EBEConfig.RENDER_ENHANCED_BELLS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.RENDER_ENHANCED_BELLS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.RENDER_ENHANCED_BELLS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(option( - new EBEOption(EBEConfig.BELL_AO_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.BELL_AO_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.BELL_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(new SectionTextWidget(BED_OPTIONS_TITLE, textRenderer)); optionsWidget.add(option( - new EBEOption(EBEConfig.RENDER_ENHANCED_BEDS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.RENDER_ENHANCED_BEDS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.RENDER_ENHANCED_BEDS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(option( - new EBEOption(EBEConfig.EXPERIMENTAL_BEDS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.EXPERIMENTAL_BEDS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.EXPERIMENTAL_BEDS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) ), option( - new EBEOption(EBEConfig.BED_AO_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.BED_AO_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.BED_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(new SectionTextWidget(SHULKER_BOX_OPTIONS_TITLE, textRenderer)); optionsWidget.add(option( - new EBEOption(EBEConfig.RENDER_ENHANCED_SHULKER_BOXES_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.RENDER_ENHANCED_SHULKER_BOXES_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.RENDER_ENHANCED_SHULKER_BOXES_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(option( - new EBEOption(EBEConfig.SHULKER_BOX_AO_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.SHULKER_BOX_AO_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.SHULKER_BOX_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(new SectionTextWidget(DECORATED_POT_OPTIONS_TITLE, textRenderer)); optionsWidget.add(option( - new EBEOption(EBEConfig.RENDER_ENHANCED_DECORATED_POTS_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.RENDER_ENHANCED_DECORATED_POTS_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.RENDER_ENHANCED_DECORATED_POTS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(option( - new EBEOption(EBEConfig.DECORATED_POT_AO_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.DECORATED_POT_AO_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.DECORATED_POT_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(new SectionTextWidget(ADVANCED_TITLE, textRenderer)); optionsWidget.add(option( - new EBEOption(EBEConfig.FORCE_RESOURCE_PACK_COMPAT_KEY, BOOLEAN_OPTIONS, BOOLEAN_OPTIONS.indexOf(config.getProperty(EBEConfig.FORCE_RESOURCE_PACK_COMPAT_KEY)), false, TextPalette.ON_OFF, ReloadType.RESOURCES) + new EBEOption(EBEConfig.FORCE_RESOURCE_PACK_COMPAT_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES) )); optionsWidget.add(ButtonWidget.builder(DUMP_LABEL, b -> { try { @@ -203,10 +204,16 @@ public void addOptions() { private ButtonWidget option(EBEOption option) { options.add(option); - return ButtonWidget.builder(option.getText(), b -> { + var button = ButtonWidget.builder(option.getText(), b -> { option.next(); b.setMessage(option.getText()); b.setTooltip(option.getTooltip()); }).tooltip(option.getTooltip()).build(); + + if (option.override != null) { + button.active = false; + } + + return button; } } diff --git a/src/main/java/foundationgames/enhancedblockentities/mixin/BuiltinModelItemRendererMixin.java b/src/main/java/foundationgames/enhancedblockentities/mixin/BuiltinModelItemRendererMixin.java index f23ced24..83439b26 100644 --- a/src/main/java/foundationgames/enhancedblockentities/mixin/BuiltinModelItemRendererMixin.java +++ b/src/main/java/foundationgames/enhancedblockentities/mixin/BuiltinModelItemRendererMixin.java @@ -8,10 +8,10 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.item.BuiltinModelItemRenderer; -import net.minecraft.item.ModelTransformationMode; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; +import net.minecraft.item.ModelTransformationMode; import net.minecraft.state.property.Properties; import net.minecraft.util.math.Direction; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/resources/assets/enhancedblockentities/lang/en_us.json b/src/main/resources/assets/enhancedblockentities/lang/en_us.json index 835bbf05..512c9c99 100644 --- a/src/main/resources/assets/enhancedblockentities/lang/en_us.json +++ b/src/main/resources/assets/enhancedblockentities/lang/en_us.json @@ -59,6 +59,8 @@ "option.ebe.dump": "Dump Example Resources", "option.ebe.dump.comment": "Dumps the mod's default resources to .minecraft/enhanced_bes_dump/ to be used as an example by resource pack makers.", + "warning.ebe.overridden": "Overwritten by '%s'", + "screen.ebe.config": "Block Entity Settings", "text.ebe.apply": "Apply", diff --git a/src/main/resources/assets/minecraft/models/block/decorated_pot_base.json b/src/main/resources/assets/minecraft/models/block/decorated_pot_base.json index acdec35d..3aca25ab 100644 --- a/src/main/resources/assets/minecraft/models/block/decorated_pot_base.json +++ b/src/main/resources/assets/minecraft/models/block/decorated_pot_base.json @@ -10,8 +10,8 @@ "from": [1, 0, 1], "to": [15, 16, 15], "faces": { - "up": {"uv": [0, 6.5, 7, 13.5], "texture": "#0", "cullface": "up"}, - "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0", "cullface": "down"} + "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0", "cullface": "up"}, + "down": {"uv": [0, 6.5, 7, 13.5], "texture": "#0", "cullface": "down"} } }, {