mirror of
https://github.com/AlmostReliable/almostunified.git
synced 2024-11-14 19:25:13 -05:00
[1.20.1] tag inheritance (#57)
This commit is contained in:
parent
1562b0323d
commit
47b50f9bc8
20 changed files with 608 additions and 134 deletions
|
@ -1,19 +1,16 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.api.StoneStrataHandler;
|
||||
import com.almostreliable.unified.config.Config;
|
||||
import com.almostreliable.unified.config.ServerConfigs;
|
||||
import com.almostreliable.unified.config.StartupConfig;
|
||||
import com.almostreliable.unified.config.UnifyConfig;
|
||||
import com.almostreliable.unified.recipe.unifier.RecipeHandlerFactory;
|
||||
import com.almostreliable.unified.utils.ReplacementMap;
|
||||
import com.almostreliable.unified.utils.TagMap;
|
||||
import com.almostreliable.unified.utils.TagOwnerships;
|
||||
import com.almostreliable.unified.utils.TagReloadHandler;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagManager;
|
||||
import net.minecraft.world.item.Item;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
@ -28,7 +25,6 @@ public final class AlmostUnified {
|
|||
public static final Logger LOG = LogManager.getLogger(BuildConfig.MOD_NAME);
|
||||
|
||||
@Nullable private static AlmostUnifiedRuntime RUNTIME;
|
||||
@Nullable private static TagManager TAG_MANAGER;
|
||||
@Nullable private static StartupConfig STARTUP_CONFIG;
|
||||
|
||||
public static boolean isRuntimeLoaded() {
|
||||
|
@ -49,40 +45,52 @@ public final class AlmostUnified {
|
|||
return STARTUP_CONFIG;
|
||||
}
|
||||
|
||||
public static void onTagManagerReload(TagManager tagManager) {
|
||||
TAG_MANAGER = tagManager;
|
||||
}
|
||||
|
||||
public static void onTagLoaderReload(Map<ResourceLocation, Collection<Holder<Item>>> tags) {
|
||||
Preconditions.checkNotNull(TAG_MANAGER, "TagManager was not loaded correctly");
|
||||
RecipeHandlerFactory recipeHandlerFactory = new RecipeHandlerFactory();
|
||||
AlmostUnifiedPlatform.INSTANCE.bindRecipeHandlers(recipeHandlerFactory);
|
||||
|
||||
ServerConfigs serverConfigs = ServerConfigs.load();
|
||||
UnifyConfig unifyConfig = serverConfigs.getUnifyConfig();
|
||||
|
||||
var unifyTags = unifyConfig.bakeTags();
|
||||
|
||||
TagOwnerships tagOwnerships = new TagOwnerships(unifyTags, unifyConfig.getTagOwnerships());
|
||||
TagOwnerships tagOwnerships = new TagOwnerships(
|
||||
unifyConfig.bakeAndValidateTags(tags),
|
||||
unifyConfig.getTagOwnerships()
|
||||
);
|
||||
tagOwnerships.applyOwnerships(tags);
|
||||
|
||||
TagMap globalTagMap = TagMap.create(tags);
|
||||
TagMap filteredTagMap = globalTagMap.filtered(unifyTags::contains, unifyConfig::includeItem);
|
||||
ReplacementData replacementData = loadReplacementData(tags, unifyConfig, tagOwnerships);
|
||||
|
||||
StoneStrataHandler stoneStrataHandler = StoneStrataHandler.create(
|
||||
unifyConfig.getStoneStrata(),
|
||||
AlmostUnifiedPlatform.INSTANCE.getStoneStrataTags(unifyConfig.getStoneStrata()),
|
||||
globalTagMap
|
||||
RUNTIME = new AlmostUnifiedRuntimeImpl(
|
||||
serverConfigs,
|
||||
replacementData.filteredTagMap(),
|
||||
replacementData.replacementMap(),
|
||||
recipeHandlerFactory
|
||||
);
|
||||
|
||||
ReplacementMap repMap = new ReplacementMap(unifyConfig, filteredTagMap, stoneStrataHandler, tagOwnerships);
|
||||
|
||||
RecipeHandlerFactory recipeHandlerFactory = new RecipeHandlerFactory();
|
||||
AlmostUnifiedPlatform.INSTANCE.bindRecipeHandlers(recipeHandlerFactory);
|
||||
|
||||
RUNTIME = new AlmostUnifiedRuntimeImpl(serverConfigs, filteredTagMap, repMap, recipeHandlerFactory);
|
||||
}
|
||||
|
||||
public static void onRecipeManagerReload(Map<ResourceLocation, JsonElement> recipes) {
|
||||
Preconditions.checkNotNull(RUNTIME, "AlmostUnifiedRuntime was not loaded correctly");
|
||||
RUNTIME.run(recipes, getStartupConfig().isServerOnly());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the required data for the replacement logic.
|
||||
* <p>
|
||||
* This method applies tag inheritance and rebuilds the replacement data if the
|
||||
* inheritance mutates the tags.
|
||||
*
|
||||
* @param tags The vanilla tag map provided by the TagManager
|
||||
* @param unifyConfig The mod config to use for unifying
|
||||
* @param tagOwnerships The tag ownerships to apply
|
||||
* @return The loaded data
|
||||
*/
|
||||
private static ReplacementData loadReplacementData(Map<ResourceLocation, Collection<Holder<Item>>> tags, UnifyConfig unifyConfig, TagOwnerships tagOwnerships) {
|
||||
ReplacementData replacementData = ReplacementData.load(tags, unifyConfig, tagOwnerships);
|
||||
var needsRebuild = TagReloadHandler.applyInheritance(unifyConfig, replacementData);
|
||||
if (needsRebuild) {
|
||||
return ReplacementData.load(tags, unifyConfig, tagOwnerships);
|
||||
}
|
||||
|
||||
return replacementData;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime {
|
|||
@Nullable private static AlmostUnifiedFallbackRuntime INSTANCE;
|
||||
|
||||
@Nullable private UnifyConfig unifyConfig;
|
||||
@Nullable private TagMap filteredTagMap;
|
||||
@Nullable private TagMap<Item> filteredTagMap;
|
||||
@Nullable private ReplacementMap replacementMap;
|
||||
|
||||
public static AlmostUnifiedFallbackRuntime getInstance() {
|
||||
|
@ -41,7 +41,7 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime {
|
|||
build();
|
||||
}
|
||||
|
||||
public void build() {
|
||||
private void build() {
|
||||
unifyConfig = Config.load(UnifyConfig.NAME, new UnifyConfig.Serializer());
|
||||
Set<UnifyTag<Item>> unifyTags = unifyConfig.bakeTags();
|
||||
filteredTagMap = TagMap.create(unifyTags).filtered($ -> true, unifyConfig::includeItem);
|
||||
|
@ -52,7 +52,7 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime {
|
|||
|
||||
private static StoneStrataHandler createStoneStrataHandler(UnifyConfig config) {
|
||||
Set<UnifyTag<Item>> stoneStrataTags = AlmostUnifiedPlatform.INSTANCE.getStoneStrataTags(config.getStoneStrata());
|
||||
TagMap stoneStrataTagMap = TagMap.create(stoneStrataTags);
|
||||
TagMap<Item> stoneStrataTagMap = TagMap.create(stoneStrataTags);
|
||||
return StoneStrataHandler.create(config.getStoneStrata(), stoneStrataTags, stoneStrataTagMap);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ public class AlmostUnifiedFallbackRuntime implements AlmostUnifiedRuntime {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<TagMap> getFilteredTagMap() {
|
||||
public Optional<TagMap<Item>> getFilteredTagMap() {
|
||||
return Optional.ofNullable(filteredTagMap);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ import net.minecraft.resources.ResourceLocation;
|
|||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class AlmostUnifiedLookupImpl implements AlmostUnifiedLookup {
|
|||
.getRuntime()
|
||||
.getFilteredTagMap()
|
||||
.map(tagMap -> tagMap
|
||||
.getItemsByTag(asUnifyTag)
|
||||
.getEntriesByTag(asUnifyTag)
|
||||
.stream()
|
||||
.flatMap(rl -> BuiltInRegistries.ITEM.getOptional(rl).stream())
|
||||
.collect(Collectors.toSet()))
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.almostreliable.unified.utils.ReplacementMap;
|
|||
import com.almostreliable.unified.utils.TagMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
@ -13,7 +14,7 @@ public interface AlmostUnifiedRuntime {
|
|||
|
||||
void run(Map<ResourceLocation, JsonElement> recipes, boolean skipClientTracking);
|
||||
|
||||
Optional<TagMap> getFilteredTagMap();
|
||||
Optional<TagMap<Item>> getFilteredTagMap();
|
||||
|
||||
Optional<ReplacementMap> getReplacementMap();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.almostreliable.unified.utils.ReplacementMap;
|
|||
import com.almostreliable.unified.utils.TagMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
@ -20,20 +21,20 @@ public final class AlmostUnifiedRuntimeImpl implements AlmostUnifiedRuntime {
|
|||
private final UnifyConfig unifyConfig;
|
||||
private final DuplicationConfig duplicationConfig;
|
||||
private final DebugConfig debugConfig;
|
||||
private final TagMap filteredTagMap;
|
||||
private final TagMap<Item> tagMap;
|
||||
private final ReplacementMap replacementMap;
|
||||
private final RecipeHandlerFactory recipeHandlerFactory;
|
||||
|
||||
AlmostUnifiedRuntimeImpl(
|
||||
ServerConfigs configs,
|
||||
TagMap tagMap,
|
||||
TagMap<Item> tagMap,
|
||||
ReplacementMap repMap,
|
||||
RecipeHandlerFactory recipeHandlerFactory
|
||||
) {
|
||||
this.unifyConfig = configs.getUnifyConfig();
|
||||
this.duplicationConfig = configs.getDupConfig();
|
||||
this.debugConfig = configs.getDebugConfig();
|
||||
this.filteredTagMap = tagMap;
|
||||
this.tagMap = tagMap;
|
||||
this.replacementMap = repMap;
|
||||
this.recipeHandlerFactory = recipeHandlerFactory;
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ public final class AlmostUnifiedRuntimeImpl implements AlmostUnifiedRuntime {
|
|||
@Override
|
||||
public void run(Map<ResourceLocation, JsonElement> recipes, boolean skipClientTracking) {
|
||||
debugConfig.logRecipes(recipes, "recipes_before_unification.txt");
|
||||
debugConfig.logUnifyTagDump(filteredTagMap);
|
||||
debugConfig.logUnifyTagDump(tagMap);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
RecipeTransformer.Result result = new RecipeTransformer(
|
||||
|
@ -57,8 +58,8 @@ public final class AlmostUnifiedRuntimeImpl implements AlmostUnifiedRuntime {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<TagMap> getFilteredTagMap() {
|
||||
return Optional.of(filteredTagMap);
|
||||
public Optional<TagMap<Item>> getFilteredTagMap() {
|
||||
return Optional.of(tagMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.api.StoneStrataHandler;
|
||||
import com.almostreliable.unified.config.UnifyConfig;
|
||||
import com.almostreliable.unified.utils.ReplacementMap;
|
||||
import com.almostreliable.unified.utils.TagMap;
|
||||
import com.almostreliable.unified.utils.TagOwnerships;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holder class for storing all the data needed for replacements in recipes.
|
||||
*
|
||||
* @param globalTagMap The global tag map, containing all tags.
|
||||
* @param filteredTagMap The filtered tag map, containing only the tags that will be used for replacing. Determined by the unify config.
|
||||
* @param stoneStrataHandler The stone strata handler, used for replacing stone strata.
|
||||
* @param replacementMap The replacement map, used for replacing items.
|
||||
*/
|
||||
public record ReplacementData(TagMap<Item> globalTagMap, TagMap<Item> filteredTagMap,
|
||||
StoneStrataHandler stoneStrataHandler,
|
||||
ReplacementMap replacementMap) {
|
||||
|
||||
public static ReplacementData load(Map<ResourceLocation, Collection<Holder<Item>>> tags, UnifyConfig unifyConfig, TagOwnerships tagOwnerships) {
|
||||
var globalTagMap = TagMap.createFromItemTags(tags);
|
||||
var unifyTags = unifyConfig.bakeAndValidateTags(tags);
|
||||
var filteredTagMap = globalTagMap.filtered(unifyTags::contains, unifyConfig::includeItem);
|
||||
|
||||
var stoneStrataHandler = StoneStrataHandler.create(
|
||||
unifyConfig.getStoneStrata(),
|
||||
AlmostUnifiedPlatform.INSTANCE.getStoneStrataTags(unifyConfig.getStoneStrata()),
|
||||
globalTagMap
|
||||
);
|
||||
|
||||
var replacementMap = new ReplacementMap(unifyConfig, filteredTagMap, stoneStrataHandler, tagOwnerships);
|
||||
|
||||
return new ReplacementData(globalTagMap, filteredTagMap, stoneStrataHandler, replacementMap);
|
||||
}
|
||||
}
|
|
@ -9,18 +9,18 @@ import net.minecraft.world.item.Item;
|
|||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class StoneStrataHandler {
|
||||
public final class StoneStrataHandler {
|
||||
|
||||
private final List<String> stoneStrata;
|
||||
private final Pattern tagMatcher;
|
||||
private final TagMap stoneStrataTagMap;
|
||||
private final TagMap<Item> stoneStrataTagMap;
|
||||
|
||||
// don't clear the caches, so they are available for the runtime and KubeJS binding
|
||||
// the runtime holding this handler is automatically yeeted on reload
|
||||
private final Map<UnifyTag<?>, Boolean> stoneStrataTagCache;
|
||||
private final Map<ResourceLocation, String> stoneStrataCache;
|
||||
|
||||
private StoneStrataHandler(List<String> stoneStrata, Pattern tagMatcher, TagMap stoneStrataTagMap) {
|
||||
private StoneStrataHandler(List<String> stoneStrata, Pattern tagMatcher, TagMap<Item> stoneStrataTagMap) {
|
||||
this.stoneStrata = createSortedStoneStrata(stoneStrata);
|
||||
this.tagMatcher = tagMatcher;
|
||||
this.stoneStrataTagMap = stoneStrataTagMap;
|
||||
|
@ -41,8 +41,8 @@ public class StoneStrataHandler {
|
|||
return stoneStrata.stream().sorted(Comparator.comparingInt(String::length).reversed()).toList();
|
||||
}
|
||||
|
||||
public static StoneStrataHandler create(List<String> stoneStrataIds, Set<UnifyTag<Item>> stoneStrataTags, TagMap tagMap) {
|
||||
TagMap stoneStrataTagMap = tagMap.filtered(stoneStrataTags::contains, item -> true);
|
||||
public static StoneStrataHandler create(List<String> stoneStrataIds, Set<UnifyTag<Item>> stoneStrataTags, TagMap<Item> tagMap) {
|
||||
var stoneStrataTagMap = tagMap.filtered(stoneStrataTags::contains, item -> true);
|
||||
Pattern tagMatcher = Pattern.compile(switch (AlmostUnifiedPlatform.INSTANCE.getPlatform()) {
|
||||
case FORGE -> "forge:ores/.+";
|
||||
case FABRIC -> "(c:ores/.+|c:.+_ores)";
|
||||
|
@ -71,7 +71,7 @@ public class StoneStrataHandler {
|
|||
*/
|
||||
private String computeStoneStrata(ResourceLocation item) {
|
||||
String strata = stoneStrataTagMap
|
||||
.getTagsByItem(item)
|
||||
.getTagsByEntry(item)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(UnifyTag::location)
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.almostreliable.unified.compat;
|
|||
import com.almostreliable.unified.AlmostUnified;
|
||||
import com.almostreliable.unified.AlmostUnifiedRuntime;
|
||||
import com.almostreliable.unified.utils.ReplacementMap;
|
||||
import com.almostreliable.unified.utils.TagMap;
|
||||
import com.almostreliable.unified.utils.TagOwnerships;
|
||||
import com.almostreliable.unified.utils.Utils;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -18,22 +18,23 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HideHelper {
|
||||
public final class HideHelper {
|
||||
|
||||
private HideHelper() {}
|
||||
|
||||
public static Collection<ItemStack> createHidingList(AlmostUnifiedRuntime runtime) {
|
||||
ReplacementMap repMap = runtime.getReplacementMap().orElse(null);
|
||||
TagMap tagMap = runtime.getFilteredTagMap().orElse(null);
|
||||
var tagMap = runtime.getFilteredTagMap().orElse(null);
|
||||
|
||||
if (repMap == null || tagMap == null) return new ArrayList<>();
|
||||
|
||||
Set<ResourceLocation> hidingList = new HashSet<>();
|
||||
|
||||
for (var unifyTag : tagMap.getTags()) {
|
||||
var itemsByTag = tagMap.getItemsByTag(unifyTag);
|
||||
var itemsByTag = tagMap.getEntriesByTag(unifyTag);
|
||||
|
||||
// avoid hiding single entries and tags that only contain the same namespace for all items
|
||||
long namespaces = itemsByTag.stream().map(ResourceLocation::getNamespace).distinct().count();
|
||||
if (namespaces <= 1) continue;
|
||||
// avoid handling single entries and tags that only contain the same namespace for all items
|
||||
if (Utils.allSameNamespace(itemsByTag)) continue;
|
||||
|
||||
Set<ResourceLocation> replacements = new HashSet<>();
|
||||
for (ResourceLocation item : itemsByTag) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.almostreliable.unified.utils.TagMap;
|
|||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
@ -29,7 +30,7 @@ public class DebugConfig extends Config {
|
|||
this.dumpRecipes = dumpRecipes;
|
||||
}
|
||||
|
||||
public void logUnifyTagDump(TagMap tagMap) {
|
||||
public void logUnifyTagDump(TagMap<Item> tagMap) {
|
||||
if (!dumpTagMap) {
|
||||
return;
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ public class DebugConfig extends Config {
|
|||
.stream()
|
||||
.sorted(Comparator.comparing(t -> t.location().toString()))
|
||||
.map(t -> StringUtils.rightPad(t.location().toString(), 40) + " => " + tagMap
|
||||
.getItemsByTag(t)
|
||||
.getEntriesByTag(t)
|
||||
.stream()
|
||||
.map(ResourceLocation::toString)
|
||||
.sorted()
|
||||
|
|
|
@ -5,11 +5,15 @@ import com.almostreliable.unified.AlmostUnifiedPlatform;
|
|||
import com.almostreliable.unified.utils.JsonUtils;
|
||||
import com.almostreliable.unified.utils.UnifyTag;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -22,6 +26,10 @@ public class UnifyConfig extends Config {
|
|||
private final List<String> materials;
|
||||
private final Map<ResourceLocation, String> priorityOverrides;
|
||||
private final Map<ResourceLocation, Set<ResourceLocation>> tagOwnerships;
|
||||
private final Enum<TagInheritanceMode> itemTagInheritanceMode;
|
||||
private final Map<ResourceLocation, Set<Pattern>> itemTagInheritance;
|
||||
private final Enum<TagInheritanceMode> blockTagInheritanceMode;
|
||||
private final Map<ResourceLocation, Set<Pattern>> blockTagInheritance;
|
||||
private final Set<UnifyTag<Item>> ignoredTags;
|
||||
private final Set<Pattern> ignoredItems;
|
||||
private final Set<Pattern> ignoredRecipeTypes;
|
||||
|
@ -38,6 +46,10 @@ public class UnifyConfig extends Config {
|
|||
List<String> materials,
|
||||
Map<ResourceLocation, String> priorityOverrides,
|
||||
Map<ResourceLocation, Set<ResourceLocation>> tagOwnerships,
|
||||
Enum<TagInheritanceMode> itemTagInheritanceMode,
|
||||
Map<ResourceLocation, Set<Pattern>> itemTagInheritance,
|
||||
Enum<TagInheritanceMode> blockTagInheritanceMode,
|
||||
Map<ResourceLocation, Set<Pattern>> blockTagInheritance,
|
||||
Set<UnifyTag<Item>> ignoredTags,
|
||||
Set<Pattern> ignoredItems,
|
||||
Set<Pattern> ignoredRecipeTypes,
|
||||
|
@ -50,6 +62,10 @@ public class UnifyConfig extends Config {
|
|||
this.materials = materials;
|
||||
this.priorityOverrides = priorityOverrides;
|
||||
this.tagOwnerships = tagOwnerships;
|
||||
this.itemTagInheritanceMode = itemTagInheritanceMode;
|
||||
this.itemTagInheritance = itemTagInheritance;
|
||||
this.blockTagInheritanceMode = blockTagInheritanceMode;
|
||||
this.blockTagInheritance = blockTagInheritance;
|
||||
this.ignoredTags = ignoredTags;
|
||||
this.ignoredItems = ignoredItems;
|
||||
this.ignoredRecipeTypes = ignoredRecipeTypes;
|
||||
|
@ -67,11 +83,20 @@ public class UnifyConfig extends Config {
|
|||
}
|
||||
|
||||
public Set<UnifyTag<Item>> bakeTags() {
|
||||
return bakeTags($ -> true);
|
||||
}
|
||||
|
||||
public Set<UnifyTag<Item>> bakeAndValidateTags(Map<ResourceLocation, Collection<Holder<Item>>> tags) {
|
||||
return bakeTags(tags::containsKey);
|
||||
}
|
||||
|
||||
private Set<UnifyTag<Item>> bakeTags(Predicate<ResourceLocation> tagValidator) {
|
||||
if (bakedTagsCache != null) {
|
||||
return bakedTagsCache;
|
||||
}
|
||||
|
||||
Set<UnifyTag<Item>> result = new HashSet<>();
|
||||
Set<UnifyTag<Item>> wrongTags = new HashSet<>();
|
||||
|
||||
for (String tag : unbakedTags) {
|
||||
for (String material : materials) {
|
||||
|
@ -83,12 +108,24 @@ public class UnifyConfig extends Config {
|
|||
}
|
||||
|
||||
UnifyTag<Item> t = UnifyTag.item(asRL);
|
||||
if (!ignoredTags.contains(t)) {
|
||||
result.add(t);
|
||||
if (ignoredTags.contains(t)) continue;
|
||||
|
||||
if (!tagValidator.test(asRL)) {
|
||||
wrongTags.add(t);
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wrongTags.isEmpty()) {
|
||||
AlmostUnified.LOG.warn(
|
||||
"The following tags are invalid and will be ignored: {}",
|
||||
wrongTags.stream().map(UnifyTag::location).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
bakedTagsCache = result;
|
||||
return result;
|
||||
}
|
||||
|
@ -107,6 +144,45 @@ public class UnifyConfig extends Config {
|
|||
return Collections.unmodifiableMap(tagOwnerships);
|
||||
}
|
||||
|
||||
public boolean shouldInheritItemTag(UnifyTag<Item> itemTag, Set<UnifyTag<Item>> dominantTags) {
|
||||
var patterns = itemTagInheritance.get(itemTag.location());
|
||||
boolean result = checkPatterns(dominantTags, patterns);
|
||||
// noinspection SimplifiableConditionalExpression
|
||||
return itemTagInheritanceMode == TagInheritanceMode.ALLOW ? result : !result;
|
||||
}
|
||||
|
||||
public boolean shouldInheritBlockTag(UnifyTag<Block> itemTag, Set<UnifyTag<Item>> dominantTags) {
|
||||
var patterns = blockTagInheritance.get(itemTag.location());
|
||||
boolean result = checkPatterns(dominantTags, patterns);
|
||||
// noinspection SimplifiableConditionalExpression
|
||||
return blockTagInheritanceMode == TagInheritanceMode.ALLOW ? result : !result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all patterns against all dominant tags.
|
||||
* <p>
|
||||
* This implementation works based on the assumption that the mode is {@link TagInheritanceMode#ALLOW}.
|
||||
* Flip the result if the mode is {@link TagInheritanceMode#DENY}.
|
||||
*
|
||||
* @param dominantTags The tags of the dominant item to check.
|
||||
* @param patterns The patterns to check against.
|
||||
* @param <T> The type of the dominant tags.
|
||||
* @return Whether the dominant tags match any of the patterns.
|
||||
*/
|
||||
private static <T> boolean checkPatterns(Set<UnifyTag<T>> dominantTags, @Nullable Set<Pattern> patterns) {
|
||||
if (patterns == null) return false;
|
||||
|
||||
for (var pattern : patterns) {
|
||||
for (var dominantTag : dominantTags) {
|
||||
if (pattern.matcher(dominantTag.location().toString()).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean includeItem(ResourceLocation item) {
|
||||
for (Pattern pattern : ignoredItems) {
|
||||
if (pattern.matcher(item.toString()).matches()) {
|
||||
|
@ -152,6 +228,10 @@ public class UnifyConfig extends Config {
|
|||
public static final String MATERIALS = "materials";
|
||||
public static final String PRIORITY_OVERRIDES = "priorityOverrides";
|
||||
public static final String TAG_OWNERSHIPS = "tagOwnerships";
|
||||
public static final String ITEM_TAG_INHERITANCE_MODE = "itemTagInheritanceMode";
|
||||
public static final String ITEM_TAG_INHERITANCE = "itemTagInheritance";
|
||||
public static final String BLOCK_TAG_INHERITANCE_MODE = "blockTagInheritanceMode";
|
||||
public static final String BLOCK_TAG_INHERITANCE = "blockTagInheritance";
|
||||
public static final String IGNORED_TAGS = "ignoredTags";
|
||||
public static final String IGNORED_ITEMS = "ignoredItems";
|
||||
public static final String IGNORED_RECIPE_TYPES = "ignoredRecipeTypes";
|
||||
|
@ -168,6 +248,7 @@ public class UnifyConfig extends Config {
|
|||
List<String> tags = safeGet(() -> JsonUtils.toList(json.getAsJsonArray(TAGS)), Defaults.getTags(platform));
|
||||
List<String> materials = safeGet(() -> JsonUtils.toList(json.getAsJsonArray(MATERIALS)),
|
||||
Defaults.MATERIALS);
|
||||
|
||||
Map<ResourceLocation, String> priorityOverrides = safeGet(() -> json.getAsJsonObject(PRIORITY_OVERRIDES)
|
||||
.entrySet()
|
||||
.stream()
|
||||
|
@ -176,6 +257,7 @@ public class UnifyConfig extends Config {
|
|||
entry -> entry.getValue().getAsString(),
|
||||
(a, b) -> b,
|
||||
HashMap::new)), new HashMap<>());
|
||||
|
||||
Map<ResourceLocation, Set<ResourceLocation>> tagOwnerships = safeGet(() -> json
|
||||
.getAsJsonObject(TAG_OWNERSHIPS)
|
||||
.entrySet()
|
||||
|
@ -188,6 +270,17 @@ public class UnifyConfig extends Config {
|
|||
.collect(Collectors.toSet()),
|
||||
(a, b) -> b,
|
||||
HashMap::new)), new HashMap<>());
|
||||
|
||||
|
||||
Enum<TagInheritanceMode> itemTagInheritanceMode = deserializeTagInheritanceMode(json,
|
||||
ITEM_TAG_INHERITANCE_MODE);
|
||||
Map<ResourceLocation, Set<Pattern>> itemTagInheritance = deserializePatternsForLocations(json,
|
||||
ITEM_TAG_INHERITANCE);
|
||||
Enum<TagInheritanceMode> blockTagInheritanceMode = deserializeTagInheritanceMode(json,
|
||||
BLOCK_TAG_INHERITANCE_MODE);
|
||||
Map<ResourceLocation, Set<Pattern>> blockTagInheritance = deserializePatternsForLocations(json,
|
||||
BLOCK_TAG_INHERITANCE);
|
||||
|
||||
Set<UnifyTag<Item>> ignoredTags = safeGet(() -> JsonUtils
|
||||
.toList(json.getAsJsonArray(IGNORED_TAGS))
|
||||
.stream()
|
||||
|
@ -206,6 +299,10 @@ public class UnifyConfig extends Config {
|
|||
materials,
|
||||
priorityOverrides,
|
||||
tagOwnerships,
|
||||
itemTagInheritanceMode,
|
||||
itemTagInheritance,
|
||||
blockTagInheritanceMode,
|
||||
blockTagInheritance,
|
||||
ignoredTags,
|
||||
ignoredItems,
|
||||
ignoredRecipeTypes,
|
||||
|
@ -214,6 +311,43 @@ public class UnifyConfig extends Config {
|
|||
);
|
||||
}
|
||||
|
||||
private TagInheritanceMode deserializeTagInheritanceMode(JsonObject json, String key) {
|
||||
return safeGet(() -> TagInheritanceMode.valueOf(json
|
||||
.getAsJsonPrimitive(key)
|
||||
.getAsString().toUpperCase()), TagInheritanceMode.ALLOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a list of patterns from a json object with a base key. Example json:
|
||||
* <pre>
|
||||
* {
|
||||
* "baseKey": {
|
||||
* "location1": [ pattern1, pattern2 ],
|
||||
* "location2": [ pattern3, pattern4 ]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param rawConfigJson The raw config json
|
||||
* @param baseKey The base key
|
||||
* @return The deserialized patterns separated by location
|
||||
*/
|
||||
private Map<ResourceLocation, Set<Pattern>> unsafeDeserializePatternsForLocations(JsonObject rawConfigJson, String baseKey) {
|
||||
JsonObject json = rawConfigJson.getAsJsonObject(baseKey);
|
||||
return json
|
||||
.keySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
ResourceLocation::new,
|
||||
key -> deserializePatterns(json, key, List.of()),
|
||||
(a, b) -> b,
|
||||
HashMap::new));
|
||||
}
|
||||
|
||||
private Map<ResourceLocation, Set<Pattern>> deserializePatternsForLocations(JsonObject rawConfigJson, String baseKey) {
|
||||
return safeGet(() -> unsafeDeserializePatternsForLocations(rawConfigJson, baseKey), new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject serialize(UnifyConfig config) {
|
||||
JsonObject json = new JsonObject();
|
||||
|
@ -232,6 +366,20 @@ public class UnifyConfig extends Config {
|
|||
JsonUtils.toArray(child.stream().map(ResourceLocation::toString).toList()));
|
||||
});
|
||||
json.add(TAG_OWNERSHIPS, tagOwnerships);
|
||||
JsonObject itemTagInheritance = new JsonObject();
|
||||
config.itemTagInheritance.forEach((tag, patterns) -> {
|
||||
itemTagInheritance.add(tag.toString(),
|
||||
JsonUtils.toArray(patterns.stream().map(Pattern::toString).toList()));
|
||||
});
|
||||
json.add(ITEM_TAG_INHERITANCE_MODE, new JsonPrimitive(config.itemTagInheritanceMode.toString()));
|
||||
json.add(ITEM_TAG_INHERITANCE, itemTagInheritance);
|
||||
JsonObject blockTagInheritance = new JsonObject();
|
||||
config.blockTagInheritance.forEach((tag, patterns) -> {
|
||||
blockTagInheritance.add(tag.toString(),
|
||||
JsonUtils.toArray(patterns.stream().map(Pattern::toString).toList()));
|
||||
});
|
||||
json.add(BLOCK_TAG_INHERITANCE_MODE, new JsonPrimitive(config.blockTagInheritanceMode.toString()));
|
||||
json.add(BLOCK_TAG_INHERITANCE, blockTagInheritance);
|
||||
json.add(IGNORED_TAGS,
|
||||
JsonUtils.toArray(config.ignoredTags
|
||||
.stream()
|
||||
|
@ -245,4 +393,9 @@ public class UnifyConfig extends Config {
|
|||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TagInheritanceMode {
|
||||
ALLOW,
|
||||
DENY
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package com.almostreliable.unified.mixin.runtime;
|
||||
|
||||
import com.almostreliable.unified.AlmostUnified;
|
||||
import com.almostreliable.unified.utils.TagReloadHandler;
|
||||
import com.almostreliable.unified.utils.Utils;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagLoader;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
@ -27,7 +29,17 @@ public class TagLoaderMixin {
|
|||
if (directory.equals("tags/items")) {
|
||||
try {
|
||||
Map<ResourceLocation, Collection<Holder<Item>>> tags = Utils.cast(cir.getReturnValue());
|
||||
AlmostUnified.onTagLoaderReload(tags);
|
||||
TagReloadHandler.initItemTags(tags);
|
||||
TagReloadHandler.run();
|
||||
} catch (Exception e) {
|
||||
AlmostUnified.LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if (directory.equals("tags/blocks")) {
|
||||
try {
|
||||
Map<ResourceLocation, Collection<Holder<Block>>> tags = Utils.cast(cir.getReturnValue());
|
||||
TagReloadHandler.initBlockTags(tags);
|
||||
TagReloadHandler.run();
|
||||
} catch (Exception e) {
|
||||
AlmostUnified.LOG.error(e.getMessage(), e);
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package com.almostreliable.unified.mixin.runtime;
|
||||
|
||||
import com.almostreliable.unified.AlmostUnified;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.tags.TagManager;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Mixin(TagManager.class)
|
||||
public class TagManagerMixin {
|
||||
|
||||
@Inject(method = "reload", at = @At("HEAD"))
|
||||
private void onReload(PreparableReloadListener.PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller profilerFiller, ProfilerFiller profilerFiller2, Executor executor, Executor executor2, CallbackInfoReturnable<CompletableFuture<Void>> cir) {
|
||||
AlmostUnified.onTagManagerReload((TagManager) (Object) this);
|
||||
}
|
||||
}
|
|
@ -18,12 +18,12 @@ import java.util.function.Predicate;
|
|||
public class ReplacementMap {
|
||||
|
||||
private final UnifyConfig unifyConfig;
|
||||
private final TagMap tagMap;
|
||||
private final TagMap<Item> tagMap;
|
||||
private final StoneStrataHandler stoneStrataHandler;
|
||||
private final TagOwnerships tagOwnerships;
|
||||
private final Set<ResourceLocation> warnings;
|
||||
|
||||
public ReplacementMap(UnifyConfig unifyConfig, TagMap tagMap, StoneStrataHandler stoneStrataHandler, TagOwnerships tagOwnerships) {
|
||||
public ReplacementMap(UnifyConfig unifyConfig, TagMap<Item> tagMap, StoneStrataHandler stoneStrataHandler, TagOwnerships tagOwnerships) {
|
||||
this.tagMap = tagMap;
|
||||
this.unifyConfig = unifyConfig;
|
||||
this.stoneStrataHandler = stoneStrataHandler;
|
||||
|
@ -33,7 +33,7 @@ public class ReplacementMap {
|
|||
|
||||
@Nullable
|
||||
public UnifyTag<Item> getPreferredTagForItem(ResourceLocation item) {
|
||||
Collection<UnifyTag<Item>> tags = tagMap.getTagsByItem(item);
|
||||
Collection<UnifyTag<Item>> tags = tagMap.getTagsByEntry(item);
|
||||
|
||||
if (tags.isEmpty()) {
|
||||
return null;
|
||||
|
@ -72,7 +72,7 @@ public class ReplacementMap {
|
|||
if (tagToLookup == null) tagToLookup = tag;
|
||||
|
||||
List<ResourceLocation> items = tagMap
|
||||
.getItemsByTag(tagToLookup)
|
||||
.getEntriesByTag(tagToLookup)
|
||||
.stream()
|
||||
.filter(itemFilter)
|
||||
// Helps us to get the clean stone variant first in case of a stone strata tag
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
@ -8,31 +9,32 @@ import net.minecraft.resources.ResourceLocation;
|
|||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.tags.TagLoader;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class TagMap {
|
||||
public class TagMap<T> {
|
||||
|
||||
private final Map<UnifyTag<Item>, Set<ResourceLocation>> tagsToItems = new HashMap<>();
|
||||
private final Map<ResourceLocation, Set<UnifyTag<Item>>> itemsToTags = new HashMap<>();
|
||||
private final Map<UnifyTag<T>, Set<ResourceLocation>> tagsToEntries = new HashMap<>();
|
||||
private final Map<ResourceLocation, Set<UnifyTag<T>>> entriesToTags = new HashMap<>();
|
||||
|
||||
protected TagMap() {}
|
||||
|
||||
/**
|
||||
* Creates a tag map from a set of unify tags.
|
||||
* Creates an item tag map from a set of item unify tags.
|
||||
* <p>
|
||||
* This should only be used for client-side tag maps or for tests.<br>
|
||||
* It requires the registry to be loaded in order to validate the tags
|
||||
* and fetch the holder from it.
|
||||
* <p>
|
||||
* For the server, use {@link #create(Map)} instead.
|
||||
* For the server, use {@link #createFromItemTags(Map)} instead.
|
||||
*
|
||||
* @param unifyTags The unify tags.
|
||||
* @return A new tag map.
|
||||
*/
|
||||
public static TagMap create(Set<UnifyTag<Item>> unifyTags) {
|
||||
TagMap tagMap = new TagMap();
|
||||
public static TagMap<Item> create(Set<UnifyTag<Item>> unifyTags) {
|
||||
TagMap<Item> tagMap = new TagMap<>();
|
||||
|
||||
unifyTags.forEach(ut -> {
|
||||
TagKey<Item> asTagKey = TagKey.create(Registries.ITEM, ut.location());
|
||||
|
@ -46,84 +48,115 @@ public class TagMap {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a tag map from the vanilla tag collection passed by the {@link TagLoader}.
|
||||
* Creates an item tag map from the vanilla item tag collection passed by the {@link TagLoader}.
|
||||
* <p>
|
||||
* This should only be used on the server.<br>
|
||||
* This tag map should later be filtered by using {@link #filtered(Predicate, Predicate)}.
|
||||
* <p>
|
||||
* For the client, use {@link #create(Set)} instead.
|
||||
*
|
||||
* @param tags The vanilla tag collection.
|
||||
* @return A new tag map.
|
||||
* @param tags The vanilla item tag collection.
|
||||
* @return A new item tag map.
|
||||
*/
|
||||
public static TagMap create(Map<ResourceLocation, Collection<Holder<Item>>> tags) {
|
||||
TagMap tagMap = new TagMap();
|
||||
public static TagMap<Item> createFromItemTags(Map<ResourceLocation, Collection<Holder<Item>>> tags) {
|
||||
TagMap<Item> tagMap = new TagMap<>();
|
||||
|
||||
for (var entry : tags.entrySet()) {
|
||||
UnifyTag<Item> unifyTag = UnifyTag.item(entry.getKey());
|
||||
for (Holder<?> holder : entry.getValue()) {
|
||||
holder
|
||||
.unwrapKey()
|
||||
.map(ResourceKey::location)
|
||||
.filter(BuiltInRegistries.ITEM::containsKey)
|
||||
.ifPresent(itemId -> tagMap.put(unifyTag, itemId));
|
||||
}
|
||||
fillEntries(tagMap, entry.getValue(), unifyTag, BuiltInRegistries.ITEM);
|
||||
}
|
||||
|
||||
return tagMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a block tag map from the vanilla block tag collection passed by the {@link TagLoader}.
|
||||
* <p>
|
||||
* This should only be used on the server.
|
||||
*
|
||||
* @param tags The vanilla block tag collection.
|
||||
* @return A new block tag map.
|
||||
*/
|
||||
public static TagMap<Block> createFromBlockTags(Map<ResourceLocation, Collection<Holder<Block>>> tags) {
|
||||
TagMap<Block> tagMap = new TagMap<>();
|
||||
|
||||
for (var entry : tags.entrySet()) {
|
||||
UnifyTag<Block> unifyTag = UnifyTag.block(entry.getKey());
|
||||
fillEntries(tagMap, entry.getValue(), unifyTag, BuiltInRegistries.BLOCK);
|
||||
}
|
||||
|
||||
return tagMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap all holders, verify them and put them into the tag map.
|
||||
*
|
||||
* @param tagMap The tag map to fill.
|
||||
* @param holders The holders to unwrap.
|
||||
* @param unifyTag The unify tag to use.
|
||||
* @param registry The registry to use.
|
||||
*/
|
||||
private static <T> void fillEntries(TagMap<T> tagMap, Collection<Holder<T>> holders, UnifyTag<T> unifyTag, Registry<T> registry) {
|
||||
for (var holder : holders) {
|
||||
holder
|
||||
.unwrapKey()
|
||||
.map(ResourceKey::location)
|
||||
.filter(registry::containsKey)
|
||||
.ifPresent(id -> tagMap.put(unifyTag, id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a filtered tag map copy.
|
||||
*
|
||||
* @param tagFilter A filter to determine which tags to include.
|
||||
* @param itemFilter A filter to determine which items to include.
|
||||
* @param tagFilter A filter to determine which tags to include.
|
||||
* @param entryFilter A filter to determine which entries to include.
|
||||
* @return A filtered copy of this tag map.
|
||||
*/
|
||||
public TagMap filtered(Predicate<UnifyTag<Item>> tagFilter, Predicate<ResourceLocation> itemFilter) {
|
||||
TagMap tagMap = new TagMap();
|
||||
public TagMap<T> filtered(Predicate<UnifyTag<T>> tagFilter, Predicate<ResourceLocation> entryFilter) {
|
||||
TagMap<T> tagMap = new TagMap<>();
|
||||
|
||||
tagsToItems.forEach((tag, items) -> {
|
||||
tagsToEntries.forEach((tag, items) -> {
|
||||
if (!tagFilter.test(tag)) {
|
||||
return;
|
||||
}
|
||||
items.stream().filter(itemFilter).forEach(item -> tagMap.put(tag, item));
|
||||
items.stream().filter(entryFilter).forEach(item -> tagMap.put(tag, item));
|
||||
});
|
||||
|
||||
return tagMap;
|
||||
}
|
||||
|
||||
public int tagSize() {
|
||||
return tagsToItems.size();
|
||||
return tagsToEntries.size();
|
||||
}
|
||||
|
||||
public int itemSize() {
|
||||
return itemsToTags.size();
|
||||
return entriesToTags.size();
|
||||
}
|
||||
|
||||
public Set<ResourceLocation> getItemsByTag(UnifyTag<Item> tag) {
|
||||
return Collections.unmodifiableSet(tagsToItems.getOrDefault(tag, Collections.emptySet()));
|
||||
public Set<ResourceLocation> getEntriesByTag(UnifyTag<T> tag) {
|
||||
return Collections.unmodifiableSet(tagsToEntries.getOrDefault(tag, Collections.emptySet()));
|
||||
}
|
||||
|
||||
public Set<UnifyTag<Item>> getTagsByItem(ResourceLocation items) {
|
||||
return Collections.unmodifiableSet(itemsToTags.getOrDefault(items, Collections.emptySet()));
|
||||
public Set<UnifyTag<T>> getTagsByEntry(ResourceLocation entry) {
|
||||
return Collections.unmodifiableSet(entriesToTags.getOrDefault(entry, Collections.emptySet()));
|
||||
}
|
||||
|
||||
public Set<UnifyTag<Item>> getTags() {
|
||||
return Collections.unmodifiableSet(tagsToItems.keySet());
|
||||
public Set<UnifyTag<T>> getTags() {
|
||||
return Collections.unmodifiableSet(tagsToEntries.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to build a relationship between a tag and an item.
|
||||
* Helper function to build a relationship between a tag and an entry.
|
||||
* <p>
|
||||
* If the entries don't exist in the internal maps yet, they will be created. That means
|
||||
* it needs to be checked whether the tag or item is valid before calling this method.
|
||||
* it needs to be checked whether the tag or entry is valid before calling this method.
|
||||
*
|
||||
* @param tag The tag.
|
||||
* @param item The item.
|
||||
* @param tag The tag.
|
||||
* @param entry The entry.
|
||||
*/
|
||||
protected void put(UnifyTag<Item> tag, ResourceLocation item) {
|
||||
tagsToItems.computeIfAbsent(tag, k -> new HashSet<>()).add(item);
|
||||
itemsToTags.computeIfAbsent(item, k -> new HashSet<>()).add(tag);
|
||||
protected void put(UnifyTag<T> tag, ResourceLocation entry) {
|
||||
tagsToEntries.computeIfAbsent(tag, k -> new HashSet<>()).add(entry);
|
||||
entriesToTags.computeIfAbsent(entry, k -> new HashSet<>()).add(tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import com.almostreliable.unified.AlmostUnified;
|
||||
import com.almostreliable.unified.ReplacementData;
|
||||
import com.almostreliable.unified.config.UnifyConfig;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class TagReloadHandler {
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
private static Map<ResourceLocation, Collection<Holder<Item>>> RAW_ITEM_TAGS;
|
||||
private static Map<ResourceLocation, Collection<Holder<Block>>> RAW_BLOCK_TAGS;
|
||||
|
||||
private TagReloadHandler() {}
|
||||
|
||||
public static void initItemTags(Map<ResourceLocation, Collection<Holder<Item>>> rawItemTags) {
|
||||
synchronized (LOCK) {
|
||||
RAW_ITEM_TAGS = rawItemTags;
|
||||
}
|
||||
}
|
||||
|
||||
public static void initBlockTags(Map<ResourceLocation, Collection<Holder<Block>>> rawBlockTags) {
|
||||
synchronized (LOCK) {
|
||||
RAW_BLOCK_TAGS = rawBlockTags;
|
||||
}
|
||||
}
|
||||
|
||||
public static void run() {
|
||||
if (RAW_ITEM_TAGS == null || RAW_BLOCK_TAGS == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AlmostUnified.onTagLoaderReload(RAW_ITEM_TAGS);
|
||||
|
||||
RAW_ITEM_TAGS = null;
|
||||
RAW_BLOCK_TAGS = null;
|
||||
}
|
||||
|
||||
public static boolean applyInheritance(UnifyConfig unifyConfig, ReplacementData replacementData) {
|
||||
Preconditions.checkNotNull(RAW_ITEM_TAGS, "Item tags were not loaded correctly");
|
||||
Preconditions.checkNotNull(RAW_BLOCK_TAGS, "Block tags were not loaded correctly");
|
||||
|
||||
Multimap<ResourceLocation, ResourceLocation> changedItemTags = HashMultimap.create();
|
||||
Multimap<ResourceLocation, ResourceLocation> changedBlockTags = HashMultimap.create();
|
||||
|
||||
var relations = resolveRelations(replacementData.filteredTagMap(), replacementData.replacementMap());
|
||||
if (relations.isEmpty()) return false;
|
||||
|
||||
var blockTagMap = TagMap.createFromBlockTags(RAW_BLOCK_TAGS);
|
||||
var globalTagMap = replacementData.globalTagMap();
|
||||
|
||||
for (TagRelation relation : relations) {
|
||||
var dominant = relation.dominant;
|
||||
var dominantItemHolder = findDominantItemHolder(relation);
|
||||
var dominantBlockHolder = findDominantBlockHolder(blockTagMap, dominant);
|
||||
|
||||
var dominantItemTags = globalTagMap.getTagsByEntry(dominant);
|
||||
|
||||
for (var item : relation.items) {
|
||||
if (dominantItemHolder != null) {
|
||||
var changed = applyItemTags(unifyConfig, globalTagMap, dominantItemHolder, dominantItemTags, item);
|
||||
changedItemTags.putAll(dominant, changed);
|
||||
}
|
||||
|
||||
if (dominantBlockHolder != null) {
|
||||
var changed = applyBlockTags(unifyConfig, blockTagMap, dominantBlockHolder, dominantItemTags, item);
|
||||
changedBlockTags.putAll(dominant, changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!changedBlockTags.isEmpty()) {
|
||||
changedBlockTags.asMap().forEach((dominant, tags) -> {
|
||||
AlmostUnified.LOG.info("[TagInheritance] Added '{}' to block tags {}", dominant, tags);
|
||||
});
|
||||
}
|
||||
|
||||
if (!changedItemTags.isEmpty()) {
|
||||
changedItemTags.asMap().forEach((dominant, tags) -> {
|
||||
AlmostUnified.LOG.info("[TagInheritance] Added '{}' to item tags {}", dominant, tags);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Set<TagRelation> resolveRelations(TagMap<Item> filteredTagMap, ReplacementMap repMap) {
|
||||
Set<TagRelation> relations = new HashSet<>();
|
||||
|
||||
for (var unifyTag : filteredTagMap.getTags()) {
|
||||
var itemsByTag = filteredTagMap.getEntriesByTag(unifyTag);
|
||||
|
||||
// avoid handling single entries and tags that only contain the same namespace for all items
|
||||
if (Utils.allSameNamespace(itemsByTag)) continue;
|
||||
|
||||
ResourceLocation dominant = repMap.getPreferredItemForTag(unifyTag, $ -> true);
|
||||
if (dominant == null || !BuiltInRegistries.ITEM.containsKey(dominant)) continue;
|
||||
|
||||
Set<ResourceLocation> items = getValidatedItems(itemsByTag, dominant);
|
||||
|
||||
if (items.isEmpty()) continue;
|
||||
relations.add(new TagRelation(unifyTag.location(), dominant, items));
|
||||
}
|
||||
|
||||
return relations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of all items that are not the dominant item and are valid by checking if they are registered.
|
||||
*
|
||||
* @param itemIds The set of all items that are in the tag
|
||||
* @param dominant The dominant item
|
||||
* @return A set of all items that are not the dominant item and are valid
|
||||
*/
|
||||
private static Set<ResourceLocation> getValidatedItems(Set<ResourceLocation> itemIds, ResourceLocation dominant) {
|
||||
Set<ResourceLocation> result = new HashSet<>(itemIds.size());
|
||||
for (ResourceLocation id : itemIds) {
|
||||
if (!id.equals(dominant) && BuiltInRegistries.ITEM.containsKey(id)) {
|
||||
result.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("StaticVariableUsedBeforeInitialization")
|
||||
@Nullable
|
||||
private static Holder<Item> findDominantItemHolder(TagRelation relation) {
|
||||
var tagHolders = RAW_ITEM_TAGS.get(relation.tag);
|
||||
if (tagHolders == null) return null;
|
||||
|
||||
return findDominantHolder(tagHolders, relation.dominant);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StaticVariableUsedBeforeInitialization")
|
||||
@Nullable
|
||||
private static Holder<Block> findDominantBlockHolder(TagMap<Block> tagMap, ResourceLocation dominant) {
|
||||
var blockTags = tagMap.getTagsByEntry(dominant);
|
||||
if (blockTags.isEmpty()) return null;
|
||||
|
||||
var tagHolders = RAW_BLOCK_TAGS.get(blockTags.iterator().next().location());
|
||||
if (tagHolders == null) return null;
|
||||
|
||||
return findDominantHolder(tagHolders, dominant);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T> Holder<T> findDominantHolder(Collection<Holder<T>> holders, ResourceLocation dominant) {
|
||||
for (var tagHolder : holders) {
|
||||
var holderKey = tagHolder.unwrapKey();
|
||||
if (holderKey.isPresent() && holderKey.get().location().equals(dominant)) {
|
||||
return tagHolder;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Set<ResourceLocation> applyItemTags(UnifyConfig unifyConfig, TagMap<Item> globalTagMap, Holder<Item> dominantItemHolder, Set<UnifyTag<Item>> dominantItemTags, ResourceLocation item) {
|
||||
var itemTags = globalTagMap.getTagsByEntry(item);
|
||||
Set<ResourceLocation> changed = new HashSet<>();
|
||||
|
||||
for (var itemTag : itemTags) {
|
||||
if (!unifyConfig.shouldInheritItemTag(itemTag, dominantItemTags)) continue;
|
||||
if (tryUpdatingRawTags(dominantItemHolder, itemTag, RAW_ITEM_TAGS)) {
|
||||
changed.add(itemTag.location());
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static Set<ResourceLocation> applyBlockTags(UnifyConfig unifyConfig, TagMap<Block> blockTagMap, Holder<Block> dominantBlockHolder, Set<UnifyTag<Item>> dominantItemTags, ResourceLocation item) {
|
||||
var blockTags = blockTagMap.getTagsByEntry(item);
|
||||
Set<ResourceLocation> changed = new HashSet<>();
|
||||
|
||||
for (var blockTag : blockTags) {
|
||||
if (!unifyConfig.shouldInheritBlockTag(blockTag, dominantItemTags)) continue;
|
||||
if (tryUpdatingRawTags(dominantBlockHolder, blockTag, RAW_BLOCK_TAGS)) {
|
||||
changed.add(blockTag.location());
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static <T> boolean tryUpdatingRawTags(Holder<T> dominantHolder, UnifyTag<T> tag, Map<ResourceLocation, Collection<Holder<T>>> rawTags) {
|
||||
var tagHolders = rawTags.get(tag.location());
|
||||
if (tagHolders == null) return false;
|
||||
if (tagHolders.contains(dominantHolder)) return false; // already present, no need to add it again
|
||||
|
||||
ImmutableSet.Builder<Holder<T>> newHolders = ImmutableSet.builder();
|
||||
newHolders.addAll(tagHolders);
|
||||
newHolders.add(dominantHolder);
|
||||
|
||||
rawTags.put(tag.location(), newHolders.build());
|
||||
return true;
|
||||
}
|
||||
|
||||
private record TagRelation(ResourceLocation tag, ResourceLocation dominant, Set<ResourceLocation> items) {}
|
||||
}
|
|
@ -2,12 +2,17 @@ package com.almostreliable.unified.utils;
|
|||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public record UnifyTag<T>(Class<T> boundType, ResourceLocation location) {
|
||||
public static UnifyTag<Item> item(ResourceLocation location) {
|
||||
return new UnifyTag<>(Item.class, location);
|
||||
}
|
||||
|
||||
public static UnifyTag<Block> block(ResourceLocation location) {
|
||||
return new UnifyTag<>(Block.class, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnifyTag[" + boundType.getSimpleName().toLowerCase() + " / " + location + "]";
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
import net.minecraft.world.item.Item;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Set;
|
||||
|
||||
public final class Utils {
|
||||
public static final ResourceLocation UNUSED_ID = new ResourceLocation(BuildConfig.MOD_ID, "unused_id");
|
||||
|
@ -37,4 +38,23 @@ public final class Utils {
|
|||
public static String prefix(String path) {
|
||||
return BuildConfig.MOD_ID + "." + path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all ids have the same namespace
|
||||
*
|
||||
* @param ids set of ids
|
||||
* @return true if all ids have the same namespace
|
||||
*/
|
||||
public static boolean allSameNamespace(Set<ResourceLocation> ids) {
|
||||
if (ids.size() <= 1) return true;
|
||||
|
||||
var it = ids.iterator();
|
||||
var namespace = it.next().getNamespace();
|
||||
|
||||
while (it.hasNext()) {
|
||||
if (!it.next().getNamespace().equals(namespace)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"mixins": [
|
||||
"runtime.RecipeManagerMixin",
|
||||
"runtime.TagLoaderMixin",
|
||||
"runtime.TagManagerMixin",
|
||||
"unifier.ArmorItemMixin",
|
||||
"unifier.TieredItemMixin"
|
||||
],
|
||||
|
|
|
@ -42,6 +42,10 @@ public final class TestUtils {
|
|||
TEST_MOD_PRIORITIES,
|
||||
new HashMap<>(),
|
||||
new HashMap<>(),
|
||||
UnifyConfig.TagInheritanceMode.ALLOW,
|
||||
new HashMap<>(),
|
||||
UnifyConfig.TagInheritanceMode.ALLOW,
|
||||
new HashMap<>(),
|
||||
new HashSet<>(),
|
||||
new HashSet<>(),
|
||||
new HashSet<>(),
|
||||
|
|
|
@ -9,8 +9,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
|
||||
public class TagMapTests {
|
||||
|
||||
public static TagMap testTagMap() {
|
||||
TagMap tagMap = new TagMap();
|
||||
public static TagMap<Item> testTagMap() {
|
||||
TagMap<Item> tagMap = new TagMap<>();
|
||||
UnifyTag<Item> bronzeOreTag = UnifyTag.item(new ResourceLocation("forge:ores/bronze"));
|
||||
UnifyTag<Item> invarOreTag = UnifyTag.item(new ResourceLocation("forge:ores/invar"));
|
||||
UnifyTag<Item> tinOreTag = UnifyTag.item(new ResourceLocation("forge:ores/tin"));
|
||||
|
@ -36,7 +36,7 @@ public class TagMapTests {
|
|||
|
||||
@Test
|
||||
public void simpleCheck() {
|
||||
TagMap tagMap = new TagMap();
|
||||
TagMap<Item> tagMap = new TagMap<>();
|
||||
UnifyTag<Item> bronzeOreTag = UnifyTag.item(new ResourceLocation("forge:ores/bronze"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod1RL("bronze_ore"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod2RL("bronze_ore"));
|
||||
|
@ -44,12 +44,12 @@ public class TagMapTests {
|
|||
tagMap.put(bronzeOreTag, TestUtils.mod4RL("bronze_ore"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod5RL("bronze_ore"));
|
||||
|
||||
assertEquals(tagMap.getItemsByTag(bronzeOreTag).size(), 5);
|
||||
assertEquals(tagMap.getTagsByItem(TestUtils.mod1RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByItem(TestUtils.mod2RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByItem(TestUtils.mod3RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByItem(TestUtils.mod4RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByItem(TestUtils.mod5RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getEntriesByTag(bronzeOreTag).size(), 5);
|
||||
assertEquals(tagMap.getTagsByEntry(TestUtils.mod1RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByEntry(TestUtils.mod2RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByEntry(TestUtils.mod3RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByEntry(TestUtils.mod4RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTagsByEntry(TestUtils.mod5RL("bronze_ore")).size(), 1);
|
||||
|
||||
tagMap.put(UnifyTag.item(new ResourceLocation("forge:ores/invar")), TestUtils.mod1RL("invar_ore"));
|
||||
|
||||
|
|
Loading…
Reference in a new issue