Update crafting recipe combinations calculation

This commit is contained in:
AJ Ferguson 2019-11-29 02:16:52 -09:00
parent e7a1063ee2
commit 8a589129f0

View file

@ -39,6 +39,8 @@ import lombok.EqualsAndHashCode;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.TranslatorsInit; import org.geysermc.connector.network.translators.TranslatorsInit;
import org.geysermc.connector.network.translators.item.ItemEntry;
import org.geysermc.connector.utils.Toolbox;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -54,8 +56,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
case CRAFTING_SHAPELESS: { case CRAFTING_SHAPELESS: {
ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData(); ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
ItemData output = TranslatorsInit.getItemTranslator().translateToBedrock(shapelessRecipeData.getResult()); ItemData output = TranslatorsInit.getItemTranslator().translateToBedrock(shapelessRecipeData.getResult());
List<ItemData[]> inputList = combinations(shapelessRecipeData.getIngredients()); ItemData[][] inputCombinations = combinations(shapelessRecipeData.getIngredients());
for (ItemData[] inputs : inputList) { for (ItemData[] inputs : inputCombinations) {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(), craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(),
inputs, new ItemData[]{output}, uuid, "crafting_table", 0)); inputs, new ItemData[]{output}, uuid, "crafting_table", 0));
@ -65,8 +67,8 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
case CRAFTING_SHAPED: { case CRAFTING_SHAPED: {
ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData(); ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
ItemData output = TranslatorsInit.getItemTranslator().translateToBedrock(shapedRecipeData.getResult()); ItemData output = TranslatorsInit.getItemTranslator().translateToBedrock(shapedRecipeData.getResult());
List<ItemData[]> inputList = combinations(shapedRecipeData.getIngredients()); ItemData[][] inputCombinations = combinations(shapedRecipeData.getIngredients());
for (ItemData[] inputs : inputList) { for (ItemData[] inputs : inputCombinations) {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(), craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(),
shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), inputs, shapedRecipeData.getWidth(), shapedRecipeData.getHeight(), inputs,
@ -79,37 +81,45 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
session.getUpstream().sendPacket(craftingDataPacket); session.getUpstream().sendPacket(craftingDataPacket);
} }
private List<ItemData[]> combinations(Ingredient[] ingredients) { private ItemData[][] combinations(Ingredient[] ingredients) {
ItemData[][] squashed = new ItemData[ingredients.length][]; Map<Set<ItemData>, Set<Integer>> squashedOptions = new HashMap<>();
for (int i = 0; i < ingredients.length; i++) { for (int i = 0; i < ingredients.length; i++) {
if (ingredients[i].getOptions().length == 0) { if (ingredients[i].getOptions().length == 0) {
squashed[i] = new ItemData[]{ItemData.AIR}; squashedOptions.computeIfAbsent(Collections.singleton(ItemData.AIR), k -> new HashSet<>()).add(i);
continue; continue;
} }
Ingredient ingredient = ingredients[i]; Ingredient ingredient = ingredients[i];
Map<GroupedItem, List<ItemData>> groupedByIds = Arrays.stream(ingredient.getOptions()) Map<GroupedItem, List<ItemData>> groupedByIds = Arrays.stream(ingredient.getOptions())
.map(item -> TranslatorsInit.getItemTranslator().translateToBedrock(item)) .map(item -> TranslatorsInit.getItemTranslator().translateToBedrock(item))
.collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag()))); .collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag())));
squashed[i] = new ItemData[groupedByIds.size()]; Set<ItemData> optionSet = new HashSet<>(groupedByIds.size());
int index = 0;
for (Map.Entry<GroupedItem, List<ItemData>> entry : groupedByIds.entrySet()) { for (Map.Entry<GroupedItem, List<ItemData>> entry : groupedByIds.entrySet()) {
if (entry.getValue().size() > 1) { if (entry.getValue().size() > 1) {
GroupedItem groupedItem = entry.getKey(); GroupedItem groupedItem = entry.getKey();
squashed[i][index++] = ItemData.of(groupedItem.id, (short) -1, groupedItem.count, groupedItem.tag); int idCount = 0;
//not optimal
for (ItemEntry itemEntry : Toolbox.ITEM_ENTRIES.valueCollection()) {
if (itemEntry.getBedrockId() == groupedItem.id) {
idCount++;
}
}
if (entry.getValue().size() < idCount) {
optionSet.addAll(entry.getValue());
} else {
optionSet.add(ItemData.of(groupedItem.id, (short) -1, groupedItem.count, groupedItem.tag));
}
} else { } else {
ItemData item = entry.getValue().get(0); ItemData item = entry.getValue().get(0);
squashed[i][index++] = item; optionSet.add(item);
} }
} }
squashedOptions.computeIfAbsent(optionSet, k -> new HashSet<>()).add(i);
} }
int[] sizeArray = new int[squashed.length]; int totalCombinations = 1;
int[] counterArray = new int[squashed.length]; for (Set optionSet : squashedOptions.keySet()) {
int totalCombinationCount = 1; totalCombinations *= optionSet.size();
for(int i = 0; i < squashed.length; i++) {
sizeArray[i] = squashed[i].length;
totalCombinationCount *= squashed[i].length;
} }
if (totalCombinationCount > 10000) { if (totalCombinations > 500) {
ItemData[] translatedItems = new ItemData[ingredients.length]; ItemData[] translatedItems = new ItemData[ingredients.length];
for (int i = 0; i < ingredients.length; i++) { for (int i = 0; i < ingredients.length; i++) {
if (ingredients[i].getOptions().length > 0) { if (ingredients[i].getOptions().length > 0) {
@ -118,25 +128,27 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
translatedItems[i] = ItemData.AIR; translatedItems[i] = ItemData.AIR;
} }
} }
return Collections.singletonList(translatedItems); return new ItemData[][]{translatedItems};
} }
List<ItemData[]> combinationList = new ArrayList<>(totalCombinationCount); List<Set<ItemData>> sortedSets = new ArrayList<>(squashedOptions.keySet());
for (int countdown = totalCombinationCount; countdown > 0; --countdown) { sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder()));
ItemData[] translatedItems = new ItemData[squashed.length]; ItemData[][] combinations = new ItemData[totalCombinations][ingredients.length];
for(int i = 0; i < squashed.length; ++i) { int x = 1;
if (squashed[i].length > 0) for (Set<ItemData> set : sortedSets) {
translatedItems[i] = squashed[i][counterArray[i]]; Set<Integer> slotSet = squashedOptions.get(set);
} int i = 0;
combinationList.add(translatedItems); for (ItemData item : set) {
for(int incIndex = squashed.length - 1; incIndex >= 0; --incIndex) { for (int j = 0; j < totalCombinations / set.size(); j++) {
if(counterArray[incIndex] + 1 < sizeArray[incIndex]) { final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x);
++counterArray[incIndex]; for (int slot : slotSet) {
break; combinations[comboIndex][slot] = item;
}
counterArray[incIndex] = 0;
} }
} }
return combinationList; i++;
}
x *= set.size();
}
return combinations;
} }
@EqualsAndHashCode @EqualsAndHashCode