mirror of
https://github.com/AlmostReliable/almostunified.git
synced 2024-11-14 19:25:13 -05:00
Set up tests & clean up
This commit is contained in:
parent
ce9543c55d
commit
455d275508
29 changed files with 774 additions and 189 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -19,5 +19,6 @@ build
|
|||
.gradle
|
||||
|
||||
# other
|
||||
*.log
|
||||
eclipse
|
||||
run
|
||||
|
|
|
@ -45,6 +45,12 @@ dependencies {
|
|||
* DON'T USE THIS! NEEDED TO COMPILE THIS PROJECT
|
||||
*/
|
||||
modCompileOnly("net.fabricmc:fabric-loader:${fabricLoaderVersion}")
|
||||
|
||||
/**
|
||||
* Test dependencies
|
||||
*/
|
||||
testImplementation ("org.junit.jupiter:junit-jupiter-api:5.8.1")
|
||||
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.1")
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
|
@ -75,3 +81,7 @@ buildConfig {
|
|||
|
||||
packageName(project.group as String)
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ 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.tags.TagKey;
|
||||
import net.minecraft.tags.TagManager;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AlmostUnifiedRuntime {
|
||||
|
||||
|
@ -29,7 +29,8 @@ public abstract class AlmostUnifiedRuntime {
|
|||
config.load();
|
||||
modPriorities = config.getModPriorities();
|
||||
onRun();
|
||||
ReplacementMap replacementMap = createContext(config.getAllowedTags(), modPriorities);
|
||||
TagMap tagMap = createTagMap();
|
||||
ReplacementMap replacementMap = new ReplacementMap(tagMap, config.getAllowedTags(), modPriorities);
|
||||
RecipeTransformer transformer = new RecipeTransformer(recipeHandlerFactory, replacementMap);
|
||||
transformer.transformRecipes(recipes);
|
||||
}
|
||||
|
@ -46,26 +47,5 @@ public abstract class AlmostUnifiedRuntime {
|
|||
return TagMap.create(tagManager);
|
||||
}
|
||||
|
||||
protected ReplacementMap createContext(List<TagKey<Item>> allowedTags, List<String> modPriorities) {
|
||||
TagMap tagMap = createTagMap();
|
||||
Map<ResourceLocation, TagKey<Item>> itemToTagMapping = new HashMap<>(allowedTags.size());
|
||||
|
||||
for (TagKey<Item> tag : allowedTags) {
|
||||
Collection<ResourceLocation> items = tagMap.getItems(tag);
|
||||
for (ResourceLocation item : items) {
|
||||
if (itemToTagMapping.containsKey(item)) {
|
||||
AlmostUnified.LOG.warn("Item '{}' already has a tag '{}' for recipe replacement. Skipping this tag",
|
||||
item,
|
||||
tag);
|
||||
continue;
|
||||
}
|
||||
|
||||
itemToTagMapping.put(item, tag);
|
||||
}
|
||||
}
|
||||
|
||||
return new ReplacementMap(tagMap, itemToTagMapping, modPriorities);
|
||||
}
|
||||
|
||||
protected abstract void onRun();
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.utils.UnifyTag;
|
||||
import com.electronwill.nightconfig.core.Config;
|
||||
import com.electronwill.nightconfig.core.ConfigSpec;
|
||||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -164,13 +163,13 @@ public class ModConfig {
|
|||
return currentConfig.get(UNIFICATION_MOD_PRIORITIES);
|
||||
}
|
||||
|
||||
public List<TagKey<Item>> getAllowedTags() {
|
||||
public List<UnifyTag<Item>> getAllowedTags() {
|
||||
if (currentConfig == null) {
|
||||
throw new IllegalStateException("Config is not loaded");
|
||||
}
|
||||
|
||||
Multimap<String, String> variables = compileVariables();
|
||||
List<TagKey<Item>> collectedPattern = new ArrayList<>();
|
||||
List<UnifyTag<Item>> collectedPattern = new ArrayList<>();
|
||||
|
||||
Collection<String> patterns = currentConfig.get(UNIFICATION_PATTERN);
|
||||
for (String pattern : patterns) {
|
||||
|
@ -183,7 +182,7 @@ public class ModConfig {
|
|||
if (rl == null) {
|
||||
AlmostUnified.LOG.warn("Invalid pattern: " + s);
|
||||
} else {
|
||||
TagKey<Item> tag = TagKey.create(Registry.ITEM_REGISTRY, rl);
|
||||
UnifyTag<Item> tag = UnifyTag.item(rl);
|
||||
collectedPattern.add(tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,4 +10,5 @@ public class RecipeConstants {
|
|||
public static final String OUTPUT = "output";
|
||||
public static final String RESULT = "result";
|
||||
public static final String RESULTS = "results";
|
||||
public static final String VALUE = "value";
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
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.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public interface RecipeContext {
|
||||
|
||||
|
@ -13,19 +15,18 @@ public interface RecipeContext {
|
|||
ResourceLocation getReplacementForItem(@Nullable ResourceLocation item);
|
||||
|
||||
@Nullable
|
||||
ResourceLocation getPreferredItemByTag(TagKey<Item> tag);
|
||||
ResourceLocation getPreferredItemByTag(@Nullable UnifyTag<Item> tag);
|
||||
|
||||
@Nullable
|
||||
TagKey<Item> getPreferredTagByItem(@Nullable ResourceLocation item);
|
||||
UnifyTag<Item> getPreferredTagByItem(@Nullable ResourceLocation item);
|
||||
|
||||
JsonElement replaceIngredient(JsonElement element);
|
||||
JsonElement createIngredientReplacement(@Nullable JsonElement element);
|
||||
|
||||
JsonElement replaceResult(JsonElement element);
|
||||
@Nullable
|
||||
JsonElement createResultReplacement(@Nullable JsonElement element);
|
||||
|
||||
ResourceLocation getType();
|
||||
|
||||
ResourceLocation getId();
|
||||
|
||||
boolean hasProperty(String property);
|
||||
|
||||
default String getModId() {
|
||||
|
|
|
@ -9,10 +9,6 @@ public interface RecipeTransformations {
|
|||
|
||||
void forEachObject(String property, BiFunction<JsonObject, RecipeContext, JsonObject> consumer);
|
||||
|
||||
void replaceIngredient(String property);
|
||||
|
||||
void replaceResult(String property);
|
||||
|
||||
void put(String property, BiFunction<JsonElement, RecipeContext, JsonElement> consumer);
|
||||
|
||||
<T extends JsonElement> void put(String property, Class<T> type, BiFunction<T, RecipeContext, T> consumer);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.almostreliable.unified.api.recipe;
|
||||
|
||||
import com.almostreliable.unified.utils.TagMap;
|
||||
import com.almostreliable.unified.utils.UnifyTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
@ -19,5 +20,5 @@ public interface ReplacementFallbackStrategy {
|
|||
* @throws IllegalStateException if returning the lookupItem
|
||||
*/
|
||||
@Nullable
|
||||
ResourceLocation getFallback(TagKey<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags);
|
||||
ResourceLocation getFallback(UnifyTag<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags);
|
||||
}
|
||||
|
|
|
@ -2,28 +2,26 @@ package com.almostreliable.unified.recipe;
|
|||
|
||||
import com.almostreliable.unified.api.recipe.RecipeConstants;
|
||||
import com.almostreliable.unified.api.recipe.RecipeContext;
|
||||
import com.almostreliable.unified.utils.JsonUtils;
|
||||
import com.almostreliable.unified.utils.ReplacementMap;
|
||||
import com.almostreliable.unified.utils.UnifyTag;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
public class RecipeContextImpl implements RecipeContext {
|
||||
private final ResourceLocation type;
|
||||
private final ResourceLocation id;
|
||||
private final JsonObject currentRecipe;
|
||||
private final ReplacementMap replacementMap;
|
||||
|
||||
public RecipeContextImpl(ResourceLocation type, ResourceLocation id, JsonObject currentRecipe, ReplacementMap replacementMap) {
|
||||
public RecipeContextImpl(ResourceLocation type, JsonObject currentRecipe, ReplacementMap replacementMap) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.currentRecipe = currentRecipe;
|
||||
this.replacementMap = replacementMap;
|
||||
}
|
||||
|
@ -40,13 +38,17 @@ public class RecipeContextImpl implements RecipeContext {
|
|||
|
||||
@Nullable
|
||||
@Override
|
||||
public ResourceLocation getPreferredItemByTag(TagKey<Item> tag) {
|
||||
public ResourceLocation getPreferredItemByTag(@Nullable UnifyTag<Item> tag) {
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return replacementMap.getPreferredItemByTag(tag);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TagKey<Item> getPreferredTagByItem(@Nullable ResourceLocation item) {
|
||||
public UnifyTag<Item> getPreferredTagByItem(@Nullable ResourceLocation item) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -54,58 +56,74 @@ public class RecipeContextImpl implements RecipeContext {
|
|||
return replacementMap.getPreferredTag(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected JsonElement depthReplace(JsonElement element, String potentialFrom, String potentialTo, UnaryOperator<JsonPrimitive> primitiveCallback) {
|
||||
if (element instanceof JsonPrimitive primitive) {
|
||||
return primitiveCallback.apply(primitive);
|
||||
public JsonElement createIngredientReplacement(@Nullable JsonElement element) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
JsonElement copy = element.deepCopy();
|
||||
tryReplacingItemInIngredient(copy);
|
||||
return element.equals(copy) ? null : copy;
|
||||
}
|
||||
|
||||
private void tryReplacingItemInIngredient(@Nullable JsonElement element) {
|
||||
if (element instanceof JsonArray array) {
|
||||
for (JsonElement e : array) {
|
||||
tryReplacingItemInIngredient(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof JsonObject object) {
|
||||
JsonElement replace = depthReplace(object.get(potentialFrom),
|
||||
potentialFrom,
|
||||
potentialTo,
|
||||
primitiveCallback);
|
||||
if (replace != null) {
|
||||
object.remove(potentialFrom);
|
||||
object.add(potentialTo, replace);
|
||||
}
|
||||
}
|
||||
tryReplacingItemInIngredient(object.get(RecipeConstants.VALUE));
|
||||
tryReplacingItemInIngredient(object.get(RecipeConstants.INGREDIENT));
|
||||
|
||||
if (element instanceof JsonArray array) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
JsonElement replace = depthReplace(array.get(i), potentialFrom, potentialTo, primitiveCallback);
|
||||
if (replace != null) {
|
||||
array.set(i, replace);
|
||||
if (object.get(RecipeConstants.ITEM) instanceof JsonPrimitive primitive) {
|
||||
ResourceLocation item = ResourceLocation.tryParse(primitive.getAsString());
|
||||
UnifyTag<Item> tag = getPreferredTagByItem(item);
|
||||
if (tag != null) {
|
||||
object.remove(RecipeConstants.ITEM);
|
||||
object.add(RecipeConstants.TAG, new JsonPrimitive(tag.location().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JsonElement replaceIngredient(JsonElement element) {
|
||||
return depthReplace(element, RecipeConstants.ITEM, RecipeConstants.TAG, primitive -> {
|
||||
ResourceLocation item = ResourceLocation.tryParse(primitive.getAsString());
|
||||
TagKey<Item> tag = getPreferredTagByItem(item);
|
||||
if (tag != null) {
|
||||
return new JsonPrimitive(tag.location().toString());
|
||||
}
|
||||
public JsonElement createResultReplacement(@Nullable JsonElement element) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
JsonElement copy = element.deepCopy();
|
||||
JsonElement result = tryCreateResultReplacement(copy);
|
||||
return element.equals(result) ? null : result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement replaceResult(JsonElement element) {
|
||||
return depthReplace(element, RecipeConstants.ITEM, RecipeConstants.ITEM, primitive -> {
|
||||
@Nullable
|
||||
private JsonElement tryCreateResultReplacement(JsonElement element) {
|
||||
if (element instanceof JsonPrimitive primitive) {
|
||||
ResourceLocation item = ResourceLocation.tryParse(primitive.getAsString());
|
||||
ResourceLocation replacement = getReplacementForItem(item);
|
||||
if (replacement != null) {
|
||||
return new JsonPrimitive(replacement.toString());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
if (element instanceof JsonArray array) {
|
||||
if (JsonUtils.replaceOn(array, this::tryCreateResultReplacement)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof JsonObject object) {
|
||||
if (JsonUtils.replaceOn(object, RecipeConstants.ITEM, this::tryCreateResultReplacement)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -113,11 +131,6 @@ public class RecipeContextImpl implements RecipeContext {
|
|||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(String property) {
|
||||
return currentRecipe.has(property);
|
||||
|
|
|
@ -32,16 +32,6 @@ public class RecipeTransformationsImpl implements RecipeTransformations {
|
|||
put(property, JsonArray.class, arrayConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceIngredient(String property) {
|
||||
put(property, JsonElement.class, (jsonElement, context) -> context.replaceIngredient(jsonElement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceResult(String property) {
|
||||
put(property, JsonElement.class, (jsonElement, context) -> context.replaceResult(jsonElement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String property, BiFunction<JsonElement, RecipeContext, JsonElement> consumer) {
|
||||
consumers.put(property, new Entry<>(JsonElement.class, consumer));
|
||||
|
@ -52,16 +42,37 @@ public class RecipeTransformationsImpl implements RecipeTransformations {
|
|||
consumers.put(property, new Entry<>(type, consumer));
|
||||
}
|
||||
|
||||
public void transform(JsonObject json, RecipeContext context) {
|
||||
@Nullable
|
||||
public JsonObject transform(JsonObject json, RecipeContext context) {
|
||||
JsonObject changedValues = new JsonObject();
|
||||
|
||||
for (var e : json.entrySet()) {
|
||||
Entry<?> consumer = consumers.get(e.getKey());
|
||||
if (consumer != null) {
|
||||
JsonElement result = consumer.apply(e.getValue(), context);
|
||||
if (result != null) {
|
||||
e.setValue(result);
|
||||
JsonElement currentElement = e.getValue();
|
||||
JsonElement transformedElement = consumer.apply(currentElement.deepCopy(), context);
|
||||
if (transformedElement != null && !transformedElement.equals(currentElement)) {
|
||||
changedValues.add(e.getKey(), transformedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changedValues.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// helps to preserve the order of the elements
|
||||
JsonObject result = new JsonObject();
|
||||
for (var entry : json.entrySet()) {
|
||||
JsonElement changedValue = changedValues.get(entry.getKey());
|
||||
if (changedValue != null) {
|
||||
result.add(entry.getKey(), changedValue);
|
||||
} else {
|
||||
result.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private record Entry<T extends JsonElement>(Class<T> expectedType,
|
||||
|
|
|
@ -32,7 +32,7 @@ public class RecipeTransformer {
|
|||
long start = System.nanoTime();
|
||||
for (var entry : recipes.entrySet()) {
|
||||
if (entry.getValue() instanceof JsonObject json) {
|
||||
JsonObject transformedJson = transformRecipe(entry.getKey(), json);
|
||||
JsonObject transformedJson = transformRecipe(json);
|
||||
if (transformedJson != null) {
|
||||
transformedRecipes++;
|
||||
entry.setValue(transformedJson);
|
||||
|
@ -54,25 +54,24 @@ public class RecipeTransformer {
|
|||
AlmostUnified.LOG.info("{}: {} | {}",
|
||||
StringUtils.leftPad(e.getKey().toString(), 40),
|
||||
StringUtils.leftPad(String.valueOf(e.getValue().size()), 4),
|
||||
e.getValue().toString());
|
||||
e.getValue().stream().map(rl -> "\"" + rl.toString() + "\"").toList().toString());
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsonObject transformRecipe(ResourceLocation id, JsonObject json) {
|
||||
public JsonObject transformRecipe(JsonObject json) {
|
||||
ResourceLocation recipeType = getRecipeType(json);
|
||||
if (recipeType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
RecipeContextImpl ctx = new RecipeContextImpl(recipeType, id, json, replacementMap);
|
||||
RecipeContextImpl ctx = new RecipeContextImpl(recipeType, json, replacementMap);
|
||||
RecipeTransformationsImpl builder = new RecipeTransformationsImpl();
|
||||
factory.create(builder, ctx);
|
||||
JsonObject copy = json.deepCopy();
|
||||
builder.transform(copy, ctx);
|
||||
if (!json.equals(copy)) {
|
||||
return copy;
|
||||
JsonObject result = builder.transform(json, ctx);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AlmostUnified.LOG.warn("Error transforming recipe type '{}': {}",
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.almostreliable.unified.recipe.fallbacks;
|
|||
|
||||
import com.almostreliable.unified.api.recipe.ReplacementFallbackStrategy;
|
||||
import com.almostreliable.unified.utils.TagMap;
|
||||
import com.almostreliable.unified.utils.UnifyTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
@ -12,7 +13,7 @@ import java.util.Comparator;
|
|||
// TODO use config and not this :D
|
||||
public class StoneStrataFallbackStrategy implements ReplacementFallbackStrategy {
|
||||
@Override
|
||||
public ResourceLocation getFallback(TagKey<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags) {
|
||||
public ResourceLocation getFallback(UnifyTag<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags) {
|
||||
if (tag.location().getPath().contains("ores")) {
|
||||
return potentialItems
|
||||
.stream()
|
||||
|
|
|
@ -18,11 +18,11 @@ public class GenericRecipeHandler implements RecipeHandler {
|
|||
@Override
|
||||
public void collectTransformations(RecipeTransformations builder) {
|
||||
for (String inputKey : inputKeys) {
|
||||
builder.replaceIngredient(inputKey);
|
||||
builder.put(inputKey, (json, ctx) -> ctx.createIngredientReplacement(json));
|
||||
}
|
||||
|
||||
for (String outputKey : outputKeys) {
|
||||
builder.replaceResult(outputKey);
|
||||
builder.put(outputKey, (json, ctx) -> ctx.createResultReplacement(json));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,15 +20,15 @@ public class RecipeHandlerFactory {
|
|||
ShapedRecipeKeyHandler.INSTANCE.collectTransformations(builder);
|
||||
}
|
||||
|
||||
RecipeHandler byType = transformersByType.get(context.getType());
|
||||
if (byType != null) {
|
||||
byType.collectTransformations(builder);
|
||||
}
|
||||
|
||||
RecipeHandler byMod = transformersByModId.get(context.getModId());
|
||||
if (byMod != null) {
|
||||
byMod.collectTransformations(builder);
|
||||
}
|
||||
|
||||
RecipeHandler byType = transformersByType.get(context.getType());
|
||||
if (byType != null) {
|
||||
byType.collectTransformations(builder);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerForType(ResourceLocation type, RecipeHandler transformer) {
|
||||
|
|
|
@ -14,7 +14,7 @@ public class ShapedRecipeKeyHandler implements RecipeHandler {
|
|||
public void collectTransformations(RecipeTransformations builder) {
|
||||
builder.put(KEY_PROPERTY, JsonObject.class, (json, context) -> {
|
||||
for (var entry : json.entrySet()) {
|
||||
JsonElement result = context.replaceIngredient(entry.getValue());
|
||||
JsonElement result = context.createIngredientReplacement(entry.getValue());
|
||||
if (result != null) {
|
||||
entry.setValue(result);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class JsonQuery {
|
||||
|
||||
private final JsonElement element;
|
||||
|
||||
public static JsonQuery of(JsonElement element) {
|
||||
return new JsonQuery(element);
|
||||
}
|
||||
|
||||
public static JsonQuery of(JsonElement element, String path) {
|
||||
String[] parts = path.split("/");
|
||||
JsonQuery current = of(element);
|
||||
for (String part : parts) {
|
||||
if(StringUtils.isNumeric(part)) {
|
||||
current = current.get(Integer.parseInt(part));
|
||||
} else {
|
||||
current = current.get(part);
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
JsonQuery(JsonElement element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public JsonQuery get(String identifier) {
|
||||
if(!element.isJsonObject()) {
|
||||
throw new IllegalArgumentException("Expected JsonObject, got " + element.getClass());
|
||||
}
|
||||
|
||||
JsonElement child = element.getAsJsonObject().get(identifier);
|
||||
if(child == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new JsonQuery(child);
|
||||
}
|
||||
|
||||
public JsonQuery get(int index) {
|
||||
if(!element.isJsonArray()) {
|
||||
throw new IllegalArgumentException("Expected JsonArray, got " + element.getClass());
|
||||
}
|
||||
|
||||
JsonElement child = element.getAsJsonArray().get(index);
|
||||
if(child == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new JsonQuery(child);
|
||||
}
|
||||
|
||||
public JsonQuery get(String identifier, int index) {
|
||||
return get(identifier).get(index);
|
||||
}
|
||||
|
||||
public JsonObject asObject() {
|
||||
return element.getAsJsonObject();
|
||||
}
|
||||
|
||||
public JsonArray asArray() {
|
||||
return element.getAsJsonArray();
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
return element.getAsString();
|
||||
}
|
||||
|
||||
public int asInt() {
|
||||
return element.getAsInt();
|
||||
}
|
||||
|
||||
public boolean asBoolean() {
|
||||
return element.getAsBoolean();
|
||||
}
|
||||
|
||||
public float asFloat() {
|
||||
return element.getAsFloat();
|
||||
}
|
||||
}
|
|
@ -2,9 +2,11 @@ package com.almostreliable.unified.utils;
|
|||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class JsonUtils {
|
||||
public static JsonArray arrayOrSelf(@Nullable JsonElement element) {
|
||||
|
@ -28,4 +30,46 @@ public class JsonUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through the array and applies the given callback to each element.
|
||||
* If the callback returns non-null, the element is replaced with the returned value.
|
||||
*
|
||||
* @param jsonArray The array to loop through.
|
||||
* @param callback The callback to apply to each element.
|
||||
* @return true if any elements were replaced, false otherwise.
|
||||
*/
|
||||
public static boolean replaceOn(JsonArray jsonArray, UnaryOperator<JsonElement> callback) {
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JsonElement result = callback.apply(jsonArray.get(i));
|
||||
if (result != null) {
|
||||
jsonArray.set(i, result);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the element for the key through given callback.
|
||||
* If the callback returns non-null, the element is replaced with the returned value.
|
||||
*
|
||||
* @param jsonObject The object to loop through.
|
||||
* @param callback The callback to apply to each element.
|
||||
* @return true if the element was replaced, false otherwise.
|
||||
*/
|
||||
public static boolean replaceOn(JsonObject jsonObject, String key, UnaryOperator<JsonElement> callback) {
|
||||
JsonElement element = jsonObject.get(key);
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonElement result = callback.apply(element);
|
||||
if (result != null) {
|
||||
jsonObject.add(key, result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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 net.minecraft.resources.ResourceLocation;
|
||||
|
@ -8,6 +9,7 @@ import net.minecraft.world.item.Item;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -15,24 +17,43 @@ public class ReplacementMap {
|
|||
|
||||
private final Collection<String> modPriorities;
|
||||
private final TagMap tagMap;
|
||||
private final Map<ResourceLocation, TagKey<Item>> itemToTagMapping;
|
||||
private final Map<ResourceLocation, UnifyTag<Item>> itemToTagMapping;
|
||||
// TODO - In the future this may be a list of multiple fallbacks.
|
||||
private final ReplacementFallbackStrategy fallbackStrategy = new StoneStrataFallbackStrategy();
|
||||
|
||||
public ReplacementMap(TagMap tagMap, Map<ResourceLocation, TagKey<Item>> itemToTagMapping, List<String> modPriorities) {
|
||||
public ReplacementMap(TagMap tagMap, List<UnifyTag<Item>> allowedTags, List<String> modPriorities) {
|
||||
this.tagMap = tagMap;
|
||||
this.itemToTagMapping = itemToTagMapping;
|
||||
this.modPriorities = modPriorities;
|
||||
this.itemToTagMapping = createItemMapping(allowedTags);
|
||||
}
|
||||
|
||||
protected Map<ResourceLocation, UnifyTag<Item>> createItemMapping(List<UnifyTag<Item>> allowedTags) {
|
||||
Map<ResourceLocation, UnifyTag<Item>> itemToTagMapping = new HashMap<>(allowedTags.size());
|
||||
for (UnifyTag<Item> tag : allowedTags) {
|
||||
Collection<ResourceLocation> items = tagMap.getItems(tag);
|
||||
for (ResourceLocation item : items) {
|
||||
if (itemToTagMapping.containsKey(item)) {
|
||||
AlmostUnified.LOG.warn("Item '{}' already has a tag '{}' for recipe replacement. Skipping this tag",
|
||||
item,
|
||||
tag);
|
||||
continue;
|
||||
}
|
||||
|
||||
itemToTagMapping.put(item, tag);
|
||||
}
|
||||
}
|
||||
|
||||
return itemToTagMapping;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TagKey<Item> getPreferredTag(ResourceLocation item) {
|
||||
public UnifyTag<Item> getPreferredTag(ResourceLocation item) {
|
||||
return itemToTagMapping.get(item);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getReplacementForItem(ResourceLocation item) {
|
||||
TagKey<Item> tag = getPreferredTag(item);
|
||||
UnifyTag<Item> tag = getPreferredTag(item);
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -46,13 +67,17 @@ public class ReplacementMap {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getPreferredItemByTag(TagKey<Item> tag) {
|
||||
public ResourceLocation getPreferredItemByTag(UnifyTag<Item> tag) {
|
||||
return getPreferredItemByTag(tag, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getPreferredItemByTag(TagKey<Item> tag, @Nullable String ignoredNamespace) {
|
||||
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()
|
||||
|
@ -62,7 +87,7 @@ public class ReplacementMap {
|
|||
return sameModItems.get(0);
|
||||
}
|
||||
|
||||
if (sameModItems.size() > 1 && !mod.equals(ignoredNamespace)) {
|
||||
if (sameModItems.size() > 1) {
|
||||
ResourceLocation fallback = fallbackStrategy.getFallback(tag, sameModItems, tagMap);
|
||||
if (fallback != null) {
|
||||
return fallback;
|
||||
|
|
|
@ -12,8 +12,8 @@ import net.minecraft.world.item.Item;
|
|||
import java.util.*;
|
||||
|
||||
public class TagMap {
|
||||
private final Map<TagKey<Item>, Set<ResourceLocation>> tagsToItems = new HashMap<>();
|
||||
private final Map<ResourceLocation, Set<TagKey<Item>>> itemsToTags = new HashMap<>();
|
||||
private final Map<UnifyTag<Item>, Set<ResourceLocation>> tagsToItems = new HashMap<>();
|
||||
private final Map<ResourceLocation, Set<UnifyTag<Item>>> itemsToTags = new HashMap<>();
|
||||
|
||||
protected TagMap() {}
|
||||
|
||||
|
@ -31,7 +31,7 @@ public class TagMap {
|
|||
TagMap tagMap = new TagMap();
|
||||
|
||||
for (var entry : tags.entrySet()) {
|
||||
TagKey<Item> tag = TagKey.create(Registry.ITEM_REGISTRY, entry.getKey());
|
||||
UnifyTag<Item> tag = UnifyTag.item(entry.getKey());
|
||||
Tag<? extends Holder<?>> holderTag = entry.getValue();
|
||||
|
||||
for (Holder<?> holder : holderTag.getValues()) {
|
||||
|
@ -46,16 +46,24 @@ public class TagMap {
|
|||
return tagMap;
|
||||
}
|
||||
|
||||
protected void put(TagKey<Item> tag, ResourceLocation item) {
|
||||
protected void put(UnifyTag<Item> tag, ResourceLocation item) {
|
||||
tagsToItems.computeIfAbsent(tag, k -> new HashSet<>()).add(item);
|
||||
itemsToTags.computeIfAbsent(item, k -> new HashSet<>()).add(tag);
|
||||
}
|
||||
|
||||
public Collection<ResourceLocation> getItems(TagKey<Item> tag) {
|
||||
public Collection<ResourceLocation> getItems(UnifyTag<Item> tag) {
|
||||
return Collections.unmodifiableSet(tagsToItems.getOrDefault(tag, Collections.emptySet()));
|
||||
}
|
||||
|
||||
public Collection<TagKey<Item>> getTags(ResourceLocation items) {
|
||||
public Collection<UnifyTag<Item>> getTags(ResourceLocation items) {
|
||||
return Collections.unmodifiableSet(itemsToTags.getOrDefault(items, Collections.emptySet()));
|
||||
}
|
||||
|
||||
public int tagSize() {
|
||||
return tagsToItems.size();
|
||||
}
|
||||
|
||||
public int itemSize() {
|
||||
return itemsToTags.size();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
public record UnifyTag<T>(Class<T> boundType, ResourceLocation location) {
|
||||
public static UnifyTag<Item> item(ResourceLocation location) {
|
||||
return new UnifyTag<>(Item.class, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnifyTag[" + boundType.getSimpleName().toLowerCase() + " / " + location + "]";
|
||||
}
|
||||
}
|
|
@ -10,9 +10,9 @@ import javax.annotation.Nullable;
|
|||
|
||||
public class Utils {
|
||||
public static final ResourceLocation UNUSED_ID = new ResourceLocation(BuildConfig.MOD_ID, "unused_id");
|
||||
public static final TagKey<Item> UNUSED_TAG = TagKey.create(Registry.ITEM_REGISTRY, UNUSED_ID);
|
||||
public static final UnifyTag<Item> UNUSED_TAG = UnifyTag.item(UNUSED_ID);
|
||||
|
||||
public static TagKey<Item> toItemTag(@Nullable String tag) {
|
||||
public static UnifyTag<Item> toItemTag(@Nullable String tag) {
|
||||
if (tag == null) {
|
||||
return UNUSED_TAG;
|
||||
}
|
||||
|
@ -22,6 +22,6 @@ public class Utils {
|
|||
return UNUSED_TAG;
|
||||
}
|
||||
|
||||
return TagKey.create(Registry.ITEM_REGISTRY, rl);
|
||||
return UnifyTag.item(rl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class FakeResourceKeyRegistry {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> ResourceKey<Registry<T>> create(String name) {
|
||||
try {
|
||||
Constructor<?> c = ResourceKey.class.getDeclaredConstructor(ResourceLocation.class, ResourceLocation.class);
|
||||
c.setAccessible(true);
|
||||
return (ResourceKey<Registry<T>>) c.newInstance(new ResourceLocation("test_registry"),
|
||||
new ResourceLocation(name));
|
||||
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.recipe.RecipeTransformer;
|
||||
import com.almostreliable.unified.recipe.handler.RecipeHandlerFactory;
|
||||
import com.almostreliable.unified.utils.ReplacementMap;
|
||||
import com.almostreliable.unified.utils.TagMapTests;
|
||||
import com.almostreliable.unified.utils.UnifyTag;
|
||||
import com.google.gson.Gson;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TestUtils {
|
||||
public static final String TEST_MOD_1 = "test_mod_1";
|
||||
public static final String TEST_MOD_2 = "test_mod_2";
|
||||
public static final String TEST_MOD_3 = "test_mod_3";
|
||||
public static final String TEST_MOD_4 = "test_mod_4";
|
||||
public static final String TEST_MOD_5 = "test_mod_5";
|
||||
public static final List<String> TEST_MOD_PRIORITIES = List.of(TEST_MOD_1,
|
||||
TEST_MOD_2,
|
||||
TEST_MOD_3,
|
||||
TEST_MOD_4,
|
||||
TEST_MOD_5);
|
||||
public static final ResourceKey<Registry<Item>> FAKE_ITEM_REGISTRY = FakeResourceKeyRegistry.create("item");
|
||||
public static final UnifyTag<Item> BRONZE_ORES_TAG = tag("forge:ores/bronze");
|
||||
public static final UnifyTag<Item> INVAR_ORES_TAG = tag("forge:ores/invar");
|
||||
public static final UnifyTag<Item> TIN_ORES_TAG = tag("forge:ores/tin");
|
||||
public static final UnifyTag<Item> SILVER_ORES_TAG = tag("forge:ores/silver");
|
||||
public static final List<UnifyTag<Item>> TEST_ALLOWED_TAGS = List.of(BRONZE_ORES_TAG,
|
||||
INVAR_ORES_TAG,
|
||||
TIN_ORES_TAG,
|
||||
SILVER_ORES_TAG);
|
||||
|
||||
/**
|
||||
* ResourceKey is null because otherwise tests can't run because Minecraft is not bootstrapped ...
|
||||
*
|
||||
* @param name the name of the tag
|
||||
* @return a TagKey for the given name
|
||||
*/
|
||||
public static UnifyTag<Item> tag(String name) {
|
||||
return UnifyTag.item(new ResourceLocation(name));
|
||||
}
|
||||
|
||||
public static ResourceLocation mod1RL(String name) {
|
||||
return new ResourceLocation(TEST_MOD_1, name);
|
||||
}
|
||||
|
||||
public static ResourceLocation mod2RL(String name) {
|
||||
return new ResourceLocation(TEST_MOD_2, name);
|
||||
}
|
||||
|
||||
public static ResourceLocation mod3RL(String name) {
|
||||
return new ResourceLocation(TEST_MOD_3, name);
|
||||
}
|
||||
|
||||
public static ResourceLocation mod4RL(String name) {
|
||||
return new ResourceLocation(TEST_MOD_4, name);
|
||||
}
|
||||
|
||||
public static ResourceLocation mod5RL(String name) {
|
||||
return new ResourceLocation(TEST_MOD_5, name);
|
||||
}
|
||||
|
||||
public static RecipeTransformer basicTransformer(Consumer<RecipeHandlerFactory> consumer) {
|
||||
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
|
||||
TestUtils.TEST_ALLOWED_TAGS,
|
||||
TestUtils.TEST_MOD_PRIORITIES);
|
||||
RecipeHandlerFactory factory = new RecipeHandlerFactory();
|
||||
consumer.accept(factory);
|
||||
return new RecipeTransformer(factory, map);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package com.almostreliable.unified.recipe;
|
||||
|
||||
import com.almostreliable.unified.TestUtils;
|
||||
import com.almostreliable.unified.utils.JsonQuery;
|
||||
import com.almostreliable.unified.utils.ReplacementMap;
|
||||
import com.almostreliable.unified.utils.TagMapTests;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
public class RecipeContextImplTest {
|
||||
private static String testJson = """
|
||||
{
|
||||
"input": [
|
||||
{
|
||||
"tag": "tag_replace_me"
|
||||
},
|
||||
[
|
||||
{
|
||||
"item": "item_replace_me"
|
||||
},
|
||||
{
|
||||
"item": "item_replace_me"
|
||||
},
|
||||
[
|
||||
{
|
||||
"item": "item_replace_me"
|
||||
},
|
||||
{
|
||||
"tag": "tag_replace_me"
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
"results": {
|
||||
"item": "item_replace_me"
|
||||
}
|
||||
}""";
|
||||
|
||||
public static String mekaTest = """
|
||||
{
|
||||
"type": "mekanism:combining",
|
||||
"mainInput": { "amount": 8, "ingredient": { "tag": "forge:raw_materials/tin" } },
|
||||
"extraInput": { "ingredient": { "tag": "forge:cobblestone/normal" } },
|
||||
"output": { "item": "mekanism:tin_ore" }
|
||||
}
|
||||
""";
|
||||
|
||||
@Test
|
||||
public void depthReplace_MekaTest() {
|
||||
JsonObject json = new Gson().fromJson(mekaTest, JsonObject.class);
|
||||
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
|
||||
TestUtils.TEST_ALLOWED_TAGS,
|
||||
TestUtils.TEST_MOD_PRIORITIES);
|
||||
RecipeContextImpl context = new RecipeContextImpl(new ResourceLocation("test"), json, map);
|
||||
JsonElement result = context.replaceResultOld(json.getAsJsonObject("output"));
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void depthReplace_NothingReplaced() {
|
||||
JsonObject json = new Gson().fromJson(testJson, JsonObject.class);
|
||||
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
|
||||
TestUtils.TEST_ALLOWED_TAGS,
|
||||
TestUtils.TEST_MOD_PRIORITIES);
|
||||
RecipeContextImpl context = new RecipeContextImpl(new ResourceLocation("test"), json, map);
|
||||
JsonElement result = context.depthReplace(json,
|
||||
"not_existing",
|
||||
"item",
|
||||
primitive -> new JsonPrimitive("dont_find_this"));
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void depthReplace_Items() {
|
||||
JsonObject json = new Gson().fromJson(testJson, JsonObject.class);
|
||||
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
|
||||
TestUtils.TEST_ALLOWED_TAGS,
|
||||
TestUtils.TEST_MOD_PRIORITIES);
|
||||
RecipeContextImpl context = new RecipeContextImpl(new ResourceLocation("test"), json, map);
|
||||
JsonElement result = context.depthReplace(json,
|
||||
"item",
|
||||
"item",
|
||||
primitive -> new JsonPrimitive("item_was_replaced"));
|
||||
assertNotNull(result);
|
||||
assertEquals(JsonQuery.of(result, "input/0/item").asString(), "item_was_replaced");
|
||||
assertEquals(JsonQuery.of(result, "input/1/1/item").asString(), "item_was_replaced");
|
||||
assertEquals(JsonQuery.of(result, "input/1/2/0/item").asString(), "item_was_replaced");
|
||||
assertEquals(JsonQuery.of(result, "result/item").asString(), "item_was_replaced");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import com.almostreliable.unified.TestUtils;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ReplacementMapTests {
|
||||
|
||||
@Test
|
||||
public void getPreferredItemByTag() {
|
||||
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
|
||||
TestUtils.TEST_ALLOWED_TAGS,
|
||||
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"));
|
||||
}
|
||||
|
||||
@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(), TestUtils.TEST_ALLOWED_TAGS, 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"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPreferredTag() {
|
||||
ReplacementMap map = new ReplacementMap(TagMapTests.testTagMap(),
|
||||
TestUtils.TEST_ALLOWED_TAGS,
|
||||
TestUtils.TEST_MOD_PRIORITIES);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import com.almostreliable.unified.TestUtils;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TagMapTests {
|
||||
|
||||
public static TagMap testTagMap() {
|
||||
TagMap 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"));
|
||||
UnifyTag<Item> silverOreTag = UnifyTag.item(new ResourceLocation("forge:ores/silver"));
|
||||
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod1RL("bronze_ore"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod2RL("bronze_ore"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod3RL("bronze_ore"));
|
||||
|
||||
tagMap.put(invarOreTag, TestUtils.mod1RL("invar_ore"));
|
||||
tagMap.put(invarOreTag, TestUtils.mod2RL("invar_ore"));
|
||||
tagMap.put(invarOreTag, TestUtils.mod3RL("invar_ore"));
|
||||
tagMap.put(invarOreTag, TestUtils.mod4RL("invar_ore"));
|
||||
|
||||
tagMap.put(tinOreTag, TestUtils.mod3RL("tin_ore"));
|
||||
tagMap.put(tinOreTag, TestUtils.mod4RL("tin_ore"));
|
||||
|
||||
tagMap.put(silverOreTag, TestUtils.mod3RL("silver_ore"));
|
||||
tagMap.put(silverOreTag, TestUtils.mod4RL("silver_ore"));
|
||||
tagMap.put(silverOreTag, TestUtils.mod5RL("silver_ore"));
|
||||
return tagMap;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleCheck() {
|
||||
TagMap 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"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod3RL("bronze_ore"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod4RL("bronze_ore"));
|
||||
tagMap.put(bronzeOreTag, TestUtils.mod5RL("bronze_ore"));
|
||||
|
||||
assertEquals(tagMap.getItems(bronzeOreTag).size(), 5);
|
||||
assertEquals(tagMap.getTags(TestUtils.mod1RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTags(TestUtils.mod2RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTags(TestUtils.mod3RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTags(TestUtils.mod4RL("bronze_ore")).size(), 1);
|
||||
assertEquals(tagMap.getTags(TestUtils.mod5RL("bronze_ore")).size(), 1);
|
||||
|
||||
tagMap.put(UnifyTag.item(new ResourceLocation("forge:ores/invar")), TestUtils.mod1RL("invar_ore"));
|
||||
|
||||
assertEquals(tagMap.tagSize(), 2);
|
||||
assertEquals(tagMap.itemSize(), 6);
|
||||
}
|
||||
}
|
|
@ -61,6 +61,9 @@ minecraft {
|
|||
|
||||
sourceSets.main.get().resources.srcDir("src/generated/resources")
|
||||
|
||||
// from millions of solutions, this is the only one which works... :-)
|
||||
val commonTests: SourceSetOutput = project(":Common").sourceSets["test"].output
|
||||
|
||||
dependencies {
|
||||
minecraft("net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}")
|
||||
compileOnly(project(":Common"))
|
||||
|
@ -80,6 +83,14 @@ dependencies {
|
|||
runtimeOnly(fg.deobf("curse.maven:nihilo-400012:3810814"))
|
||||
|
||||
annotationProcessor("org.spongepowered:mixin:${mixinVersion}:processor")
|
||||
|
||||
/**
|
||||
* Test dependencies
|
||||
*/
|
||||
testImplementation(project(":Common"))
|
||||
testImplementation(commonTests)
|
||||
testImplementation ("org.junit.jupiter:junit-jupiter-api:5.8.1")
|
||||
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.1")
|
||||
}
|
||||
|
||||
mixin {
|
||||
|
@ -101,6 +112,10 @@ tasks {
|
|||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
register("mavenJava", MavenPublication::class) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.almostreliable.unified.api.recipe.RecipeHandler;
|
|||
import com.almostreliable.unified.api.recipe.RecipeTransformations;
|
||||
import com.almostreliable.unified.utils.JsonUtils;
|
||||
import com.almostreliable.unified.utils.Utils;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -20,79 +21,65 @@ public class IERecipeHandler implements RecipeHandler {
|
|||
// TODO make it cleaner
|
||||
@Override
|
||||
public void collectTransformations(RecipeTransformations builder) {
|
||||
builder.put("input0", (json, context) -> {
|
||||
replaceIEIngredient(json, context);
|
||||
return json;
|
||||
}); // alloy recipes, refinery
|
||||
builder.put("input1", (json, context) -> {
|
||||
replaceIEIngredient(json, context);
|
||||
return json;
|
||||
}); // alloy recipes, refinery
|
||||
builder.put(RecipeConstants.INPUT, (json, context) -> {
|
||||
replaceIEIngredient(json, context);
|
||||
return json;
|
||||
}); // arc furnace, squeezer, cloche, coke oven, fermenter, fertilizer, metal_press
|
||||
builder.put("additives", (json, context) -> {
|
||||
replaceIEIngredient(json, context);
|
||||
return json;
|
||||
}); // arc furnace
|
||||
builder.put(RecipeConstants.INPUTS, (json, context) -> {
|
||||
replaceIEIngredient(json, context);
|
||||
return json;
|
||||
}); // blueprint, mixer
|
||||
|
||||
builder.put("input0", this::replaceIEIngredient); // alloy recipes, refinery
|
||||
builder.put("input1", this::replaceIEIngredient); // alloy recipes, refinery
|
||||
builder.put(RecipeConstants.INPUT,
|
||||
this::replaceIEIngredient); // arc furnace, squeezer, cloche, coke oven, fermenter, fertilizer, metal_press
|
||||
builder.put("additives", this::replaceIEIngredient); // arc furnace
|
||||
builder.put(RecipeConstants.INPUTS, this::replaceIEIngredient); // blueprint, mixer
|
||||
// alloy recipes, crusher
|
||||
builder.forEachObject("secondaries", (jsonObject, context) -> {
|
||||
replaceIEResult(jsonObject.get(RecipeConstants.OUTPUT), context);
|
||||
return jsonObject;
|
||||
});
|
||||
|
||||
builder.put(RecipeConstants.RESULT, (json, context) -> {
|
||||
replaceIEResult(json, context);
|
||||
return json;
|
||||
});
|
||||
|
||||
builder.put(RecipeConstants.RESULTS, (json, context) -> {
|
||||
replaceIEResult(json, context);
|
||||
return json;
|
||||
});
|
||||
builder.forEachObject("secondaries",
|
||||
(jsonObject, context) ->
|
||||
replaceIEResult(jsonObject.get(RecipeConstants.OUTPUT), context) instanceof JsonObject
|
||||
? jsonObject : null);
|
||||
builder.put(RecipeConstants.RESULT, this::replaceIEResult);
|
||||
builder.put(RecipeConstants.RESULTS, this::replaceIEResult);
|
||||
}
|
||||
|
||||
protected void replaceIEResult(@Nullable JsonElement element, RecipeContext context) {
|
||||
if (element == null) {
|
||||
return;
|
||||
@Nullable
|
||||
protected JsonElement replaceIEResult(@Nullable JsonElement element, RecipeContext context) {
|
||||
if (element instanceof JsonArray array) {
|
||||
if (JsonUtils.replaceOn(array, e -> this.replaceIEResult(e, context))) {
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
JsonUtils.arrayForEach(element, JsonObject.class, json -> {
|
||||
if (json.has(RecipeConstants.ITEM)) {
|
||||
context.replaceResult(json);
|
||||
} else if (json.has(RecipeConstants.TAG)) {
|
||||
if (element instanceof JsonObject object) {
|
||||
JsonElement tag = object.get(RecipeConstants.TAG);
|
||||
if (tag != null) {
|
||||
/*
|
||||
* Immersive Engineering allows tags in result and filters them. So we replace the tags with
|
||||
* the preferred item from our config.
|
||||
*/
|
||||
ResourceLocation item = context.getPreferredItemByTag(Utils.toItemTag(json
|
||||
ResourceLocation item = context.getPreferredItemByTag(Utils.toItemTag(object
|
||||
.get(RecipeConstants.TAG)
|
||||
.getAsString()));
|
||||
if (item != null) {
|
||||
json.remove(RecipeConstants.TAG);
|
||||
json.addProperty(RecipeConstants.ITEM, item.toString());
|
||||
object.remove(RecipeConstants.TAG);
|
||||
object.addProperty(RecipeConstants.ITEM, item.toString());
|
||||
return object;
|
||||
}
|
||||
} else if (json.has(BASE_KEY)) {
|
||||
replaceIEResult(json.get(BASE_KEY), context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void replaceIEIngredient(@Nullable JsonElement element, RecipeContext context) {
|
||||
if (element == null) {
|
||||
return;
|
||||
JsonElement base = object.get(BASE_KEY);
|
||||
if (base != null) {
|
||||
JsonElement baseResult = replaceIEResult(base, context);
|
||||
if (baseResult != null) {
|
||||
object.add(BASE_KEY, baseResult);
|
||||
return object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context.createResultReplacement(element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsonElement replaceIEIngredient(@Nullable JsonElement element, RecipeContext context) {
|
||||
if (element instanceof JsonObject json && json.has(BASE_KEY)) {
|
||||
context.replaceIngredient(json.get(BASE_KEY));
|
||||
} else {
|
||||
context.replaceIngredient(element);
|
||||
return context.createIngredientReplacement(json.get(BASE_KEY));
|
||||
}
|
||||
|
||||
return context.createIngredientReplacement(element);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package com.almostreliable.unified.compat.ie;
|
||||
|
||||
import com.almostreliable.unified.TestUtils;
|
||||
import com.almostreliable.unified.api.ModConstants;
|
||||
import com.almostreliable.unified.recipe.RecipeTransformer;
|
||||
import com.almostreliable.unified.utils.JsonQuery;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class IERecipeHandlerTest {
|
||||
public final Gson gson = new Gson();
|
||||
|
||||
private final String simpleAlloyRecipe = """
|
||||
{
|
||||
"type": "immersiveengineering:alloy",
|
||||
"time": 200,
|
||||
"result": { "count": 2, "base_ingredient": { "tag": "forge:ingots/electrum" } },
|
||||
"input0": { "tag": "forge:ingots/gold" },
|
||||
"input1": { "tag": "forge:ingots/silver" }
|
||||
}
|
||||
""";
|
||||
|
||||
@Test
|
||||
public void notMatching() {
|
||||
RecipeTransformer transformer = TestUtils.basicTransformer(f -> f.registerForMod(ModConstants.IE,
|
||||
new IERecipeHandler()));
|
||||
JsonObject alloy = gson.fromJson(simpleAlloyRecipe, JsonObject.class);
|
||||
JsonObject result = transformer.transformRecipe(alloy);
|
||||
assertNull(result, "Nothing to transform, so it should be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resultTagMatches() {
|
||||
RecipeTransformer transformer = TestUtils.basicTransformer(f -> f.registerForMod(ModConstants.IE,
|
||||
new IERecipeHandler()));
|
||||
JsonObject alloy = gson.fromJson(simpleAlloyRecipe, JsonObject.class);
|
||||
alloy
|
||||
.getAsJsonObject("result")
|
||||
.getAsJsonObject("base_ingredient")
|
||||
.addProperty("tag", TestUtils.BRONZE_ORES_TAG.location().toString());
|
||||
JsonObject result = transformer.transformRecipe(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(),
|
||||
TestUtils.mod1RL("bronze_ore").toString(),
|
||||
"Result should be bronze_ore");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resultItemMatches() {
|
||||
RecipeTransformer transformer = TestUtils.basicTransformer(f -> f.registerForMod(ModConstants.IE,
|
||||
new IERecipeHandler()));
|
||||
JsonObject alloy = gson.fromJson(simpleAlloyRecipe, JsonObject.class);
|
||||
alloy.getAsJsonObject("result").getAsJsonObject("base_ingredient").remove("tag");
|
||||
alloy
|
||||
.getAsJsonObject("result")
|
||||
.getAsJsonObject("base_ingredient")
|
||||
.addProperty("item", TestUtils.mod3RL("bronze_ore").toString());
|
||||
JsonObject result = transformer.transformRecipe(alloy);
|
||||
assertNotEquals(result, alloy, "Result should be different");
|
||||
assertNotNull(result, "Result should not be null");
|
||||
assertEquals(JsonQuery.of(result, ("result/base_ingredient/item")).asString(),
|
||||
TestUtils.mod1RL("bronze_ore").toString(),
|
||||
"Transformer should replace bronze_ore from mod3 with bronze_ore from mod1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputAlloyItemMatches() {
|
||||
RecipeTransformer transformer = TestUtils.basicTransformer(f -> f.registerForMod(ModConstants.IE,
|
||||
new IERecipeHandler()));
|
||||
JsonObject alloy = gson.fromJson(simpleAlloyRecipe, JsonObject.class);
|
||||
alloy.getAsJsonObject("result").getAsJsonObject("base_ingredient").remove("tag");
|
||||
alloy
|
||||
.getAsJsonObject("result")
|
||||
.getAsJsonObject("base_ingredient")
|
||||
.addProperty("item", TestUtils.mod3RL("bronze_ore").toString());
|
||||
JsonObject result = transformer.transformRecipe(alloy);
|
||||
assertNotEquals(result, alloy, "Result should be different");
|
||||
assertNotNull(result, "Result should not be null");
|
||||
assertEquals(JsonQuery.of(result, ("result/base_ingredient/item")).asString(),
|
||||
TestUtils.mod1RL("bronze_ore").toString(),
|
||||
"Transformer should replace bronze_ore from mod3 with bronze_ore from mod1");
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue