Implement forge:conditionals type unify

This commit is contained in:
LLytho 2022-07-31 16:20:42 +02:00
parent b36227dc2b
commit 7fe1f6254f
4 changed files with 94 additions and 55 deletions

View file

@ -5,15 +5,20 @@ import com.almostreliable.unified.config.DuplicationConfig;
import com.almostreliable.unified.config.UnifyConfig; import com.almostreliable.unified.config.UnifyConfig;
import com.almostreliable.unified.recipe.unifier.RecipeHandlerFactory; import com.almostreliable.unified.recipe.unifier.RecipeHandlerFactory;
import com.almostreliable.unified.utils.JsonCompare; import com.almostreliable.unified.utils.JsonCompare;
import com.almostreliable.unified.utils.JsonQuery;
import com.almostreliable.unified.utils.ReplacementMap; import com.almostreliable.unified.utils.ReplacementMap;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nullable;
import java.util.*; import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class RecipeTransformer { public class RecipeTransformer {
@ -50,29 +55,67 @@ public class RecipeTransformer {
Result result = new Result(); Result result = new Result();
Map<ResourceLocation, List<RecipeLink>> byType = groupRecipesByType(recipes); Map<ResourceLocation, List<RecipeLink>> byType = groupRecipesByType(recipes);
byType.forEach((type, recipeLinks) -> {
Set<RecipeLink.DuplicateLink> duplicates = new HashSet<>(recipeLinks.size());
for (RecipeLink curRecipe : recipeLinks) {
unifyRecipe(curRecipe);
if (curRecipe.isUnified()) {
recipes.put(curRecipe.getId(), curRecipe.getUnified());
if (handleDuplicate(curRecipe, recipeLinks)) {
duplicates.add(curRecipe.getDuplicateLink());
}
}
result.add(curRecipe);
}
for (RecipeLink.DuplicateLink link : duplicates) { ResourceLocation fcLocation = new ResourceLocation("forge:conditional");
link.getRecipes().forEach(recipe -> recipes.remove(recipe.getId())); byType.forEach((type, recipeLinks) -> {
recipes.put(link.createNewRecipeId(), link.getMaster().getActual()); if (type.equals(fcLocation)) {
recipeLinks.forEach(recipeLink -> handleForgeConditionals(recipeLink).ifPresent(json -> recipes.put(
recipeLink.getId(),
json)));
} else {
transformRecipes(recipeLinks, recipes::put, recipes::remove);
} }
}); });
byType.values().stream().flatMap(Collection::stream).forEach(result::add);
AlmostUnified.LOG.warn("Recipe counts afterwards: " + recipes.size()); AlmostUnified.LOG.warn("Recipe counts afterwards: " + recipes.size());
return result; return result;
} }
private Optional<JsonObject> handleForgeConditionals(RecipeLink recipeLink) {
JsonObject copy = recipeLink.getOriginal().deepCopy();
if (copy.get("recipes") instanceof JsonArray recipes) {
for (JsonElement element : recipes) {
JsonQuery
.of(element, "recipe")
.asObject()
.map(jsonObject -> new RecipeLink(recipeLink.getId(), jsonObject))
.ifPresent(temporaryLink -> {
unifyRecipe(temporaryLink);
if (temporaryLink.isUnified()) {
element.getAsJsonObject().add("recipe", temporaryLink.getUnified());
}
});
}
if (!copy.equals(recipeLink.getOriginal())) {
recipeLink.setUnified(copy);
return Optional.of(copy);
}
}
return Optional.empty();
}
private void transformRecipes(List<RecipeLink> recipeLinks, BiConsumer<ResourceLocation, JsonElement> onAdd, Consumer<ResourceLocation> onRemove) {
Set<RecipeLink.DuplicateLink> duplicates = new HashSet<>(recipeLinks.size());
for (RecipeLink curRecipe : recipeLinks) {
unifyRecipe(curRecipe);
if (curRecipe.isUnified()) {
onAdd.accept(curRecipe.getId(), curRecipe.getUnified());
if (handleDuplicate(curRecipe, recipeLinks)) {
duplicates.add(curRecipe.getDuplicateLink());
}
}
}
for (RecipeLink.DuplicateLink link : duplicates) {
link.getRecipes().forEach(recipe -> onRemove.accept(recipe.getId()));
onAdd.accept(link.createNewRecipeId(), link.getMaster().getActual());
}
}
public Map<ResourceLocation, List<RecipeLink>> groupRecipesByType(Map<ResourceLocation, JsonElement> recipes) { public Map<ResourceLocation, List<RecipeLink>> groupRecipesByType(Map<ResourceLocation, JsonElement> recipes) {
return recipes return recipes
.entrySet() .entrySet()
@ -83,8 +126,7 @@ public class RecipeTransformer {
} }
private boolean includeRecipe(ResourceLocation recipe, JsonElement json) { private boolean includeRecipe(ResourceLocation recipe, JsonElement json) {
return unifyConfig.includeRecipe(recipe) && json.isJsonObject() && return unifyConfig.includeRecipe(recipe) && json.isJsonObject() && hasValidType(json.getAsJsonObject());
hasValidType(json.getAsJsonObject());
} }
private boolean handleDuplicate(RecipeLink curRecipe, List<RecipeLink> recipes) { private boolean handleDuplicate(RecipeLink curRecipe, List<RecipeLink> recipes) {
@ -132,9 +174,7 @@ public class RecipeTransformer {
recipe.setUnified(result); recipe.setUnified(result);
} }
} catch (Exception e) { } catch (Exception e) {
AlmostUnified.LOG.warn("Error unifying recipe '{}': {}", AlmostUnified.LOG.warn("Error unifying recipe '{}': {}", recipe.getId(), e.getMessage());
recipe.getId(),
e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
} }

View file

@ -5,14 +5,21 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
import java.util.Optional;
public class JsonQuery { public class JsonQuery {
private final JsonElement element; @Nullable private final JsonElement element;
JsonQuery(JsonElement element) { JsonQuery(@Nullable JsonElement element) {
this.element = element; this.element = element;
} }
JsonQuery() {
this.element = null;
}
public static JsonQuery of(JsonElement element) { public static JsonQuery of(JsonElement element) {
return new JsonQuery(element); return new JsonQuery(element);
} }
@ -31,56 +38,45 @@ public class JsonQuery {
} }
public JsonQuery get(String identifier) { public JsonQuery get(String identifier) {
if (!element.isJsonObject()) { if (element instanceof JsonObject json) {
throw new IllegalArgumentException("Expected JsonObject, got " + element.getClass()); JsonElement child = json.get(identifier);
if (child != null) {
return new JsonQuery(child);
}
} }
JsonElement child = element.getAsJsonObject().get(identifier); return new JsonQuery();
if (child == null) {
return null;
}
return new JsonQuery(child);
} }
public JsonQuery get(int index) { public JsonQuery get(int index) {
if (!element.isJsonArray()) { if (element instanceof JsonArray json && 0 <= index && index < json.size()) {
throw new IllegalArgumentException("Expected JsonArray, got " + element.getClass()); JsonElement child = json.get(index);
if (child != null) {
return new JsonQuery(child);
}
} }
JsonElement child = element.getAsJsonArray().get(index); return new JsonQuery();
if (child == null) {
return null;
}
return new JsonQuery(child);
} }
public JsonQuery get(String identifier, int index) { public JsonQuery get(String identifier, int index) {
return get(identifier).get(index); return get(identifier).get(index);
} }
public JsonObject asObject() { public Optional<JsonElement> asElement() {
return element.getAsJsonObject(); return Optional.ofNullable(element);
} }
public JsonArray asArray() { public Optional<JsonObject> asObject() {
return element.getAsJsonArray(); return asElement().filter(JsonObject.class::isInstance).map(JsonObject.class::cast);
} }
public String asString() { public Optional<JsonArray> asArray() {
return element.getAsString(); return asElement().filter(JsonArray.class::isInstance).map(JsonArray.class::cast);
} }
public int asInt() { public Optional<String> asString() {
return element.getAsInt(); return asElement().filter(JsonElement::isJsonPrimitive).map(JsonElement::getAsString);
}
public boolean asBoolean() {
return element.getAsBoolean();
}
public float asFloat() {
return element.getAsFloat();
} }
} }

View file

@ -8,6 +8,7 @@ import net.minecraft.world.item.Item;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -84,6 +85,8 @@ public class ReplacementMap {
.getItems(tag) .getItems(tag)
.stream() .stream()
.filter(itemFilter) .filter(itemFilter)
// Helps us to get the clean stone variant first in case of a stone strata tag
.sorted(Comparator.comparingInt(value -> value.toString().length()))
.toList(); .toList();
for (String modPriority : unifyConfig.getModPriorities()) { for (String modPriority : unifyConfig.getModPriorities()) {

View file

@ -80,7 +80,7 @@ public class TestUtils {
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(), DEFAULT_UNIFY_CONFIG); ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(), DEFAULT_UNIFY_CONFIG);
RecipeHandlerFactory factory = new RecipeHandlerFactory(); RecipeHandlerFactory factory = new RecipeHandlerFactory();
consumer.accept(factory); consumer.accept(factory);
return new RecipeTransformer(factory, map, DEFAULT_UNIFY_CONFIG, duplicationConfig); return new RecipeTransformer(factory, map, DEFAULT_UNIFY_CONFIG, null);
} }
public static JsonObject json(String json) { public static JsonObject json(String json) {