Performance improvements (#35)

Co-authored-by: LLytho <main@lytho.dev>
Co-authored-by: Relentless <relentless@rlnt.dev>
This commit is contained in:
embeddedt 2023-03-09 13:47:21 -05:00 committed by Relentless
parent 88687ff027
commit f88172c8fc
No known key found for this signature in database
GPG key ID: 50C5FD225130D790
3 changed files with 46 additions and 18 deletions

View file

@ -6,6 +6,7 @@ import com.almostreliable.unified.utils.JsonCompare;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
@ -20,6 +21,7 @@ public class DuplicationConfig extends Config {
private final Set<Pattern> ignoreRecipeTypes;
private final Set<Pattern> ignoreRecipes;
private final boolean strictMode;
private final HashMap<ResourceLocation, Boolean> ignoredRecipeTypesCache;
public DuplicationConfig(JsonCompare.CompareSettings defaultRules, LinkedHashMap<ResourceLocation, JsonCompare.CompareSettings> overrideRules, Set<Pattern> ignoreRecipeTypes, Set<Pattern> ignoreRecipes, boolean strictMode) {
this.defaultRules = defaultRules;
@ -27,11 +29,38 @@ public class DuplicationConfig extends Config {
this.ignoreRecipeTypes = ignoreRecipeTypes;
this.ignoreRecipes = ignoreRecipes;
this.strictMode = strictMode;
this.ignoredRecipeTypesCache = new HashMap<>();
}
public boolean shouldIgnoreRecipe(RecipeLink recipe) {
return ignoreRecipeTypes.stream().anyMatch(pattern -> pattern.matcher(recipe.getType().toString()).matches()) ||
ignoreRecipes.stream().anyMatch(pattern -> pattern.matcher(recipe.getId().toString()).matches());
if (isRecipeTypeIgnored(recipe)) {
return true;
}
for (Pattern ignoreRecipePattern : ignoreRecipes) {
if (ignoreRecipePattern.matcher(recipe.getId().toString()).matches()) {
return true;
}
}
return false;
}
/**
* Checks if the recipe type is ignored. This is cached to avoid having to recompute the regex for every recipe.
*
* @param recipe The recipe to check
* @return True if the recipe type is ignored, false otherwise
*/
private boolean isRecipeTypeIgnored(RecipeLink recipe) {
return ignoredRecipeTypesCache.computeIfAbsent(recipe.getType(), type -> {
for (Pattern ignorePattern : ignoreRecipeTypes) {
if (ignorePattern.matcher(type.toString()).matches()) {
return true;
}
}
return false;
});
}
public JsonCompare.CompareSettings getCompareSettings(ResourceLocation type) {
@ -42,6 +71,10 @@ public class DuplicationConfig extends Config {
return strictMode;
}
public void clearCache() {
ignoredRecipeTypesCache.clear();
}
public static class Serializer extends Config.Serializer<DuplicationConfig> {
public static final String DEFAULT_DUPLICATE_RULES = "defaultDuplicateRules";
public static final String OVERRIDE_DUPLICATE_RULES = "overrideDuplicateRules";

View file

@ -8,6 +8,7 @@ import com.almostreliable.unified.utils.JsonCompare;
import com.almostreliable.unified.utils.JsonQuery;
import com.almostreliable.unified.utils.RecipeTypePropertiesLogger;
import com.almostreliable.unified.utils.ReplacementMap;
import com.google.common.base.Stopwatch;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.gson.JsonArray;
@ -54,6 +55,7 @@ public class RecipeTransformer {
* @return The result of the transformation.
*/
public Result transformRecipes(Map<ResourceLocation, JsonElement> recipes, boolean skipClientTracking) {
Stopwatch transformationTimer = Stopwatch.createStarted();
AlmostUnified.LOG.warn("Recipe count: " + recipes.size());
ClientRecipeTracker.RawBuilder tracker = skipClientTracking ? null : new ClientRecipeTracker.RawBuilder();
@ -72,7 +74,8 @@ public class RecipeTransformer {
result.addAll(recipeLinks);
});
AlmostUnified.LOG.warn("Recipe count afterwards: " + recipes.size());
AlmostUnified.LOG.warn("Recipe count afterwards: " + recipes.size() + " (done in " + transformationTimer.stop() + ")");
duplicationConfig.clearCache();
if (tracker != null) recipes.putAll(tracker.compute());
return result;
}

View file

@ -90,24 +90,16 @@ public final class JsonCompare {
public static boolean matches(JsonObject first, JsonObject second, CompareSettings compareSettings) {
Collection<String> ignoredFields = compareSettings.getIgnoredFields();
List<String> firstValidKeys = first
.keySet()
.stream()
.filter(key -> !ignoredFields.contains(key))
.toList();
List<String> secondValidKeys = second
.keySet()
.stream()
.filter(key -> !ignoredFields.contains(key))
.toList();
if (ignoredFields.isEmpty() && first.size() != second.size()) {
return false;
}
if (firstValidKeys.size() != secondValidKeys.size()) return false;
for (Map.Entry<String, JsonElement> firstEntry : first.entrySet()) {
if (ignoredFields.contains(firstEntry.getKey())) continue;
for (String firstKey : firstValidKeys) {
JsonElement firstElem = first.get(firstKey);
JsonElement secondElem = second.get(firstKey);
JsonElement firstElem = firstEntry.getValue();
JsonElement secondElem = second.get(firstEntry.getKey());
// the second element can still be null although the valid keys have the same size
if (secondElem == null) return false;
// sanitize elements for implicit counts of 1