diff --git a/src/main/java/com/daniking/backtools/BackToolFeatureRenderer.java b/src/main/java/com/daniking/backtools/BackToolFeatureRenderer.java index 0b916ac..f4af875 100644 --- a/src/main/java/com/daniking/backtools/BackToolFeatureRenderer.java +++ b/src/main/java/com/daniking/backtools/BackToolFeatureRenderer.java @@ -42,7 +42,8 @@ public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsume matrixStack.push(); this.getContextModel().body.rotate(matrixStack); boolean isHelicopterMode = ConfigHandler.isHelicopterModeOn() && (playerRenderState.isSwimming || playerRenderState.isGliding); - this.renderItem(!playerRenderState.equippedChestStack.isEmpty() ? 1.0F : playerRenderState.jacketVisible ? 0.5F : 0F, matrixStack, vertexConsumerProvider, light, isHelicopterMode ? playerRenderState.age : 0); + this.renderItem(!playerRenderState.equippedChestStack.isEmpty() ? 1.0F : playerRenderState.jacketVisible ? 0.5F : 0F, + matrixStack, vertexConsumerProvider, light, isHelicopterMode ? playerRenderState.age : 0); matrixStack.pop(); } } @@ -55,8 +56,8 @@ private void renderItem(float offset, MatrixStack matrices, VertexConsumerProvid if (this.mainArm == Arm.RIGHT) { matrices.scale(-1F, 1F, -1F); } - boolean bl = this.mainStack.getItem() instanceof ShieldItem; - if (bl) { + + if (this.mainStack.getItem() instanceof ShieldItem) { float scale = 1.5F; matrices.scale(scale, scale, scale); if (this.mainArm == Arm.LEFT) { @@ -67,11 +68,11 @@ private void renderItem(float offset, MatrixStack matrices, VertexConsumerProvid matrices.translate(-1F / 16F, 0.25F / 16F, 1.0F / 16F); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(25F)); } - } - if (!bl) { + } else { final float i = ConfigHandler.getToolOrientation(this.mainStack.getItem()); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(i)); } + if (ConfigHandler.isBeltTool(this.mainStack.getItem())) { float swordScale = 0.8F; matrices.scale(swordScale, swordScale, swordScale); @@ -84,6 +85,7 @@ private void renderItem(float offset, MatrixStack matrices, VertexConsumerProvid matrices.translate(0.19F, 0.6F, 0.33F); } } + if (age > 0) { matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(age * 40F)); } diff --git a/src/main/java/com/daniking/backtools/BackToolsConfig.java b/src/main/java/com/daniking/backtools/BackToolsConfig.java index 5312cc3..5603b64 100644 --- a/src/main/java/com/daniking/backtools/BackToolsConfig.java +++ b/src/main/java/com/daniking/backtools/BackToolsConfig.java @@ -15,20 +15,29 @@ public class BackToolsConfig implements ConfigData { @Comment(value = "\nThese options affect only the client that loads the mod.\nIt is not possible to override the environment of the mod.") public final String environment = EnvType.CLIENT.name(); - @Comment(value = "What items should render on your belt.") + @Comment(value = "What items should render on your belt by their resource name. Eg: minecraft:diamond_hoe") public List beltTools = new ArrayList<>(); @Comment(value = "Enabled tools, by their resource name. Eg: minecraft:diamond_hoe. Putting any entry in here converts BackTools to a whitelist-only mod. Disabled Tools will be ignored.") public List enabledTools = new ArrayList<>(); @Comment(value = "Disabled tools, by their resource name. Eg: minecraft:diamond_hoe") public List disabledTools = new ArrayList<>(); - @Comment(value = "Tool orientation, by class file and degrees. Separate with \":\" . See defaults for examples.") + @Comment(value = + """ + Tool orientation, by class file and degrees. + Entries starting with "#" are tags (https://minecraft.wiki/w/Tag) + Leading namespace (e.g. minecraft:) is optional. + Separate with ":" for rotation. + Later occurrences of the same item override the previous once (Like in hoes override their config values set in mining). + Item types not listed here will default to 0. + "See defaults for examples.""") public List toolOrientation = Arrays.asList( - "net.minecraft.item.MiningToolItem" + ":0", - "net.minecraft.item.HoeItem" + ":0", - "net.minecraft.item.FishingRodItem" + ":0", - "net.minecraft.item.TridentItem" + ":0", - "net.minecraft.item.MaceItem" + ":-22.5", - "net.minecraft.item.RangedWeaponItem" + ":90"); + "#minecraft:enchantable/mining" + ":0", + "#minecraft:hoes" + ":0", + "#minecraft:enchantable/fishing" + ":0", + "#minecraft:enchantable/trident" + ":0", + "mace" + ":-22.5", + "bow" + ":90", + "crossbow" + ":90"); @Comment(value = "Get in swimming position and your tools go \"Weeee\"") public boolean helicopterMode = false; @Comment(value = "If true, tools render with capes") diff --git a/src/main/java/com/daniking/backtools/ClientSetup.java b/src/main/java/com/daniking/backtools/ClientSetup.java index 87c5523..ad37191 100644 --- a/src/main/java/com/daniking/backtools/ClientSetup.java +++ b/src/main/java/com/daniking/backtools/ClientSetup.java @@ -5,6 +5,7 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents; import java.util.Map; import java.util.WeakHashMap; @@ -18,6 +19,8 @@ public class ClientSetup implements ClientModInitializer { public void onInitializeClient() { AutoConfig.register(BackToolsConfig.class, JanksonConfigSerializer::new); config = AutoConfig.getConfigHolder(BackToolsConfig.class).getConfig(); - ConfigHandler.init(); + + // since we depend on item tags, our config can't load until the tags are loaded first. (creating / joining worlds) + CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> ConfigHandler.init()); } } diff --git a/src/main/java/com/daniking/backtools/ConfigHandler.java b/src/main/java/com/daniking/backtools/ConfigHandler.java index 9a48ba4..eb69b17 100644 --- a/src/main/java/com/daniking/backtools/ConfigHandler.java +++ b/src/main/java/com/daniking/backtools/ConfigHandler.java @@ -2,38 +2,35 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.MappingResolver; import net.minecraft.item.*; import net.minecraft.registry.Registries; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryEntryList; +import net.minecraft.registry.tag.TagKey; import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; @Environment(EnvType.CLIENT) public class ConfigHandler { - private static final HashMap, Float> TOOL_ORIENTATIONS = new HashMap<>(); - private static final HashSet ENABLED_TOOLS = new HashSet<>(); + private static final @NotNull Pattern TOOL_ORIENTATION_PATTERN = Pattern.compile("^(?#)?(?:(?minecraft):)?(?.+?):(?.+?)$"); + private static final Map TOOL_ORIENTATIONS = new LinkedHashMap<>(); + private static final Set ENABLED_TOOLS = new HashSet<>(); private static final Set DISABLED_TOOLS = new HashSet<>(); + private static final HashSet BELT_TOOLS = new HashSet<>(); private static boolean HELICOPTER_MODE = false; private static boolean RENDER_WITH_CAPES = true; - public static final HashSet BELT_TOOLS = new HashSet<>(); public static float getToolOrientation(@NotNull Item item) { - return getToolOrientation(item.getClass()); - } + Float orientation = TOOL_ORIENTATIONS.get(item); - public static float getToolOrientation(@NotNull Class object) { - if (object.equals(Item.class)) { - return 0; - } - if (!TOOL_ORIENTATIONS.containsKey(object)) { - TOOL_ORIENTATIONS.put(object, getToolOrientation(object.getSuperclass())); - } - return TOOL_ORIENTATIONS.get(object); + return Objects.requireNonNullElse(orientation, 0.0F); } public static boolean isItemEnabled(final Item item) { @@ -84,41 +81,51 @@ public static void init() { private static void parseOrientation() { TOOL_ORIENTATIONS.clear(); - MappingResolver resolver = FabricLoader.getInstance().getMappingResolver(); for (String configText : ClientSetup.config.toolOrientation) { - final String[] split = new String[2]; - final int i = configText.indexOf(':'); - if (i == -1) { - BackTools.LOGGER.error("[CONFIG_FILE]: Tool orientation class file and degrees must be separated with \":\"!"); - } else { - split[0] = configText.substring(0, i);//chunk of the text, contains the file class. - split[1] = configText.substring(i + 1);//orientation - } + Matcher matcher = TOOL_ORIENTATION_PATTERN.matcher(configText); - Class path = null; - for (String namespace : resolver.getNamespaces()) { + if (matcher.matches()) { + float orientation; try { - path = Class.forName(resolver.unmapClassName(namespace, split[0])); - - // if no error was thrown, we were successful! - break; - } catch (ClassNotFoundException ignored) { + orientation = Float.parseFloat(matcher.group("orientation")); + } catch (NumberFormatException exception) { + BackTools.LOGGER.error("[CONFIG_FILE]: Could not load config option, because string \"{}\" was not an integer!", matcher.group("orientation")); + continue; } - } - if (path != null) { - try { - if (Item.class.isAssignableFrom(path)) { - TOOL_ORIENTATIONS.put(path, Float.parseFloat(split[1])); + final @Nullable String nameSpace = matcher.group("namespace"); + if (matcher.group("isTag") == null) { // not a tag + final @NotNull String itemID = matcher.group("itemOrTag"); // item id can't be null or the pattern didn't match + + final @Nullable Identifier identifier = Identifier.of(Objects.requireNonNullElse(nameSpace, Identifier.DEFAULT_NAMESPACE), itemID); + final @NotNull Optional> optionalRegistryEntry = Registries.ITEM.getOptional(RegistryKey.of( + Registries.ITEM.getKey(), identifier + )); + + if (optionalRegistryEntry.isPresent()) { + TOOL_ORIENTATIONS.put(optionalRegistryEntry.get().value(), orientation); + } else { + BackTools.LOGGER.error("[CONFIG_FILE]: Could not find any item with identifier of {}", identifier); + } + } else { // is a tag + final @NotNull String tagID = matcher.group("itemOrTag"); // tag id can't be null or the pattern didn't match + + final @Nullable Identifier identifier = Identifier.of(Objects.requireNonNullElse(nameSpace, Identifier.DEFAULT_NAMESPACE), tagID); + TagKey tag = TagKey.of(RegistryKeys.ITEM, identifier); + + Optional> optionalRegistryEntries = Registries.ITEM.getOptional(tag); + + if (optionalRegistryEntries.isPresent()) { + for (RegistryEntry registryEntry : optionalRegistryEntries.get()){ + TOOL_ORIENTATIONS.put(registryEntry.value(), orientation); + } } else { - BackTools.LOGGER.error("[CONFIG_FILE]: Invalid Tool class file: {}", split[0]); + BackTools.LOGGER.error("[CONFIG_FILE]: Could not find any item tag with identifier of {}", identifier); } - } catch (NumberFormatException e) { - BackTools.LOGGER.error("[CONFIG_FILE]: Could not parse text: {}", configText); } } else { - BackTools.LOGGER.error("[CONFIG_FILE]: Could not find class to add orientation: {}", split[0]); + BackTools.LOGGER.error("[CONFIG_FILE]: Could not read tool configuration \"{}\"!", configText); } } } @@ -126,5 +133,6 @@ private static void parseOrientation() { public static boolean isHelicopterModeOn() { return HELICOPTER_MODE; } + public static boolean isRenderWithCapesTrue() { return RENDER_WITH_CAPES; } } diff --git a/src/main/java/com/daniking/backtools/HeldItemContext.java b/src/main/java/com/daniking/backtools/HeldItemContext.java index 9183f4f..42640f0 100644 --- a/src/main/java/com/daniking/backtools/HeldItemContext.java +++ b/src/main/java/com/daniking/backtools/HeldItemContext.java @@ -11,9 +11,7 @@ public class HeldItemContext { public ItemStack activeMain = ItemStack.EMPTY; public ItemStack activeOff = ItemStack.EMPTY; - public void tick(ItemStack main, ItemStack off) { - if (droppedEntity != null && !droppedEntity.getStack().isEmpty()) { this.reset(droppedEntity.getStack()); droppedEntity = null; @@ -21,15 +19,15 @@ public void tick(ItemStack main, ItemStack off) { } //check to see if we should remove the main hand back tool - if(areStacksEqual(main, previousMain) || areStacksEqual(off, previousMain)) { + if(ItemStack.areItemsAndComponentsEqual(main, previousMain) || ItemStack.areItemsAndComponentsEqual(off, previousMain)) { previousMain = ItemStack.EMPTY; } - if(areStacksEqual(main, previousOff) || areStacksEqual(off, previousOff)) { + if(ItemStack.areItemsAndComponentsEqual(main, previousOff) || ItemStack.areItemsAndComponentsEqual(off, previousOff)) { previousOff = ItemStack.EMPTY; } //set back tool if main tool was an item, and we don't see that item anymore. - if(!activeMain.isEmpty() && !areStacksEqual(main, activeMain) && !areStacksEqual(off, activeMain)) { + if(!activeMain.isEmpty() && !ItemStack.areItemsAndComponentsEqual(main, activeMain) && !ItemStack.areItemsAndComponentsEqual(off, activeMain)) { previousMain = activeMain; activeMain = ItemStack.EMPTY; } @@ -37,45 +35,38 @@ public void tick(ItemStack main, ItemStack off) { // //set back tool if offhand tool was an item, and we don't see that item anymore. // this.updatePreviousStacks(main, off); - if(!activeOff.isEmpty() && !areStacksEqual(main, activeOff) && !areStacksEqual(off, activeOff)) { + if(!activeOff.isEmpty() && !ItemStack.areItemsAndComponentsEqual(main, activeOff) && !ItemStack.areItemsAndComponentsEqual(off, activeOff)) { previousOff = activeOff; activeOff = ItemStack.EMPTY; } if(ConfigHandler.isItemEnabled(main.getItem())) { activeMain = main; - if(areStacksEqual(activeMain, activeOff)) { + if(ItemStack.areItemsAndComponentsEqual(activeMain, activeOff)) { activeOff = ItemStack.EMPTY; } } if(ConfigHandler.isItemEnabled(off.getItem())) { activeOff = off; - if(areStacksEqual(activeOff, activeMain)) { + if(ItemStack.areItemsAndComponentsEqual(activeOff, activeMain)) { activeMain = ItemStack.EMPTY; } } } private void reset(ItemStack entityStack) { - if (areStacksEqual(entityStack, previousMain)) { + if (ItemStack.areItemsAndComponentsEqual(entityStack, previousMain)) { previousMain = ItemStack.EMPTY; } - if (areStacksEqual(entityStack, activeMain)) { + if (ItemStack.areItemsAndComponentsEqual(entityStack, activeMain)) { activeMain = ItemStack.EMPTY; } //Check to see if we should remove the offhand BackTool - if (areStacksEqual(entityStack, previousOff)) { + if (ItemStack.areItemsAndComponentsEqual(entityStack, previousOff)) { previousOff = ItemStack.EMPTY; } - if (areStacksEqual(entityStack, activeOff)) { + if (ItemStack.areItemsAndComponentsEqual(entityStack, activeOff)) { activeOff = ItemStack.EMPTY; } } - - public static boolean areStacksEqual(final ItemStack a, final ItemStack b) { - return !a.isEmpty() && !b.isEmpty() && - (a.getComponents().isEmpty() || !b.getComponents().isEmpty()) && - (!a.getComponents().isEmpty() || b.getComponents().isEmpty()) && - a.getItem() == b.getItem(); - } }