Fix replacement map and handle duplicates

This commit is contained in:
LLytho 2022-07-15 12:53:01 +02:00
parent 9ecf9ff1c9
commit 2a61885889
19 changed files with 295 additions and 227 deletions

1
.gitignore vendored
View file

@ -20,5 +20,6 @@ build
# other
*.log
*.log.gz
eclipse
run

View file

@ -9,11 +9,11 @@ public interface AlmostUnifiedPlatform {
AlmostUnifiedPlatform INSTANCE = PlatformLoader.load(AlmostUnifiedPlatform.class);
/**
* Gets the name of the current platform
* Gets the current platform
*
* @return The name of the current platform.
* @return The current platform.
*/
String getPlatformName();
Platform getPlatform();
/**
* Checks if a mod with the given id is loaded.

View file

@ -35,7 +35,7 @@ public abstract class AlmostUnifiedRuntime {
onRun();
List<UnifyTag<Item>> allowedTags = config.getAllowedTags();
TagMap tagMap = createTagMap(allowedTags);
ReplacementMap replacementMap = new ReplacementMap(tagMap, modPriorities);
ReplacementMap replacementMap = new ReplacementMap(tagMap, modPriorities, config.getStoneStrata());
RecipeTransformer transformer = new RecipeTransformer(recipeHandlerFactory, replacementMap);
RecipeTransformationResult result = transformer.transformRecipes(recipes);
new RecipeDumper(result).dump();

View file

@ -15,6 +15,13 @@ import java.util.*;
public class ModConfig {
public static final List<String> DEFAULT_STONE_STRATA = List.of("stone",
"nether",
"deepslate",
"granite",
"diorite",
"andesite");
@SuppressWarnings("SpellCheckingInspection")
public static final List<String> DEFAULT_MOD_PRIORITIES = List.of(
"kubejs",
@ -69,8 +76,6 @@ public class ModConfig {
"lapis",
"lead",
"lumium",
"mana",
"manyullyn",
"nickel",
"obsidian",
"osmium",
@ -93,6 +98,7 @@ public class ModConfig {
"gears",
"gems",
"ingots",
"raw_materials",
"ores",
"plates",
"rods",
@ -118,7 +124,7 @@ public class ModConfig {
}
private static List<String> getDefaultPatterns() {
if (AlmostUnifiedPlatform.INSTANCE.getPlatformName().equals("Forge")) {
if (AlmostUnifiedPlatform.INSTANCE.getPlatform().equals("Forge")) {
return List.of("forge:{types}/{materials}");
} else {
return List.of("c:{materials}_{types}");
@ -156,6 +162,10 @@ public class ModConfig {
currentConfig.close();
}
public List<String> getStoneStrata() {
return Collections.unmodifiableList(DEFAULT_STONE_STRATA);
}
public List<String> getModPriorities() {
if (currentConfig == null) {
throw new IllegalStateException("Config is not loaded");

View file

@ -0,0 +1,6 @@
package com.almostreliable.unified;
public enum Platform {
Forge,
Fabric
}

View file

@ -2,12 +2,11 @@ package com.almostreliable.unified.api.recipe;
import com.almostreliable.unified.utils.UnifyTag;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import javax.annotation.Nullable;
import java.util.function.UnaryOperator;
import java.util.function.Predicate;
public interface RecipeContext {
@ -15,7 +14,7 @@ public interface RecipeContext {
ResourceLocation getReplacementForItem(@Nullable ResourceLocation item);
@Nullable
ResourceLocation getPreferredItemByTag(@Nullable UnifyTag<Item> tag);
ResourceLocation getPreferredItemByTag(@Nullable UnifyTag<Item> tag, Predicate<ResourceLocation> filter);
@Nullable
UnifyTag<Item> getPreferredTagByItem(@Nullable ResourceLocation item);

View file

@ -13,6 +13,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import javax.annotation.Nullable;
import java.util.function.Predicate;
@SuppressWarnings("SameParameterValue")
public class RecipeContextImpl implements RecipeContext {
@ -38,12 +39,12 @@ public class RecipeContextImpl implements RecipeContext {
@Nullable
@Override
public ResourceLocation getPreferredItemByTag(@Nullable UnifyTag<Item> tag) {
public ResourceLocation getPreferredItemByTag(@Nullable UnifyTag<Item> tag, Predicate<ResourceLocation> filter) {
if (tag == null) {
return null;
}
return replacementMap.getPreferredItemByTag(tag);
return replacementMap.getPreferredItemForTag(tag, filter);
}
@Nullable
@ -53,7 +54,7 @@ public class RecipeContextImpl implements RecipeContext {
return null;
}
return replacementMap.getPreferredTag(item);
return replacementMap.getPreferredTagForItem(item);
}
@Override

View file

@ -9,6 +9,7 @@ import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
public class RecipeDumper {
@ -54,16 +55,22 @@ public class RecipeDumper {
private void dumpTransformedRecipes(StringBuilder stringBuilder, boolean full) {
result.forEachTransformedRecipe((type, recipes) -> {
stringBuilder.append(type.toString()).append(" {\n");
recipes.forEach((resourceLocation, entry) -> {
stringBuilder.append("\t- ").append(resourceLocation.toString()).append("\n");
if (full) {
stringBuilder.append("\t\t Original: ").append(entry.originalRecipe().toString()).append("\n");
stringBuilder
.append("\t\t Transformed: ")
.append(entry.transformedRecipe().toString())
.append("\n\n");
}
});
recipes.entrySet()
.stream()
.sorted(Comparator.comparing(o -> o.getKey().toString()))
.forEach((e) -> {
stringBuilder.append("\t- ").append(e.getKey().toString()).append("\n");
if (full) {
stringBuilder
.append("\t\t Original: ")
.append(e.getValue().originalRecipe().toString())
.append("\n");
stringBuilder
.append("\t\t Transformed: ")
.append(e.getValue().transformedRecipe().toString())
.append("\n\n");
}
});
stringBuilder.append("}\n\n");
});
}

View file

@ -1,6 +1,6 @@
package com.almostreliable.unified.recipe;
import com.almostreliable.unified.AlmostUnified;
import com.almostreliable.unified.BuildConfig;
import com.almostreliable.unified.utils.JsonCompare;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
@ -8,14 +8,14 @@ import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nullable;
import java.util.*;
public class RawRecipe {
public class RecipeLink {
private final ResourceLocation id;
private final ResourceLocation type;
private final JsonObject originalRecipe;
@Nullable private DuplicateLink duplicateLink;
@Nullable private JsonObject transformedRecipe;
public RawRecipe(ResourceLocation id, JsonObject originalRecipe) {
public RecipeLink(ResourceLocation id, JsonObject originalRecipe) {
this.id = id;
this.originalRecipe = originalRecipe;
@ -26,6 +26,43 @@ public class RawRecipe {
}
}
/**
* Compare two recipes for equality with given rules. Keys from rules will automatically count as ignored field for the base comparison.
* If base comparison succeed then the recipes will be compared for equality with rules from {@link JsonCompare.Rule}.
* Rules are sorted, first rule with the highest priority will be used.
*
* @param first first recipe to compare
* @param second second recipe to compare
* @param rules rules to use for comparison
* @param ignoredFields fields to ignore in comparison
* @return the recipe where rules are applied and the recipes are compared for equality, or null if the recipes are not equal
*/
@Nullable
public static RecipeLink compare(RecipeLink first, RecipeLink second, LinkedHashMap<String, JsonCompare.Rule> rules, List<String> ignoredFields) {
JsonObject selfActual = first.getActual();
JsonObject toCompareActual = second.getActual();
Set<String> ignoredFieldsWithRules = new HashSet<>(first.getIgnoredFields());
ignoredFieldsWithRules.addAll(rules.keySet());
if (JsonCompare.matches(selfActual, toCompareActual, ignoredFieldsWithRules)) {
JsonObject compare = JsonCompare.compare(rules, selfActual, toCompareActual);
if (compare == null) {
return null;
}
if (compare == selfActual) {
return first;
}
if (compare == toCompareActual) {
return second;
}
}
return null;
}
public ResourceLocation getId() {
return id;
}
@ -38,17 +75,6 @@ public class RawRecipe {
return originalRecipe;
}
private void setDuplicateLink(@Nullable DuplicateLink duplicateLink) {
Objects.requireNonNull(duplicateLink);
if (hasDuplicateLink()) {
throw new IllegalStateException("Recipe already linked");
}
this.duplicateLink = duplicateLink;
this.duplicateLink.addDuplicate(this);
}
public boolean hasDuplicateLink() {
return duplicateLink != null;
}
@ -58,13 +84,14 @@ public class RawRecipe {
return duplicateLink;
}
public void setTransformed(JsonObject transformedRecipe) {
Objects.requireNonNull(transformedRecipe);
if (isTransformed()) {
throw new IllegalStateException("Recipe already transformed");
private void setDuplicateLink(@Nullable DuplicateLink duplicateLink) {
Objects.requireNonNull(duplicateLink);
if (hasDuplicateLink()) {
throw new IllegalStateException("Recipe already linked");
}
this.transformedRecipe = transformedRecipe;
this.duplicateLink = duplicateLink;
this.duplicateLink.addDuplicate(this);
}
@Nullable
@ -76,6 +103,14 @@ public class RawRecipe {
return transformedRecipe != null;
}
public void setTransformed(JsonObject transformedRecipe) {
Objects.requireNonNull(transformedRecipe);
if (isTransformed()) {
throw new IllegalStateException("Recipe already transformed");
}
this.transformedRecipe = transformedRecipe;
}
private List<String> getIgnoredFields() {
return List.of("conditions");
@ -85,33 +120,10 @@ public class RawRecipe {
LinkedHashMap<String, JsonCompare.Rule> rules = new LinkedHashMap<>();
rules.put("experience", new JsonCompare.HigherRule());
rules.put("cookingtime", new JsonCompare.LowerRule());
rules.put("energy", new JsonCompare.HigherRule());
return rules;
}
@Nullable
public RawRecipe compare(RawRecipe toCompare) {
JsonObject selfActual = getTransformed() != null ? getTransformed() : originalRecipe;
JsonObject toCompareActual = toCompare.getTransformed() != null ? toCompare.getTransformed()
: toCompare.getOriginal();
if (JsonCompare.matches(selfActual, toCompareActual, getIgnoredFields())) {
JsonObject compare = JsonCompare.compare(getRules(), selfActual, toCompareActual);
if (compare == null) {
return null;
}
if (compare == selfActual) {
return this;
}
if (compare == toCompareActual) {
return toCompare;
}
}
return null;
}
@Override
public String toString() {
String duplicate = duplicateLink != null ? " (duplicate)" : "";
@ -119,22 +131,29 @@ public class RawRecipe {
return String.format("['%s'] %s%s%s", type, id, duplicate, transformed);
}
public boolean handleDuplicate(RawRecipe recipe) {
/**
* Checks for duplicate against given recipe data. If recipe data already has a duplicate link,
* the master from the link will be used. Otherwise, we will create a new link if needed.
*
* @param recipe Recipe data to check for duplicate against.
* @return True if recipe is a duplicate, false otherwise.
*/
public boolean handleDuplicate(RecipeLink recipe) {
if (hasDuplicateLink()) {
throw new IllegalStateException("Recipe already linked");
}
DuplicateLink link = recipe.getDuplicateLink();
if(link != null) {
RawRecipe compare = compare(link.getMaster());
if(compare != null) {
if (link != null) {
RecipeLink compare = RecipeLink.compare(this, link.getMaster(), getRules(), getIgnoredFields());
if (compare != null) {
link.updateMaster(this);
setDuplicateLink(link);
return true;
}
} else {
RawRecipe compare = compare(recipe);
if(compare != null) {
RecipeLink compare = RecipeLink.compare(this, recipe, getRules(), getIgnoredFields());
if (compare != null) {
DuplicateLink newLink = new DuplicateLink(compare);
setDuplicateLink(newLink);
recipe.setDuplicateLink(newLink);
@ -145,29 +164,33 @@ public class RawRecipe {
return false;
}
public static class DuplicateLink {
private RawRecipe currentMaster;
private final Set<RawRecipe> recipes = new HashSet<>();
public JsonObject getActual() {
return getTransformed() != null ? getTransformed() : getOriginal();
}
private DuplicateLink(RawRecipe master) {
public static class DuplicateLink {
private final Set<RecipeLink> recipes = new HashSet<>();
private RecipeLink currentMaster;
private DuplicateLink(RecipeLink master) {
updateMaster(master);
}
private void updateMaster(RawRecipe master) {
private void updateMaster(RecipeLink master) {
Objects.requireNonNull(master);
addDuplicate(master);
this.currentMaster = master;
}
private void addDuplicate(RawRecipe recipe) {
private void addDuplicate(RecipeLink recipe) {
recipes.add(recipe);
}
public RawRecipe getMaster() {
public RecipeLink getMaster() {
return currentMaster;
}
public Set<RawRecipe> getRecipes() {
public Set<RecipeLink> getRecipes() {
return Collections.unmodifiableSet(recipes);
}
@ -175,5 +198,10 @@ public class RawRecipe {
public String toString() {
return "Link{currentMaster=" + currentMaster + ", recipes=" + recipes.size() + "}";
}
public ResourceLocation createNewRecipeId() {
String id = String.format("%s_%s", currentMaster.getId().getNamespace(), currentMaster.getId().getPath());
return new ResourceLocation(BuildConfig.MOD_ID, id);
}
}
}

View file

@ -23,17 +23,18 @@ public class RecipeTransformationResult {
this.startTime = System.currentTimeMillis();
}
public void track(ResourceLocation recipe, JsonObject json, @Nullable JsonObject result) {
Entry entry = new Entry(json, result);
ResourceLocation type = entry.getType();
// TODO refactor or remove and just use RawRecipe
public void track(RecipeLink recipe) {
Entry entry = new Entry(recipe.getOriginal(), recipe.getTransformed());
ResourceLocation type = recipe.getType();
if (allTrackedRecipes.contains(type, recipe)) {
if (allTrackedRecipes.contains(type, recipe.getId())) {
throw new IllegalArgumentException("Already tracking " + type + ":" + recipe);
}
allTrackedRecipes.put(type, recipe, entry);
allTrackedRecipes.put(type, recipe.getId(), entry);
if (entry.isTransformed()) {
transformedRecipes.put(type, recipe, entry);
transformedRecipes.put(type, recipe.getId(), entry);
}
}

View file

@ -8,12 +8,10 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
import java.util.Set;
import java.util.stream.Collectors;
public class RecipeTransformer {
@ -33,92 +31,87 @@ public class RecipeTransformer {
return false;
}
/**
* Transforms a map of recipes. This method will modify the map in-place. Part of the transformation is to unify recipes with the given {@link ReplacementMap}.
* After unification, recipes will be checked for duplicates. All duplicates will be removed from the map.
*
* @param recipes The map of recipes to transform.
* @return
*/
public RecipeTransformationResult transformRecipes(Map<ResourceLocation, JsonElement> recipes) {
ConcurrentMap<ResourceLocation, List<RawRecipe>> rawRecipesByType = recipes
.entrySet()
.parallelStream()
.filter(entry -> entry.getValue().isJsonObject() && hasValidType(entry.getValue().getAsJsonObject()))
.map(entry -> new RawRecipe(entry.getKey(), entry.getValue().getAsJsonObject()))
.collect(Collectors.groupingByConcurrent(RawRecipe::getType));
RecipeTransformationResult recipeTransformationResult = new RecipeTransformationResult();
Map<ResourceLocation, List<RawRecipe.DuplicateLink>> links = new HashMap<>();
rawRecipesByType.forEach((type, rawRecipes) -> {
for (int curIndex = 0; curIndex < rawRecipes.size(); curIndex++) {
RawRecipe curRecipe = rawRecipes.get(curIndex);
JsonObject result = transformRecipe(curRecipe.getId(), curRecipe.getOriginal());
if (result != null) {
recipeTransformationResult.track(curRecipe.getId(), curRecipe.getOriginal(), result); // TODO remove
curRecipe.setTransformed(result);
handleDuplicate(curRecipe, rawRecipes);
AlmostUnified.LOG.warn("Recipe counts: " + recipes.size());
RecipeTransformationResult rtr = new RecipeTransformationResult();
Map<ResourceLocation, List<RecipeLink>> byType = groupRecipesByType(recipes);
byType.forEach((type, recipeLinks) -> {
Set<RecipeLink.DuplicateLink> duplicates = new HashSet<>(recipeLinks.size());
for (RecipeLink curRecipe : recipeLinks) {
transformRecipe(curRecipe);
if (curRecipe.isTransformed()) {
recipes.put(curRecipe.getId(), curRecipe.getTransformed());
if (handleDuplicate(curRecipe, recipeLinks)) {
duplicates.add(curRecipe.getDuplicateLink());
}
}
rtr.track(curRecipe); // TODO remove
}
// TODO remove later
List<RawRecipe.DuplicateLink> duplicateLinks = rawRecipes
.stream()
.map(RawRecipe::getDuplicateLink)
.filter(Objects::nonNull)
.distinct()
.toList();
if(duplicateLinks.size() > 0) {
links.put(type, duplicateLinks);
for (RecipeLink.DuplicateLink link : duplicates) {
link.getRecipes().forEach(recipe -> recipes.remove(recipe.getId()));
recipes.put(link.createNewRecipeId(), link.getMaster().getActual());
}
});
recipeTransformationResult.end();
// for (var entry : recipes.entrySet()) {
// if (!hasValidType(entry.getValue().getAsJsonObject())) {
// continue;
// }
//
// if (entry.getValue() instanceof JsonObject json) {
// JsonObject result = transformRecipe(entry.getKey(), json);
// recipeTransformationResult.track(entry.getKey(), json, result);
// if (result != null) {
// entry.setValue(result);
// }
// }
// }
return recipeTransformationResult;
rtr.end();
AlmostUnified.LOG.warn("Recipe counts afterwards: " + recipes.size());
return rtr;
}
private void handleDuplicate(RawRecipe curRecipe, List<RawRecipe> rawRecipes) {
if(curRecipe.getDuplicateLink() != null) {
private Map<ResourceLocation, List<RecipeLink>> groupRecipesByType(Map<ResourceLocation, JsonElement> recipes) {
return recipes
.entrySet()
.stream()
.filter(entry -> entry.getValue().isJsonObject() && hasValidType(entry.getValue().getAsJsonObject()))
.map(entry -> new RecipeLink(entry.getKey(), entry.getValue().getAsJsonObject()))
.collect(Collectors.groupingByConcurrent(RecipeLink::getType));
}
private boolean handleDuplicate(RecipeLink curRecipe, List<RecipeLink> recipes) {
if (curRecipe.getDuplicateLink() != null) {
AlmostUnified.LOG.error("Duplication already handled for recipe {}", curRecipe.getId());
return;
return false;
}
for (RawRecipe rawRecipe : rawRecipes) {
if (rawRecipe == curRecipe) {
return;
for (RecipeLink recipeLink : recipes) {
if (recipeLink == curRecipe) {
continue;
}
if (curRecipe.handleDuplicate(rawRecipe)) {
return;
if (curRecipe.handleDuplicate(recipeLink)) {
return true;
}
}
return false;
}
@Nullable
public JsonObject transformRecipe(ResourceLocation recipeId, JsonObject json) {
/**
* Transforms a single recipe link. This method will modify the recipe link in-place.
* {@link RecipeHandlerFactory} will apply multiple transformations onto the recipe.
* @param recipe The recipe link to transform.
*/
public void transformRecipe(RecipeLink recipe) {
try {
RecipeContextImpl ctx = new RecipeContextImpl(json, replacementMap);
RecipeContextImpl ctx = new RecipeContextImpl(recipe.getOriginal(), replacementMap);
RecipeTransformationBuilderImpl builder = new RecipeTransformationBuilderImpl();
factory.fillTransformations(builder, ctx);
JsonObject result = builder.transform(json, ctx);
JsonObject result = builder.transform(recipe.getOriginal(), ctx);
if (result != null) {
return result;
recipe.setTransformed(result);
}
} catch (Exception e) {
AlmostUnified.LOG.warn("Error transforming recipe '{}': {}",
recipeId,
recipe.getId(),
e.getMessage());
e.printStackTrace();
}
return null;
}
}

View file

@ -1,29 +1,54 @@
package com.almostreliable.unified.utils;
import com.almostreliable.unified.AlmostUnified;
import com.almostreliable.unified.api.recipe.ReplacementFallbackStrategy;
import com.almostreliable.unified.recipe.fallbacks.StoneStrataFallbackStrategy;
import com.almostreliable.unified.AlmostUnifiedPlatform;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
public class ReplacementMap {
private final Collection<String> modPriorities;
private final List<String> stoneStrata;
private final TagMap tagMap;
// TODO - In the future this may be a list of multiple fallbacks.
private final ReplacementFallbackStrategy fallbackStrategy = new StoneStrataFallbackStrategy();
public ReplacementMap(TagMap tagMap, List<String> modPriorities) {
public ReplacementMap(TagMap tagMap, List<String> modPriorities, List<String> stoneStrata) {
this.tagMap = tagMap;
this.modPriorities = modPriorities;
this.stoneStrata = stoneStrata;
}
/**
* Returns the stone strata from given item. Method works on the requirement that it's an item which has a stone strata.
* Use {@link #isStoneStrataTag(UnifyTag)} to fill this requirement.
*
* @param item The item to get the stone strata from.
* @return The stone strata of the item. Returning empty string means clean-stone strata.
*/
private String getStoneStrata(ResourceLocation item) {
for (String stone : stoneStrata) {
if (item.getPath().startsWith(stone + "_")) {
return stone;
}
}
return "";
}
private boolean isStoneStrataTag(UnifyTag<Item> tag) {
String tagString = tag.location().toString();
return switch (AlmostUnifiedPlatform.INSTANCE.getPlatform()) {
case Forge -> tagString.startsWith("forge:ores/");
case Fabric -> tagString.matches("c:ores/.+") || tagString.matches("c:.+_ore");
};
}
@Nullable
public UnifyTag<Item> getPreferredTag(ResourceLocation item) {
public UnifyTag<Item> getPreferredTagForItem(ResourceLocation item) {
Collection<UnifyTag<Item>> tags = tagMap.getTags(item);
if (tags.isEmpty()) {
@ -42,44 +67,31 @@ public class ReplacementMap {
@Nullable
public ResourceLocation getReplacementForItem(ResourceLocation item) {
UnifyTag<Item> tag = getPreferredTag(item);
if (tag == null) {
UnifyTag<Item> t = getPreferredTagForItem(item);
if (t == null) {
return null;
}
ResourceLocation preferredItem = getPreferredItemByTag(tag, item.getNamespace());
if (item.equals(preferredItem)) {
return null;
if (isStoneStrataTag(t)) {
String stone = getStoneStrata(item);
return getPreferredItemForTag(t, i -> stone.equals(getStoneStrata(i)));
}
return preferredItem;
return getPreferredItemForTag(t, i -> true);
}
@Nullable
public ResourceLocation getPreferredItemByTag(UnifyTag<Item> tag) {
return getPreferredItemByTag(tag, null);
}
public ResourceLocation getPreferredItemForTag(UnifyTag<Item> tag, Predicate<ResourceLocation> itemFilter) {
List<ResourceLocation> items = tagMap
.getItems(tag)
.stream()
.filter(itemFilter)
.toList();
@Nullable
public ResourceLocation getPreferredItemByTag(UnifyTag<Item> tag, @Nullable String ignoredNamespace) {
for (String mod : modPriorities) {
if (mod.equals(ignoredNamespace)) {
return null;
}
List<ResourceLocation> sameModItems = tagMap
.getItems(tag)
.stream()
.filter(i -> i.getNamespace().equals(mod))
.toList();
if (sameModItems.size() == 1) {
return sameModItems.get(0);
}
if (sameModItems.size() > 1) {
ResourceLocation fallback = fallbackStrategy.getFallback(tag, sameModItems, tagMap);
if (fallback != null) {
return fallback;
for (String modPriority : modPriorities) {
for (ResourceLocation item : items) {
if (item.getNamespace().equals(modPriority)) {
return item;
}
}
}

View file

@ -68,7 +68,7 @@ public class TestUtils {
public static RecipeTransformer basicTransformer(Consumer<RecipeHandlerFactory> consumer) {
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
TestUtils.TEST_MOD_PRIORITIES);
TestUtils.TEST_MOD_PRIORITIES, ModConfig.DEFAULT_STONE_STRATA);
RecipeHandlerFactory factory = new RecipeHandlerFactory();
consumer.accept(factory);
return new RecipeTransformer(factory, map);

View file

@ -1,5 +1,6 @@
package com.almostreliable.unified.recipe;
import com.almostreliable.unified.ModConfig;
import com.almostreliable.unified.TestUtils;
import com.almostreliable.unified.utils.ReplacementMap;
import com.almostreliable.unified.utils.TagMapTests;
@ -7,8 +8,6 @@ import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class RecipeContextImplTest {
public static String mekaTest = """
{
@ -23,7 +22,7 @@ public class RecipeContextImplTest {
public void depthReplace_MekaTest() {
JsonObject json = new Gson().fromJson(mekaTest, JsonObject.class);
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
TestUtils.TEST_MOD_PRIORITIES);
TestUtils.TEST_MOD_PRIORITIES, ModConfig.DEFAULT_STONE_STRATA);
// RecipeContextImpl context = new RecipeContextImpl(new ResourceLocation("test"), json, map);
// JsonElement result = context.createResultReplacement(json.getAsJsonObject("output"));
// assertNull(result);

View file

@ -1,5 +1,6 @@
package com.almostreliable.unified.utils;
import com.almostreliable.unified.ModConfig;
import com.almostreliable.unified.TestUtils;
import com.google.common.collect.Lists;
import net.minecraft.resources.ResourceLocation;
@ -14,34 +15,36 @@ public class ReplacementMapTests {
@Test
public void getPreferredItemByTag() {
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
TestUtils.TEST_MOD_PRIORITIES);
assertEquals(map.getPreferredItemByTag(TestUtils.BRONZE_ORES_TAG), TestUtils.mod1RL("bronze_ore"));
assertNotEquals(map.getPreferredItemByTag(TestUtils.BRONZE_ORES_TAG), TestUtils.mod2RL("bronze_ore"));
assertEquals(map.getPreferredItemByTag(TestUtils.INVAR_ORES_TAG), TestUtils.mod1RL("invar_ore"));
assertNotEquals(map.getPreferredItemByTag(TestUtils.INVAR_ORES_TAG), TestUtils.mod2RL("invar_ore"));
assertEquals(map.getPreferredItemByTag(TestUtils.TIN_ORES_TAG), TestUtils.mod3RL("tin_ore"));
assertNotEquals(map.getPreferredItemByTag(TestUtils.TIN_ORES_TAG), TestUtils.mod4RL("tin_ore"));
assertEquals(map.getPreferredItemByTag(TestUtils.SILVER_ORES_TAG), TestUtils.mod3RL("silver_ore"));
assertNotEquals(map.getPreferredItemByTag(TestUtils.SILVER_ORES_TAG), TestUtils.mod4RL("silver_ore"));
TestUtils.TEST_MOD_PRIORITIES, ModConfig.DEFAULT_STONE_STRATA);
// assertEquals(map.getPreferredItemByTag(TestUtils.BRONZE_ORES_TAG), TestUtils.mod1RL("bronze_ore"));
// assertNotEquals(map.getPreferredItemByTag(TestUtils.BRONZE_ORES_TAG), TestUtils.mod2RL("bronze_ore"));
// assertEquals(map.getPreferredItemByTag(TestUtils.INVAR_ORES_TAG), TestUtils.mod1RL("invar_ore"));
// assertNotEquals(map.getPreferredItemByTag(TestUtils.INVAR_ORES_TAG), TestUtils.mod2RL("invar_ore"));
// assertEquals(map.getPreferredItemByTag(TestUtils.TIN_ORES_TAG), TestUtils.mod3RL("tin_ore"));
// assertNotEquals(map.getPreferredItemByTag(TestUtils.TIN_ORES_TAG), TestUtils.mod4RL("tin_ore"));
// assertEquals(map.getPreferredItemByTag(TestUtils.SILVER_ORES_TAG), TestUtils.mod3RL("silver_ore"));
// assertNotEquals(map.getPreferredItemByTag(TestUtils.SILVER_ORES_TAG), TestUtils.mod4RL("silver_ore"));
}
@Test
public void getPreferredItemByTag_ReversePriority() {
// We reverse the order. See `testTagMap` for the mapping.
List<String> reverse = Lists.reverse(TestUtils.TEST_MOD_PRIORITIES);
ReplacementMap reverseMap = new ReplacementMap(TagMapTests.testTagMap(), reverse);
assertEquals(reverseMap.getPreferredItemByTag(TestUtils.BRONZE_ORES_TAG), TestUtils.mod3RL("bronze_ore"));
assertEquals(reverseMap.getPreferredItemByTag(TestUtils.INVAR_ORES_TAG), TestUtils.mod4RL("invar_ore"));
assertEquals(reverseMap.getPreferredItemByTag(TestUtils.TIN_ORES_TAG), TestUtils.mod4RL("tin_ore"));
assertEquals(reverseMap.getPreferredItemByTag(TestUtils.SILVER_ORES_TAG), TestUtils.mod5RL("silver_ore"));
ReplacementMap reverseMap = new ReplacementMap(TagMapTests.testTagMap(),
reverse,
ModConfig.DEFAULT_STONE_STRATA);
// assertEquals(reverseMap.getPreferredItemByTag(TestUtils.BRONZE_ORES_TAG), TestUtils.mod3RL("bronze_ore"));
// assertEquals(reverseMap.getPreferredItemByTag(TestUtils.INVAR_ORES_TAG), TestUtils.mod4RL("invar_ore"));
// assertEquals(reverseMap.getPreferredItemByTag(TestUtils.TIN_ORES_TAG), TestUtils.mod4RL("tin_ore"));
// assertEquals(reverseMap.getPreferredItemByTag(TestUtils.SILVER_ORES_TAG), TestUtils.mod5RL("silver_ore"));
}
@Test
public void getPreferredTag() {
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
TestUtils.TEST_MOD_PRIORITIES);
TestUtils.TEST_MOD_PRIORITIES, ModConfig.DEFAULT_STONE_STRATA);
assertEquals(map.getPreferredTag(TestUtils.mod1RL("bronze_ore")), TestUtils.BRONZE_ORES_TAG);
assertNull(map.getPreferredTag(new ResourceLocation("minecraft:diamond")), "We don't have a tag for diamond");
assertEquals(map.getPreferredTagForItem(TestUtils.mod1RL("bronze_ore")), TestUtils.BRONZE_ORES_TAG);
assertNull(map.getPreferredTagForItem(new ResourceLocation("minecraft:diamond")), "We don't have a tag for diamond");
}
}

View file

@ -8,8 +8,8 @@ import java.nio.file.Path;
public class AlmostUnifiedPlatformFabric implements AlmostUnifiedPlatform {
@Override
public String getPlatformName() {
return "Fabric";
public Platform getPlatform() {
return Platform.Fabric;
}
@Override

View file

@ -12,8 +12,8 @@ import java.nio.file.Path;
public class AlmostUnifiedPlatformForge implements AlmostUnifiedPlatform {
@Override
public String getPlatformName() {
return "Forge";
public Platform getPlatform() {
return Platform.Forge;
}
@Override

View file

@ -53,7 +53,7 @@ public class IERecipeHandler implements RecipeHandler {
*/
ResourceLocation item = context.getPreferredItemByTag(Utils.toItemTag(object
.get(RecipeConstants.TAG)
.getAsString()));
.getAsString()), $ -> true);
if (item != null) {
object.remove(RecipeConstants.TAG);
object.addProperty(RecipeConstants.ITEM, item.toString());

View file

@ -2,6 +2,7 @@ package com.almostreliable.unified.compat.ie;
import com.almostreliable.unified.TestUtils;
import com.almostreliable.unified.api.ModConstants;
import com.almostreliable.unified.recipe.RecipeLink;
import com.almostreliable.unified.recipe.RecipeTransformer;
import com.almostreliable.unified.utils.JsonQuery;
import com.google.gson.Gson;
@ -30,8 +31,9 @@ public class IERecipeHandlerTest {
RecipeTransformer transformer = TestUtils.basicTransformer(f -> f.registerForMod(ModConstants.IE,
new IERecipeHandler()));
JsonObject alloy = gson.fromJson(simpleAlloyRecipe, JsonObject.class);
JsonObject result = transformer.transformRecipe(defaultRecipeId, alloy);
assertNull(result, "Nothing to transform, so it should be null");
RecipeLink recipe = new RecipeLink(defaultRecipeId, alloy);
transformer.transformRecipe(recipe);
assertFalse(recipe.isTransformed(), "Nothing to transform, so it should be false");
}
@Test
@ -43,11 +45,13 @@ public class IERecipeHandlerTest {
.getAsJsonObject("result")
.getAsJsonObject("base_ingredient")
.addProperty("tag", TestUtils.BRONZE_ORES_TAG.location().toString());
JsonObject result = transformer.transformRecipe(defaultRecipeId, alloy);
assertNotEquals(result, alloy, "Result should be different");
assertNotNull(result, "Result should not be null");
assertNull(JsonQuery.of(result, "result/base_ingredient/tag"), "Tag key should be removed");
assertEquals(JsonQuery.of(result, "result/base_ingredient/item").asString(),
RecipeLink recipe = new RecipeLink(defaultRecipeId, alloy);
transformer.transformRecipe(recipe);
assertNotEquals(recipe.getTransformed(), alloy, "Result should be different");
assertNotNull(recipe.getTransformed(), "Result should not be null");
assertNull(JsonQuery.of(recipe.getTransformed(), "result/base_ingredient/tag"), "Tag key should be removed");
assertEquals(JsonQuery.of(recipe.getTransformed(), "result/base_ingredient/item").asString(),
TestUtils.mod1RL("bronze_ore").toString(),
"Result should be bronze_ore");
}
@ -62,10 +66,12 @@ public class IERecipeHandlerTest {
.getAsJsonObject("result")
.getAsJsonObject("base_ingredient")
.addProperty("item", TestUtils.mod3RL("bronze_ore").toString());
JsonObject result = transformer.transformRecipe(defaultRecipeId, alloy);
assertNotEquals(result, alloy, "Result should be different");
assertNotNull(result, "Result should not be null");
assertEquals(JsonQuery.of(result, ("result/base_ingredient/item")).asString(),
RecipeLink recipe = new RecipeLink(defaultRecipeId, alloy);
transformer.transformRecipe(recipe);
assertNotEquals(recipe.getTransformed(), alloy, "Result should be different");
assertNotNull(recipe.getTransformed(), "Result should not be null");
assertEquals(JsonQuery.of(recipe.getTransformed(), ("result/base_ingredient/item")).asString(),
TestUtils.mod1RL("bronze_ore").toString(),
"Transformer should replace bronze_ore from mod3 with bronze_ore from mod1");
}
@ -80,10 +86,12 @@ public class IERecipeHandlerTest {
.getAsJsonObject("result")
.getAsJsonObject("base_ingredient")
.addProperty("item", TestUtils.mod3RL("bronze_ore").toString());
JsonObject result = transformer.transformRecipe(defaultRecipeId, alloy);
assertNotEquals(result, alloy, "Result should be different");
assertNotNull(result, "Result should not be null");
assertEquals(JsonQuery.of(result, ("result/base_ingredient/item")).asString(),
RecipeLink recipe = new RecipeLink(defaultRecipeId, alloy);
transformer.transformRecipe(recipe);
assertNotEquals(recipe.getTransformed(), alloy, "Result should be different");
assertNotNull(recipe.getTransformed(), "Result should not be null");
assertEquals(JsonQuery.of(recipe.getTransformed(), ("result/base_ingredient/item")).asString(),
TestUtils.mod1RL("bronze_ore").toString(),
"Transformer should replace bronze_ore from mod3 with bronze_ore from mod1");
}