diff --git a/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java b/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java index 0989d6a..adf5573 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java @@ -2,7 +2,6 @@ package io.gitlab.jfronny.respackopts; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import io.gitlab.jfronny.respackopts.filters.DirFilterEventImpl; import io.gitlab.jfronny.respackopts.filters.FileFilterEventImpl; @@ -36,7 +35,6 @@ import net.fabricmc.loader.impl.gui.FabricGuiEntry; import net.minecraft.client.MinecraftClient; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.Identifier; -import net.minecraft.util.JsonHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -104,14 +102,14 @@ public class Respackopts implements ClientModInitializer { } if (CONFIG.debugLogs) SAVE_ACTIONS.add(() -> LOGGER.info("Save")); - SAVE_ACTIONS.add(() -> MetaCache.forEach((dataLocation, branch) -> STAR_SCRIPT.set(sanitizeString(MetaCache.getId(dataLocation)), branch::buildStarScript))); + SAVE_ACTIONS.add(() -> MetaCache.forEach((key, state) -> STAR_SCRIPT.set(sanitizeString(state.packId()), state.configBranch()::buildStarScript))); SAVE_ACTIONS.add(() -> { if (CONFIG.debugLogs) LOGGER.info("Generating shader code"); StringBuilder sb = new StringBuilder(); sb.append("#ifndef respackopts_loaded"); sb.append("\n#define respackopts_loaded"); - MetaCache.forEach((dataLocation, branch) -> branch.buildShader(sb, sanitizeString(MetaCache.getId(dataLocation)))); + MetaCache.forEach((key, state) -> state.configBranch().buildShader(sb, sanitizeString(state.packId()))); sb.append("\n#endif"); shaderImportSource = sb.toString(); }); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEventImpl.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEventImpl.java index 5d61b3b..bb26080 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEventImpl.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/DirFilterEventImpl.java @@ -22,7 +22,7 @@ public class DirFilterEventImpl { return previous.get(); String path = new ResourcePath(type, id).getName(); DirRpo rpo = findDirRpo(pack, path); - if (rpo != null && dirHidden(rpo, MetaCache.getId(MetaCache.getDataLocation(pack)), path)) { + if (rpo != null && dirHidden(rpo, MetaCache.getId(MetaCache.getKeyByPack(pack)), path)) { path = findReplacementDir(path, rpo); if (path == null) throw new FileNotFoundException(); ResourcePath rp = new ResourcePath(path); @@ -42,7 +42,7 @@ public class DirFilterEventImpl { String path = type.getDirectory() + "/" + identifier.getNamespace() + "/" + identifier.getPath(); DirRpo rpo = findDirRpo(pack, path); if (rpo != null) { - if (dirHidden(rpo, MetaCache.getId(MetaCache.getDataLocation(pack)), path)) { + if (dirHidden(rpo, MetaCache.getId(MetaCache.getKeyByPack(pack)), path)) { path = findReplacementDir(path, rpo); if (path == null) nextRes.remove(identifier); @@ -70,7 +70,7 @@ public class DirFilterEventImpl { return previous.get(); String path = new ResourcePath(type, id).getName(); DirRpo rpo = findDirRpo(pack, path); - if (rpo != null && dirHidden(rpo, MetaCache.getId(MetaCache.getDataLocation(pack)), path)) { + if (rpo != null && dirHidden(rpo, MetaCache.getId(MetaCache.getKeyByPack(pack)), path)) { path = findReplacementDir(path, rpo); if (path == null) return false; @@ -98,7 +98,7 @@ public class DirFilterEventImpl { } private static DirRpo findDirRpo(ResourcePack pack, String name) { - Map drpReg = MetaCache.DIR_RPOS.get(MetaCache.getDataLocation(pack)); + Map drpReg = MetaCache.getState(MetaCache.getKeyByPack(pack)).cachedDirRPOs(); int li = name.lastIndexOf('/'); if (li <= 0) return null; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java index e2ff558..a65db07 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileExclusionProvider.java @@ -11,7 +11,7 @@ public class FileExclusionProvider { if (rpo.conditions == null) return false; try { - return !rpo.conditions.evaluate(MetaCache.getId(MetaCache.getDataLocation(pack))); + return !rpo.conditions.evaluate(MetaCache.getId(MetaCache.getKeyByPack(pack))); } catch (RpoFormatException e) { Respackopts.LOGGER.error("Could not evaluate condition " + file, e); return false; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java index 2a51225..0f348a6 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/util/FileRpoSearchProvider.java @@ -2,6 +2,7 @@ package io.gitlab.jfronny.respackopts.filters.util; import io.gitlab.jfronny.libjf.ResourcePath; import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.respackopts.model.DirRpo; import io.gitlab.jfronny.respackopts.model.FileRpo; import io.gitlab.jfronny.respackopts.util.MetaCache; import net.minecraft.resource.ResourceNotFoundException; @@ -21,7 +22,7 @@ public class FileRpoSearchProvider { public static T modifyWithRpo(String fileName, ResourcePack pack, ModifiedGenerator getModified, T defaultValue) { if (FileRpoSearchProvider.isRpo(fileName)) return defaultValue; - Map frpReg = MetaCache.FILE_RPOS.get(MetaCache.getDataLocation(pack)); + Map frpReg = MetaCache.getState(MetaCache.getKeyByPack(pack)).cachedFileRPOs(); String rpPathName = fileName + Respackopts.FILE_EXTENSION; if (frpReg.containsKey(rpPathName)) return getModified.getModified(frpReg.get(rpPathName)); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java b/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java index ba1af59..dbeddd6 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java @@ -55,10 +55,9 @@ public class ModMenuCompat implements ModMenuApi { .build() ); //Pack config screens - MetaCache.forEach((dataLocation, conf) -> { - String id = MetaCache.getId(dataLocation); - ConfigCategory config = builder.getOrCreateCategory(new TranslatableText((MetaCache.getMeta(dataLocation).version >= 5 ? "rpo." : "respackopts.title.") + id)); - Respackopts.GUI_FACTORY.buildCategory(conf, id, config::addEntry, agg, entryBuilder, ""); + MetaCache.forEach((key, state) -> { + ConfigCategory config = builder.getOrCreateCategory(new TranslatableText((state.metadata().version >= 5 ? "rpo." : "respackopts.title.") + state.packId())); + Respackopts.GUI_FACTORY.buildCategory(state.configBranch(), state.packId(), config::addEntry, agg, entryBuilder, ""); }); return builder.build(); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java index 0e6bb91..dd6a1f3 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java @@ -1,6 +1,7 @@ package io.gitlab.jfronny.respackopts.mixin; import com.mojang.blaze3d.systems.RenderSystem; +import io.gitlab.jfronny.respackopts.model.cache.CacheKey; import io.gitlab.jfronny.respackopts.util.MetaCache; import io.gitlab.jfronny.respackopts.Respackopts; import net.minecraft.client.MinecraftClient; @@ -30,7 +31,7 @@ public abstract class ResourcePackEntryMixin { @Inject(at = @At("TAIL"), method = "render(Lnet/minecraft/client/util/math/MatrixStack;IIIIIIIZF)V") private void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta, CallbackInfo info) { - if (this.isSelectable() && MetaCache.getDataLocationByDisplayName(pack.getDisplayName().asString()) != null) { + if (this.isSelectable() && MetaCache.getKeyByDisplayName(pack.getDisplayName().asString()) != null) { int d = mouseX - x; d = widget.getRowWidth() - d; int e = mouseY - y; @@ -44,7 +45,7 @@ public abstract class ResourcePackEntryMixin { if (!info.getReturnValue()) { if (this.isSelectable()) { String displayName = pack.getDisplayName().asString(); - Path dataLocation = MetaCache.getDataLocationByDisplayName(displayName); + CacheKey dataLocation = MetaCache.getKeyByDisplayName(displayName); if (dataLocation != null && rpo$selected) { info.setReturnValue(true); MinecraftClient c = MinecraftClient.getInstance(); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java index e02a645..6734b01 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.respackopts.mixin; +import io.gitlab.jfronny.respackopts.model.cache.CacheKey; import io.gitlab.jfronny.respackopts.util.MetaCache; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.model.PackMeta; @@ -63,7 +64,8 @@ public class ResourcePackManagerMixin { } }); for (Path s : toRemove) { - MetaCache.remove(s); + CacheKey k = MetaCache.getKeyByDataLocation(s); + if (k != null) MetaCache.remove(k); } MetaCache.save(); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CacheKey.java b/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CacheKey.java new file mode 100644 index 0000000..3ff21aa --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CacheKey.java @@ -0,0 +1,10 @@ +package io.gitlab.jfronny.respackopts.model.cache; + +import java.nio.file.Path; + +public record CacheKey(String displayName, String packName, Path dataLocation) { + @Override + public String toString() { + return "CacheKey{displayName='" + displayName + "', packName='" + packName + "', dataLocation=" + dataLocation + '}'; + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CachedPackState.java b/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CachedPackState.java new file mode 100644 index 0000000..c36e64a --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/cache/CachedPackState.java @@ -0,0 +1,23 @@ +package io.gitlab.jfronny.respackopts.model.cache; + +import io.gitlab.jfronny.respackopts.model.DirRpo; +import io.gitlab.jfronny.respackopts.model.FileRpo; +import io.gitlab.jfronny.respackopts.model.PackMeta; +import io.gitlab.jfronny.respackopts.model.tree.ConfigBranch; + +import java.util.HashMap; +import java.util.Map; + +public record CachedPackState( + String packId, + String displayName, + String packName, + ConfigBranch configBranch, + PackMeta metadata, + Map cachedFileRPOs, + Map cachedDirRPOs +) { + public CachedPackState(CacheKey key, PackMeta meta, ConfigBranch branch) { + this(meta.id, key.displayName(), key.packName(), branch, meta, new HashMap<>(), new HashMap<>()); + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/condition/RpoBooleanCondition.java b/src/main/java/io/gitlab/jfronny/respackopts/model/condition/RpoBooleanCondition.java index 815946f..e63c816 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/model/condition/RpoBooleanCondition.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/condition/RpoBooleanCondition.java @@ -2,6 +2,8 @@ package io.gitlab.jfronny.respackopts.model.condition; import com.google.gson.JsonParseException; import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.respackopts.model.cache.CacheKey; +import io.gitlab.jfronny.respackopts.model.cache.CachedPackState; import io.gitlab.jfronny.respackopts.util.MetaCache; import io.gitlab.jfronny.respackopts.model.ThrowingBiConsumer; import io.gitlab.jfronny.respackopts.model.tree.ConfigBranch; @@ -46,10 +48,10 @@ public record RpoBooleanCondition(String name) implements Condition { } } AtomicReference result = new AtomicReference<>(null); - MetaCache.forEach((ThrowingBiConsumer) (dataLocation, branch) -> { - if (Objects.equals(MetaCache.getId(dataLocation), sourcePack)) { + MetaCache.forEach((ThrowingBiConsumer) (key, data) -> { + if (Objects.equals(MetaCache.getId(key), sourcePack)) { try { - result.set(branch.getBoolean(finalCondition)); + result.set(data.configBranch().getBoolean(finalCondition)); } catch (RpoFormatException ex) { throw new RpoFormatException("Could not get value", ex); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java b/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java index d1ac837..9ceaeb4 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/util/MetaCache.java @@ -1,10 +1,10 @@ package io.gitlab.jfronny.respackopts.util; import io.gitlab.jfronny.respackopts.Respackopts; -import io.gitlab.jfronny.respackopts.model.DirRpo; -import io.gitlab.jfronny.respackopts.model.FileRpo; import io.gitlab.jfronny.respackopts.model.PackMeta; import io.gitlab.jfronny.respackopts.model.ThrowingBiConsumer; +import io.gitlab.jfronny.respackopts.model.cache.CacheKey; +import io.gitlab.jfronny.respackopts.model.cache.CachedPackState; import io.gitlab.jfronny.respackopts.model.enums.ConfigSyncMode; import io.gitlab.jfronny.respackopts.model.enums.PackCapability; import io.gitlab.jfronny.respackopts.model.tree.ConfigBranch; @@ -20,21 +20,18 @@ import java.util.HashMap; import java.util.Map; public class MetaCache { - private static final Map CONFIG_BRANCH = new HashMap<>(); // pack.rpo -> active config branch - private static final Map PACK_METAS = new HashMap<>(); // pack.rpo -> original pack metadata - private static final Map PACK_IDS = new HashMap<>(); // pack.rpo -> pack id - private static final Map DISPLAY_NAME_LOOKUP = new HashMap<>(); // display name -> pack.rpo - private static final Map PACK_NAME_LOOKUP = new HashMap<>(); // pack name -> pack.rpo - public static final Map> DIR_RPOS = new HashMap<>(); // pack.rpo -> .rpo path -> parsed .rpo - public static final Map> FILE_RPOS = new HashMap<>(); // pack.rpo -> .rpo path -> parsed .rpo - public static void remove(Path packRpo) { - CONFIG_BRANCH.remove(packRpo); - PACK_METAS.remove(packRpo); - PACK_IDS.remove(packRpo); - //DISPLAY_NAME_LOOKUP - //PACK_NAME_LOOKUP - DIR_RPOS.remove(packRpo); - FILE_RPOS.remove(packRpo); + private static final Map PACK_STATES = new HashMap<>(); + private static final Map KEYS_BY_DISPLAY_NAME = new HashMap<>(); + private static final Map KEYS_BY_PACK_NAME = new HashMap<>(); + private static final Map KEYS_BY_DATA_LOCATION = new HashMap<>(); + public static void remove(CacheKey key) { + CacheKey k; + // Remove the key and ones that share a property + // Example: if an old pack has the same data location but a different name, it should still be removed + if ((k = KEYS_BY_DATA_LOCATION.remove(key.dataLocation())) != null) remove(k); + if ((k = KEYS_BY_PACK_NAME.remove(key.packName())) != null) remove(k); + if ((k = KEYS_BY_DISPLAY_NAME.remove(key.displayName())) != null) remove(k); + PACK_STATES.remove(key); } public static void addFromScan(String displayName, String packName, PackMeta meta, Path dataLocation) { @@ -43,17 +40,23 @@ public class MetaCache { } meta.conf.setVersion(meta.version); if (meta.version < 5) meta.capabilities.add(PackCapability.DirFilter); - remove(dataLocation); - if (CONFIG_BRANCH.containsKey(dataLocation)) - CONFIG_BRANCH.get(dataLocation).sync(meta.conf, ConfigSyncMode.RESPACK_LOAD); - else - CONFIG_BRANCH.put(dataLocation, meta.conf.clone()); - DISPLAY_NAME_LOOKUP.put(displayName, dataLocation); - PACK_NAME_LOOKUP.put(packName, dataLocation); - PACK_METAS.put(dataLocation, meta); - DIR_RPOS.put(dataLocation, new HashMap<>()); - FILE_RPOS.put(dataLocation, new HashMap<>()); - PACK_IDS.put(dataLocation, meta.id); + // Reuse the existing branch with a RESPACK_LOAD sync if present + ConfigBranch branch; + if (KEYS_BY_DATA_LOCATION.containsKey(dataLocation)) { + branch = getState(KEYS_BY_DATA_LOCATION.get(dataLocation)).configBranch(); + branch.sync(meta.conf, ConfigSyncMode.RESPACK_LOAD); + } else { + branch = meta.conf.clone(); + } + // Register the key and state in the relevant maps + CacheKey key = new CacheKey(displayName, packName, dataLocation); + CachedPackState state = new CachedPackState(key, meta, branch); + remove(key); + PACK_STATES.put(key, state); + KEYS_BY_DISPLAY_NAME.put(key.displayName(), key); + KEYS_BY_PACK_NAME.put(key.packName(), key); + KEYS_BY_DATA_LOCATION.put(key.dataLocation(), key); + // Move old configs to the new location if (!dataLocation.startsWith(Respackopts.FALLBACK_CONF_DIR)) { Path legacyLocation = Respackopts.FALLBACK_CONF_DIR.resolve(meta.id + ".json"); if (Files.exists(legacyLocation) && !Files.exists(dataLocation)) { @@ -64,15 +67,15 @@ public class MetaCache { } } } - load(dataLocation); + load(key); save(dataLocation, meta.conf); } public static void save() { if (Respackopts.CONFIG.debugLogs) Respackopts.LOGGER.info("Saving configs"); - for (Map.Entry e : CONFIG_BRANCH.entrySet()) { - save(e.getKey(), e.getValue()); + for (Map.Entry e : PACK_STATES.entrySet()) { + save(e.getKey().dataLocation(), e.getValue().configBranch()); } for (Runnable action : Respackopts.SAVE_ACTIONS) { action.run(); @@ -88,59 +91,66 @@ public class MetaCache { } } - public static void load(Path dataLocation) { - if (Files.exists(dataLocation)) { + public static void load(CacheKey key) { + if (Files.exists(key.dataLocation())) { if (Respackopts.CONFIG.debugLogs) - Respackopts.LOGGER.info("Loading configs for: " + dataLocation); - try (Reader reader = Files.newBufferedReader(dataLocation)) { + Respackopts.LOGGER.info("Loading configs for: " + key); + try (Reader reader = Files.newBufferedReader(key.dataLocation())) { ConfigBranch b = Respackopts.GSON.fromJson(reader, ConfigBranch.class); - if (CONFIG_BRANCH.containsKey(dataLocation)) - CONFIG_BRANCH.get(dataLocation).sync(b, ConfigSyncMode.CONF_LOAD); - Respackopts.STAR_SCRIPT.set(Respackopts.sanitizeString(getId(dataLocation)), b::buildStarScript); + if (PACK_STATES.containsKey(key)) + getBranch(key).sync(b, ConfigSyncMode.CONF_LOAD); + Respackopts.STAR_SCRIPT.set(Respackopts.sanitizeString(getId(key)), b::buildStarScript); } catch (IOException e) { - Respackopts.LOGGER.error("Failed to load " + dataLocation, e); + Respackopts.LOGGER.error("Failed to load " + key, e); } } } - public static Path getDataLocation(ResourcePack pack) { - return PACK_NAME_LOOKUP.get(pack.getName()); + public static PackMeta getMeta(CacheKey key) { + return getState(key).metadata(); } - public static PackMeta getMeta(Path dataLocation) { - return PACK_METAS.get(dataLocation); + public static @Nullable CacheKey getKeyByPack(ResourcePack pack) { + return KEYS_BY_PACK_NAME.get(pack.getName()); } - public static @Nullable Path getDataLocationByDisplayName(String displayName) { - if (!DISPLAY_NAME_LOOKUP.containsKey(displayName)) return null; - return DISPLAY_NAME_LOOKUP.get(displayName); + public static @Nullable CacheKey getKeyByDisplayName(String displayName) { + return KEYS_BY_DISPLAY_NAME.get(displayName); } - public static ConfigBranch getBranch(Path dataLocation) { - return CONFIG_BRANCH.get(dataLocation); + public static @Nullable CacheKey getKeyByDataLocation(Path dataLocation) { + return KEYS_BY_DATA_LOCATION.get(dataLocation); } - public static String getId(Path dataLocation) { - return PACK_IDS.get(dataLocation); + public static ConfigBranch getBranch(CacheKey key) { + return getState(key).configBranch(); + } + + public static String getId(CacheKey key) { + return getState(key).packId(); + } + + public static CachedPackState getState(CacheKey key) { + return PACK_STATES.get(key); } public static boolean hasCapability(ResourcePack pack, PackCapability capability) { - Path dataLocation = getDataLocation(pack); - if (dataLocation == null) return false; - if (!PACK_METAS.containsKey(dataLocation)) { + CacheKey key = getKeyByPack(pack); + if (key == null) return false; + if (!PACK_STATES.containsKey(key)) { StringBuilder sb = new StringBuilder("Could not get pack with \""); - sb.append(dataLocation); + sb.append(key); sb.append("\" (available: "); - for (Path path : PACK_METAS.keySet()) { + for (CacheKey path : PACK_STATES.keySet()) { sb.append(path).append(", "); } throw new NullPointerException(sb.substring(0, sb.length() - 2) + ')'); } - return PACK_METAS.get(dataLocation).capabilities.contains(capability); + return getMeta(key).capabilities.contains(capability); } - public static void forEach(ThrowingBiConsumer idAndBranchConsumer) throws TEx { - for (Map.Entry entry : CONFIG_BRANCH.entrySet()) { + public static void forEach(ThrowingBiConsumer idAndBranchConsumer) throws TEx { + for (Map.Entry entry : PACK_STATES.entrySet()) { idAndBranchConsumer.accept(entry.getKey(), entry.getValue()); } }