mirror of
https://github.com/AlmostReliable/almostunified.git
synced 2024-11-28 10:35:38 -05:00
Refactor factory system & context
This commit is contained in:
parent
c6beabaf2e
commit
e746cf95f4
25 changed files with 493 additions and 270 deletions
|
@ -1,5 +1,6 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.handler.RecipeHandlerFactory;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
@ -11,11 +12,6 @@ public class AlmostUnified {
|
|||
@Nullable
|
||||
private static AlmostUnifiedRuntime RUNTIME;
|
||||
|
||||
|
||||
public AlmostUnified() {
|
||||
// MANAGER.register(new ResourceLocation("minecraft:crafting_shaped"), new ShapedRecipeTransformer());
|
||||
}
|
||||
|
||||
public static AlmostUnifiedRuntime getRuntime() {
|
||||
if (RUNTIME == null) {
|
||||
throw new IllegalStateException("AlmostUnifiedRuntime not initialized");
|
||||
|
@ -24,6 +20,8 @@ public class AlmostUnified {
|
|||
}
|
||||
|
||||
static void initializeRuntime() {
|
||||
RUNTIME = new AlmostUnifiedRuntime();
|
||||
RecipeHandlerFactory factory = new RecipeHandlerFactory();
|
||||
// factory.registerForMod("immersiveengineering", new IERecipeTransformerFactory());
|
||||
RUNTIME = new AlmostUnifiedRuntime(factory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeTransformContext;
|
||||
import com.almostreliable.unified.api.RecipeTransformer;
|
||||
import com.almostreliable.unified.api.RecipeTransformerFactory;
|
||||
import com.almostreliable.unified.api.RecipeTransformerRegistry;
|
||||
import com.almostreliable.unified.transformer.GenericRecipeTransformerFactory;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.almostreliable.unified.api.RecipeHandler;
|
||||
import com.almostreliable.unified.handler.RecipeHandlerFactory;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -23,72 +18,74 @@ import java.util.Map;
|
|||
public class AlmostUnifiedRuntime {
|
||||
|
||||
protected final ModConfig config;
|
||||
protected final RecipeTransformerFactory defaultFactory = new GenericRecipeTransformerFactory();
|
||||
protected final RecipeHandlerFactory recipeHandlerFactory;
|
||||
@Nullable protected TagManager tagManager;
|
||||
|
||||
public AlmostUnifiedRuntime() {
|
||||
public AlmostUnifiedRuntime(RecipeHandlerFactory recipeHandlerFactory) {
|
||||
this.recipeHandlerFactory = recipeHandlerFactory;
|
||||
config = new ModConfig(BuildConfig.MOD_ID);
|
||||
}
|
||||
|
||||
public void run(Map<ResourceLocation, JsonElement> recipes) {
|
||||
config.load();
|
||||
RecipeTransformContext context = createContext(config.getAllowedTags(), config.getModPriorities());
|
||||
transformRecipes(recipes, context);
|
||||
ReplacementMap replacementMap = createContext(config.getAllowedTags(), config.getModPriorities());
|
||||
transformRecipes(recipes, replacementMap);
|
||||
}
|
||||
|
||||
public void transformRecipes(Map<ResourceLocation, JsonElement> recipes, RecipeTransformContext helper) {
|
||||
public void transformRecipes(Map<ResourceLocation, JsonElement> recipes, ReplacementMap replacementMap) {
|
||||
int transformedRecipes = 0;
|
||||
int transformedPropertiesInRecipes = 0;
|
||||
long start = System.nanoTime();
|
||||
for (var entry : recipes.entrySet()) {
|
||||
if (entry.getValue() instanceof JsonObject json) {
|
||||
int changes = transformRecipe(json, helper);
|
||||
if (changes > 0) {
|
||||
JsonObject transformedJson = transformRecipe(entry.getKey(), json, replacementMap);
|
||||
if (transformedJson != null) {
|
||||
transformedRecipes++;
|
||||
transformedPropertiesInRecipes += changes;
|
||||
entry.setValue(transformedJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
long finish = System.nanoTime();
|
||||
long timeElapsed = finish - start;
|
||||
AlmostUnified.LOG.info("Transformed {}/{} recipes with {} changes in {}ms",
|
||||
AlmostUnified.LOG.info("Transformed {}/{} recipes changes in {}ms",
|
||||
transformedRecipes,
|
||||
recipes.size(),
|
||||
transformedPropertiesInRecipes,
|
||||
timeElapsed / 1000_000D);
|
||||
}
|
||||
|
||||
public int transformRecipe(JsonObject json, RecipeTransformContext helper) {
|
||||
@Nullable
|
||||
public JsonObject transformRecipe(ResourceLocation id, JsonObject json, ReplacementMap replacementMap) {
|
||||
ResourceLocation recipeType = getRecipeType(json);
|
||||
if (recipeType == null) {
|
||||
return 0;
|
||||
return null;
|
||||
}
|
||||
|
||||
RecipeTransformerFactory factory = RecipeTransformerRegistry.getOrDefault(recipeType, defaultFactory);
|
||||
int transformedProperties = 0;
|
||||
for (var entry : json.entrySet()) {
|
||||
String property = entry.getKey();
|
||||
RecipeTransformer recipeTransformer = factory.create(recipeType, property);
|
||||
if (recipeTransformer == null) {
|
||||
continue;
|
||||
RecipeContextImpl ctx = new RecipeContextImpl(recipeType, id, json, replacementMap);
|
||||
// for (var entry : json.entrySet()) {
|
||||
|
||||
try {
|
||||
RecipeHandler recipeHandler = recipeHandlerFactory.create(ctx);
|
||||
if (recipeHandler == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
JsonElement jsonValue = json.get(property);
|
||||
JsonElement overriddenJson = recipeTransformer.transformRecipe(jsonValue.deepCopy(), helper);
|
||||
if (overriddenJson != null && !jsonValue.equals(overriddenJson)) {
|
||||
entry.setValue(overriddenJson);
|
||||
transformedProperties++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AlmostUnified.LOG.warn("Error transforming recipe for type '{}' with property '{}': {}",
|
||||
JsonObject copy = json.deepCopy();
|
||||
recipeHandler.transformRecipe(copy, ctx);
|
||||
if (!json.equals(copy)) {
|
||||
AlmostUnified.LOG.info("Transformed recipe '{}' for type '{}' ========> {}",
|
||||
id,
|
||||
recipeType,
|
||||
property,
|
||||
e.getMessage());
|
||||
e.printStackTrace();
|
||||
copy);
|
||||
|
||||
return copy;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AlmostUnified.LOG.warn("Error transforming recipe type '{}': {}",
|
||||
recipeType,
|
||||
e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return transformedProperties;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,7 +99,7 @@ public class AlmostUnifiedRuntime {
|
|||
this.tagManager = tagManager;
|
||||
}
|
||||
|
||||
protected RecipeTransformContext createContext(List<TagKey<Item>> allowedTags, List<String> modPriorities) {
|
||||
protected ReplacementMap createContext(List<TagKey<Item>> allowedTags, List<String> modPriorities) {
|
||||
if (tagManager == null) {
|
||||
throw new IllegalStateException("Internal error. TagManager was not updated correctly");
|
||||
}
|
||||
|
@ -125,6 +122,6 @@ public class AlmostUnifiedRuntime {
|
|||
}
|
||||
}
|
||||
|
||||
return new RecipeTransformContextImpl(tagMap, itemToTagMapping, modPriorities);
|
||||
return new ReplacementMap(tagMap, itemToTagMapping, modPriorities);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeContext;
|
||||
import com.almostreliable.unified.utils.JsonUtils;
|
||||
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.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class RecipeContextImpl implements RecipeContext {
|
||||
public static final String TAG = "tag";
|
||||
public static final String ITEM = "item";
|
||||
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) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.currentRecipe = currentRecipe;
|
||||
this.replacementMap = replacementMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ResourceLocation getReplacementForItem(@Nullable ResourceLocation item) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return replacementMap.getReplacementForItem(item);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ResourceLocation getPreferredItemByTag(TagKey<Item> tag) {
|
||||
return replacementMap.getPreferredItemByTag(tag);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TagKey<Item> getPreferredTagByItem(@Nullable ResourceLocation item) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return replacementMap.getPreferredTag(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceIngredient(JsonElement element) {
|
||||
AtomicBoolean changed = new AtomicBoolean(false);
|
||||
|
||||
JsonUtils.arrayForEach(element, JsonObject.class, json -> {
|
||||
if (json.get(ITEM) instanceof JsonPrimitive primitive) {
|
||||
ResourceLocation item = ResourceLocation.tryParse(primitive.getAsString());
|
||||
TagKey<Item> tag = getPreferredTagByItem(item);
|
||||
if (tag != null) {
|
||||
json.remove(ITEM);
|
||||
json.addProperty(TAG, tag.location().toString());
|
||||
changed.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return changed.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceResult(JsonElement element) {
|
||||
AtomicBoolean changed = new AtomicBoolean(false);
|
||||
|
||||
JsonUtils.arrayForEach(element, JsonObject.class, json -> {
|
||||
if (json.get(ITEM) instanceof JsonPrimitive primitive) {
|
||||
ResourceLocation item = ResourceLocation.tryParse(primitive.getAsString());
|
||||
ResourceLocation replacement = getReplacementForItem(item);
|
||||
if (replacement != null) {
|
||||
json.addProperty(ITEM, replacement.toString());
|
||||
changed.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return changed.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(String property) {
|
||||
return currentRecipe.has(property);
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeTransformContext;
|
||||
import com.almostreliable.unified.api.ReplacementFallbackStrategy;
|
||||
import com.almostreliable.unified.fallbacks.StoneStrataFallbackStrategy;
|
||||
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;
|
||||
import java.util.*;
|
||||
|
||||
public class RecipeTransformContextImpl implements RecipeTransformContext {
|
||||
|
||||
private final Collection<String> modPriorities;
|
||||
private final TagMap tagMap;
|
||||
private final Map<ResourceLocation, TagKey<Item>> itemToTagMapping;
|
||||
/**
|
||||
* Cache for replacements. Key is the item to replace, value is the replacement.
|
||||
*/
|
||||
private final Map<ResourceLocation, ResourceLocation> replacementCache = new HashMap<>();
|
||||
private final Set<ResourceLocation> invalidCache = new HashSet<>();
|
||||
// TODO - In the future this may be a list of multiple fallbacks.
|
||||
private final ReplacementFallbackStrategy fallbackStrategy = new StoneStrataFallbackStrategy();
|
||||
|
||||
|
||||
public RecipeTransformContextImpl(TagMap tagMap, Map<ResourceLocation, TagKey<Item>> itemToTagMapping, List<String> modPriorities) {
|
||||
this.tagMap = tagMap;
|
||||
this.itemToTagMapping = itemToTagMapping;
|
||||
this.modPriorities = modPriorities;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String findReplacement(String id) {
|
||||
ResourceLocation asLocation = new ResourceLocation(id);
|
||||
if(invalidCache.contains(asLocation)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResourceLocation replacement = replacementCache.get(asLocation);
|
||||
if(replacement != null) {
|
||||
return replacement.toString();
|
||||
}
|
||||
|
||||
TagKey<Item> tag = itemToTagMapping.get(asLocation);
|
||||
if (!Registry.ITEM.containsKey(asLocation) || tag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResourceLocation modReplacement = computeReplacement(asLocation, tag);
|
||||
if(modReplacement == null || modReplacement.equals(asLocation)) {
|
||||
invalidCache.add(asLocation);
|
||||
return null;
|
||||
}
|
||||
|
||||
replacementCache.put(asLocation, modReplacement);
|
||||
AlmostUnified.LOG.info("########### {} -> {}", id, modReplacement.toString());
|
||||
return modReplacement.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation computeReplacement(ResourceLocation item, TagKey<Item> tag) {
|
||||
for (String mod : modPriorities) {
|
||||
if(mod.equals(item.getNamespace())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ResourceLocation> sameModItems = tagMap
|
||||
.getItems(tag)
|
||||
.stream()
|
||||
.filter(i -> i.getNamespace().equals(mod) && Registry.ITEM.containsKey(i))
|
||||
.toList();
|
||||
if(sameModItems.size() == 1) {
|
||||
return sameModItems.get(0);
|
||||
}
|
||||
|
||||
if(sameModItems.size() > 1) {
|
||||
ResourceLocation fallback = fallbackStrategy.getFallback(item, tag, sameModItems, tagMap);
|
||||
if(fallback != null) {
|
||||
if(fallback.equals(item)) {
|
||||
throw new IllegalStateException("Fallback for " + item + " is the same as the item itself. This is not allowed.");
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.almostreliable.unified;
|
||||
|
||||
import com.almostreliable.unified.api.ReplacementFallbackStrategy;
|
||||
import com.almostreliable.unified.fallbacks.StoneStrataFallbackStrategy;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReplacementMap {
|
||||
|
||||
private final Collection<String> modPriorities;
|
||||
private final TagMap tagMap;
|
||||
private final Map<ResourceLocation, TagKey<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) {
|
||||
this.tagMap = tagMap;
|
||||
this.itemToTagMapping = itemToTagMapping;
|
||||
this.modPriorities = modPriorities;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TagKey<Item> getPreferredTag(ResourceLocation item) {
|
||||
return itemToTagMapping.get(item);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getReplacementForItem(ResourceLocation item) {
|
||||
TagKey<Item> tag = getPreferredTag(item);
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResourceLocation preferredItem = getPreferredItemByTag(tag, item.getNamespace());
|
||||
if (item.equals(preferredItem)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return preferredItem;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getPreferredItemByTag(TagKey<Item> tag) {
|
||||
return getPreferredItemByTag(tag, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getPreferredItemByTag(TagKey<Item> tag, @Nullable String ignoredNamespace) {
|
||||
for (String mod : modPriorities) {
|
||||
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 && !mod.equals(ignoredNamespace)) {
|
||||
ResourceLocation fallback = fallbackStrategy.getFallback(tag, sameModItems, tagMap);
|
||||
if (fallback != null) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -35,7 +35,11 @@ public class TagMap {
|
|||
Tag<? extends Holder<?>> holderTag = entry.getValue();
|
||||
|
||||
for (Holder<?> holder : holderTag.getValues()) {
|
||||
holder.unwrapKey().map(ResourceKey::location).ifPresent(itemId -> tagMap.put(tag, itemId));
|
||||
holder
|
||||
.unwrapKey()
|
||||
.map(ResourceKey::location)
|
||||
.filter(Registry.ITEM::containsKey)
|
||||
.ifPresent(itemId -> tagMap.put(tag, itemId));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.almostreliable.unified.api;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface RecipeContext {
|
||||
|
||||
@Nullable
|
||||
ResourceLocation getReplacementForItem(@Nullable ResourceLocation item);
|
||||
|
||||
@Nullable
|
||||
ResourceLocation getPreferredItemByTag(TagKey<Item> tag);
|
||||
|
||||
@Nullable
|
||||
TagKey<Item> getPreferredTagByItem(@Nullable ResourceLocation item);
|
||||
|
||||
boolean replaceIngredient(JsonElement element);
|
||||
|
||||
boolean replaceResult(JsonElement element);
|
||||
|
||||
ResourceLocation getType();
|
||||
|
||||
ResourceLocation getId();
|
||||
|
||||
// String getIterateProperty();
|
||||
|
||||
boolean hasProperty(String property);
|
||||
|
||||
default String getModId() {
|
||||
return getType().getNamespace();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.almostreliable.unified.api;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface RecipeHandler {
|
||||
|
||||
void transformRecipe(JsonObject json, RecipeContext context);
|
||||
|
||||
default String getName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package com.almostreliable.unified.api;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface RecipeTransformContext {
|
||||
|
||||
@Nullable
|
||||
String findReplacement(String id);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package com.almostreliable.unified.api;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface RecipeTransformer {
|
||||
@Nullable
|
||||
JsonElement transformRecipe(JsonElement json, RecipeTransformContext context);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package com.almostreliable.unified.api;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface RecipeTransformerFactory {
|
||||
@Nullable
|
||||
RecipeTransformer create(ResourceLocation type, String property);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.almostreliable.unified.api;
|
||||
|
||||
import com.almostreliable.unified.AlmostUnified;
|
||||
import com.almostreliable.unified.api.RecipeTransformerFactory;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class RecipeTransformerRegistry {
|
||||
private static final Map<ResourceLocation, RecipeTransformerFactory> FACTORIES = new HashMap<>();
|
||||
|
||||
public static void registerFactory(ResourceLocation type, RecipeTransformerFactory factory) {
|
||||
Objects.requireNonNull(type, "type cannot be null");
|
||||
Objects.requireNonNull(factory, "factory cannot be null");
|
||||
|
||||
if (FACTORIES.containsKey(type)) {
|
||||
AlmostUnified.LOG.warn("Overwriting transformer factory for {} with {}",
|
||||
type,
|
||||
factory.getClass().getName());
|
||||
}
|
||||
|
||||
FACTORIES.put(type, factory);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static RecipeTransformerFactory getFactory(ResourceLocation type) {
|
||||
return FACTORIES.get(type);
|
||||
}
|
||||
|
||||
public static RecipeTransformerFactory getOrDefault(ResourceLocation type, RecipeTransformerFactory defaultFactory) {
|
||||
return FACTORIES.getOrDefault(type, defaultFactory);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@ public interface ReplacementFallbackStrategy {
|
|||
/**
|
||||
* Determine a fallback for the given item.
|
||||
*
|
||||
* @param lookupItem the item to lookup
|
||||
* @param tag the tag to replace the item with
|
||||
* @param potentialItems the potential items to replace with
|
||||
* @param tags the tag map to use for lookup
|
||||
|
@ -20,5 +19,5 @@ public interface ReplacementFallbackStrategy {
|
|||
* @throws IllegalStateException if returning the lookupItem
|
||||
*/
|
||||
@Nullable
|
||||
ResourceLocation getFallback(ResourceLocation lookupItem, TagKey<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags);
|
||||
ResourceLocation getFallback(TagKey<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Comparator;
|
|||
// TODO use config and not this :D
|
||||
public class StoneStrataFallbackStrategy implements ReplacementFallbackStrategy {
|
||||
@Override
|
||||
public ResourceLocation getFallback(ResourceLocation lookupItem, TagKey<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags) {
|
||||
public ResourceLocation getFallback(TagKey<Item> tag, Collection<ResourceLocation> potentialItems, TagMap tags) {
|
||||
if (tag.location().getPath().contains("ores")) {
|
||||
return potentialItems
|
||||
.stream()
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package com.almostreliable.unified.handler;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeContext;
|
||||
import com.almostreliable.unified.api.RecipeHandler;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class GenericRecipeHandler implements RecipeHandler {
|
||||
public static final GenericRecipeHandler INSTANCE = new GenericRecipeHandler();
|
||||
private final Set<String> inputKeys = Set.of(RecipeConstants.INPUT,
|
||||
RecipeConstants.INGREDIENT,
|
||||
RecipeConstants.INGREDIENTS);
|
||||
private final Set<String> outputKeys = Set.of(RecipeConstants.OUTPUT,
|
||||
RecipeConstants.RESULT,
|
||||
RecipeConstants.RESULTS);
|
||||
|
||||
public boolean hasInputOrOutputProperty(RecipeContext property) {
|
||||
for (String inputKey : inputKeys) {
|
||||
if (property.hasProperty(inputKey)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (String outputKey : outputKeys) {
|
||||
if (property.hasProperty(outputKey)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformRecipe(JsonObject json, RecipeContext context) {
|
||||
for (String inputKey : inputKeys) {
|
||||
if (json.has(inputKey)) {
|
||||
context.replaceIngredient(json.get(inputKey));
|
||||
}
|
||||
}
|
||||
|
||||
for (String outputKey : outputKeys) {
|
||||
JsonElement jsonElement = json.get(outputKey);
|
||||
if (jsonElement instanceof JsonPrimitive) {
|
||||
ResourceLocation item = context.getReplacementForItem(ResourceLocation.tryParse(jsonElement.getAsString()));
|
||||
if (item != null) {
|
||||
json.addProperty(outputKey, item.toString());
|
||||
}
|
||||
} else if (jsonElement != null) {
|
||||
// Forge patched recipe results to also allow JsonObjects. See SimpleCookingSerializer::fromJson as an example.
|
||||
context.replaceResult(jsonElement);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.almostreliable.unified.handler;
|
||||
|
||||
public class RecipeConstants {
|
||||
public static final String ITEM = "item";
|
||||
public static final String TAG = "tag";
|
||||
public static final String INPUT = "input";
|
||||
public static final String INGREDIENT = "ingredient";
|
||||
public static final String INGREDIENTS = "ingredients";
|
||||
public static final String OUTPUT = "output";
|
||||
public static final String RESULT = "result";
|
||||
public static final String RESULTS = "results";
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.almostreliable.unified.handler;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeContext;
|
||||
import com.almostreliable.unified.api.RecipeHandler;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RecipeHandlerFactory {
|
||||
private final Map<ResourceLocation, RecipeHandler> transformersByType = new HashMap<>();
|
||||
|
||||
@Nullable
|
||||
public RecipeHandler create(RecipeContext context) {
|
||||
RecipeHandler transformer = transformersByType.get(context.getType());
|
||||
if (transformer != null) {
|
||||
return transformer;
|
||||
}
|
||||
|
||||
if (context.hasProperty(ShapedRecipeKeyHandler.PATTERN_PROPERTY) &&
|
||||
context.hasProperty(ShapedRecipeKeyHandler.KEY_PROPERTY)) {
|
||||
return ShapedRecipeKeyHandler.INSTANCE;
|
||||
}
|
||||
|
||||
if (GenericRecipeHandler.INSTANCE.hasInputOrOutputProperty(context)) {
|
||||
return GenericRecipeHandler.INSTANCE;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void register(ResourceLocation type, RecipeHandler transformer) {
|
||||
transformersByType.put(type, transformer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.almostreliable.unified.handler;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeContext;
|
||||
import com.almostreliable.unified.api.RecipeHandler;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class ShapedRecipeKeyHandler implements RecipeHandler {
|
||||
public static final RecipeHandler INSTANCE = new ShapedRecipeKeyHandler();
|
||||
public static final String PATTERN_PROPERTY = "pattern";
|
||||
public static final String KEY_PROPERTY = "key";
|
||||
|
||||
@Override
|
||||
public void transformRecipe(JsonObject json, RecipeContext context) {
|
||||
if (json.get(KEY_PROPERTY) instanceof JsonObject object) {
|
||||
for (var entry : object.entrySet()) {
|
||||
context.replaceIngredient(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
JsonElement result = json.get("result");
|
||||
if (result != null) {
|
||||
context.replaceResult(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.almostreliable.unified.handler.ie;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeContext;
|
||||
import com.almostreliable.unified.api.RecipeHandler;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class IEBaseRecipeHandler implements RecipeHandler {
|
||||
|
||||
@Override
|
||||
public void transformRecipe(JsonObject json, RecipeContext context) {
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.almostreliable.unified.transformer;
|
||||
package com.almostreliable.unified.handler.ie;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.almostreliable.unified.handler;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,34 +0,0 @@
|
|||
package com.almostreliable.unified.transformer;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeTransformer;
|
||||
import com.almostreliable.unified.api.RecipeTransformContext;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class GenericRecipeTransformer implements RecipeTransformer {
|
||||
protected void replaceItems(JsonElement element, RecipeTransformContext context) {
|
||||
if (element instanceof JsonObject asObject) {
|
||||
if (asObject.has("item")) {
|
||||
String newItem = context.findReplacement(asObject.get("item").getAsString());
|
||||
if (newItem != null) {
|
||||
asObject.addProperty("item", newItem);
|
||||
}
|
||||
}
|
||||
} else if (element instanceof JsonArray asArray) {
|
||||
for (JsonElement innerElement : asArray) {
|
||||
replaceItems(innerElement, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JsonElement transformRecipe(JsonElement json, RecipeTransformContext context) {
|
||||
// TODO refactor
|
||||
replaceItems(json, context);
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package com.almostreliable.unified.transformer;
|
||||
|
||||
import com.almostreliable.unified.api.RecipeTransformer;
|
||||
import com.almostreliable.unified.api.RecipeTransformerFactory;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class GenericRecipeTransformerFactory implements RecipeTransformerFactory {
|
||||
|
||||
private final GenericRecipeTransformer transformer = new GenericRecipeTransformer();
|
||||
private final Set<String> inputKeys = Set.of("input", "ingredient", "ingredients");
|
||||
private final Set<String> outputKeys = Set.of("output", "result", "results");
|
||||
|
||||
@Override
|
||||
public RecipeTransformer create(ResourceLocation type, String property) {
|
||||
if (inputKeys.contains(property) || outputKeys.contains(property)) {
|
||||
return transformer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class JsonUtils {
|
||||
public static JsonArray arrayOrSelf(@Nullable JsonElement element) {
|
||||
if (element == null) {
|
||||
return new JsonArray();
|
||||
}
|
||||
|
||||
if (element.isJsonArray()) {
|
||||
return element.getAsJsonArray();
|
||||
}
|
||||
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(element);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static <T extends JsonElement> void arrayForEach(@Nullable JsonElement element, Class<T> filter, Consumer<T> consumer) {
|
||||
for (JsonElement e : arrayOrSelf(element)) {
|
||||
if (filter.isInstance(e)) {
|
||||
consumer.accept(filter.cast(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.almostreliable.unified.utils;
|
||||
|
||||
import com.almostreliable.unified.BuildConfig;
|
||||
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;
|
||||
|
||||
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 TagKey<Item> toItemTag(@Nullable String tag) {
|
||||
if (tag == null) {
|
||||
return UNUSED_TAG;
|
||||
}
|
||||
|
||||
ResourceLocation rl = ResourceLocation.tryParse(tag);
|
||||
if (rl == null) {
|
||||
return UNUSED_TAG;
|
||||
}
|
||||
|
||||
return TagKey.create(Registry.ITEM_REGISTRY, rl);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue