Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions xplat/src/main/java/dev/emi/emi/EmiRenderHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,13 @@ public static void renderAmount(EmiDrawContext context, int x, int y, Text amoun
context.pop();
}

public static void renderText(EmiDrawContext context, int x, int y, Text text) {
context.push();
context.matrices().translate(0, 0, 200);
context.drawTextWithShadow(text, x + 1, y + 5, -1);
context.pop();
}

public static void renderIngredient(EmiIngredient ingredient, EmiDrawContext context, int x, int y) {
RenderSystem.enableDepthTest();
context.push();
Expand Down
15 changes: 3 additions & 12 deletions xplat/src/main/java/dev/emi/emi/VanillaPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,7 @@
import dev.emi.emi.api.recipe.EmiWorldInteractionRecipe;
import dev.emi.emi.api.render.EmiRenderable;
import dev.emi.emi.api.render.EmiTexture;
import dev.emi.emi.api.stack.Comparison;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiRegistryAdapter;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.stack.FluidEmiStack;
import dev.emi.emi.api.stack.ItemEmiStack;
import dev.emi.emi.api.stack.ListEmiIngredient;
import dev.emi.emi.api.stack.TagEmiIngredient;
import dev.emi.emi.api.stack.*;
import dev.emi.emi.api.widget.Bounds;
import dev.emi.emi.api.widget.GeneratedSlotWidget;
import dev.emi.emi.config.EffectLocation;
Expand Down Expand Up @@ -95,10 +88,7 @@
import dev.emi.emi.runtime.EmiDrawContext;
import dev.emi.emi.runtime.EmiLog;
import dev.emi.emi.runtime.EmiReloadLog;
import dev.emi.emi.stack.serializer.FluidEmiStackSerializer;
import dev.emi.emi.stack.serializer.ItemEmiStackSerializer;
import dev.emi.emi.stack.serializer.ListEmiIngredientSerializer;
import dev.emi.emi.stack.serializer.TagEmiIngredientSerializer;
import dev.emi.emi.stack.serializer.*;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
Expand Down Expand Up @@ -217,6 +207,7 @@ public void initialize(EmiInitRegistry registry) {
registry.addIngredientSerializer(FluidEmiStack.class, new FluidEmiStackSerializer());
registry.addIngredientSerializer(TagEmiIngredient.class, new TagEmiIngredientSerializer());
registry.addIngredientSerializer(ListEmiIngredient.class, new ListEmiIngredientSerializer());
registry.addIngredientSerializer(SearchEmiIngredient.class, new SearchEmiIngredientSerializer());

registry.addRegistryAdapter(EmiRegistryAdapter.simple(Item.class, EmiPort.getItemRegistry(), EmiStack::of));
registry.addRegistryAdapter(EmiRegistryAdapter.simple(Fluid.class, EmiPort.getFluidRegistry(), EmiStack::of));
Expand Down
4 changes: 4 additions & 0 deletions xplat/src/main/java/dev/emi/emi/api/stack/EmiIngredient.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,8 @@ public static EmiIngredient of(List<? extends EmiIngredient> list, long amount)
return EmiTags.getIngredient(tagType, list.stream().flatMap(i -> i.getEmiStacks().stream()).toList(), amount);
}
}

public static EmiIngredient of(String text, List<? extends EmiIngredient> results) {
return new SearchEmiIngredient(text, results);
}
}
106 changes: 106 additions & 0 deletions xplat/src/main/java/dev/emi/emi/api/stack/SearchEmiIngredient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package dev.emi.emi.api.stack;

import com.google.common.collect.Lists;
import dev.emi.emi.EmiPort;
import dev.emi.emi.api.render.EmiRender;
import dev.emi.emi.screen.tooltip.EmiTextTooltipWrapper;
import dev.emi.emi.screen.tooltip.IngredientTooltipComponent;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.tooltip.TooltipComponent;
import org.jetbrains.annotations.ApiStatus;

import java.util.List;

@ApiStatus.Internal
public class SearchEmiIngredient implements EmiIngredient {
private final List<? extends EmiIngredient> results;
private final List<EmiStack> fullResults;

public final String content;

public SearchEmiIngredient(String content, List<? extends EmiIngredient> results) {
this.results = results;
this.fullResults = results.stream().flatMap(i -> i.getEmiStacks().stream()).toList();
if (fullResults.isEmpty()) {
throw new IllegalArgumentException("SearchEmiIngredient cannot be and empty search");
}

this.content = content;
}

@Override
public void render(DrawContext draw, int x, int y, float delta, int flags) {
int item = (int) (System.currentTimeMillis() / 1000 % results.size());
EmiIngredient current = results.get(item);
if ((flags & RENDER_ICON) != 0) {
current.render(draw, x, y, delta, -1 ^ RENDER_AMOUNT);
}
if ((flags & RENDER_INGREDIENT) != 0) {
EmiRender.renderIngredientIcon(this, draw, x, y);
}

// // Maybe render a couple of letters of the search above the icon
// EmiDrawContext context = EmiDrawContext.wrap(draw);
// EmiRenderHelper.renderText(context, x, y, EmiPort.literal(content.substring(0, 3)));
}

@Override
public boolean equals(Object obj) {
return obj instanceof SearchEmiIngredient ingredient && ingredient.content.equals(this.content);
}

@Override
public EmiIngredient copy() {
return new SearchEmiIngredient(content, results);
}

@Override
public long getAmount() {
return 1;
}

@Override
public EmiIngredient setAmount(long amount) {
return null;
}

@Override
public float getChance() {
return 1;
}

@Override
public EmiIngredient setChance(float chance) {
return null;
}

@Override
public List<EmiStack> getEmiStacks() {
return EmiStack.EMPTY.getEmiStacks();
}

@Override
public boolean isEmpty() {
return false;
}

@Override
public List<TooltipComponent> getTooltip() {
List<TooltipComponent> tooltip = Lists.newArrayList();
tooltip.add(new EmiTextTooltipWrapper(this, EmiPort.ordered(EmiPort.literal(content))));
tooltip.add(new IngredientTooltipComponent(results));
int item = (int) (System.currentTimeMillis() / 1000 % results.size());
tooltip.addAll(results.get(item).copy().setAmount(1).getTooltip());
return tooltip;
}

@ApiStatus.Internal
public String getContent() {
return content;
}

@ApiStatus.Internal
public List<? extends EmiIngredient> getResults() {
return results;
}
}
89 changes: 83 additions & 6 deletions xplat/src/main/java/dev/emi/emi/bom/BoM.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package dev.emi.emi.bom;

import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
Expand All @@ -12,6 +14,7 @@

import dev.emi.emi.EmiPort;
import dev.emi.emi.api.EmiApi;
import dev.emi.emi.api.recipe.EmiPlayerInventory;
import dev.emi.emi.api.recipe.EmiRecipe;
import dev.emi.emi.api.recipe.EmiResolutionRecipe;
import dev.emi.emi.api.stack.EmiIngredient;
Expand All @@ -26,7 +29,10 @@

public class BoM {
private static RecipeDefaults defaults = new RecipeDefaults();
public static MaterialTree tree;
public static List<MaterialTree> trees = Lists.newArrayList();
public static int treeIndex = -1;
public static TreeCost combinedCost = new TreeCost();
public static TreeCost combinedProgress = new TreeCost();
public static Map<EmiIngredient, EmiRecipe> defaultRecipes = Maps.newHashMap();
public static Map<EmiIngredient, EmiRecipe> addedRecipes = Maps.newHashMap();
public static Set<EmiRecipe> disabledRecipes = Sets.newHashSet();
Expand Down Expand Up @@ -166,12 +172,70 @@ public static EmiRecipe getRecipe(EmiIngredient stack) {
}

public static void setGoal(EmiRecipe recipe) {
tree = new MaterialTree(recipe);
trees.clear();
trees.add(new MaterialTree(recipe));
treeIndex = 0;
craftingMode = false;
recalculate();
}

public static void addGoal(EmiRecipe recipe) {
if (trees.isEmpty()) {
setGoal(recipe);
return;
}
trees.add(new MaterialTree(recipe));
treeIndex = trees.size() - 1;
recalculate();
}

public static MaterialTree getTree() {
if (treeIndex < 0 || treeIndex >= trees.size()) {
return null;
}
return trees.get(treeIndex);
}

public static List<MaterialTree> getTrees() {
return trees;
}

public static void selectTree(int index) {
if (trees.isEmpty()) {
treeIndex = -1;
return;
}
treeIndex = Math.max(0, Math.min(index, trees.size() - 1));
}

public static void cycleTree(int delta) {
if (trees.isEmpty()) {
treeIndex = -1;
return;
}
int size = trees.size();
treeIndex = ((treeIndex + delta) % size + size) % size;
}

public static void removeTree(int index) {
if (index < 0 || index >= trees.size()) {
return;
}
trees.remove(index);
if (trees.isEmpty()) {
treeIndex = -1;
craftingMode = false;
} else {
treeIndex = Math.max(0, Math.min(treeIndex, trees.size() - 1));
}
recalculate();
}

public static void addResolution(EmiIngredient ingredient, EmiRecipe recipe) {
tree.addResolution(ingredient, recipe);
MaterialTree tree = getTree();
if (tree != null) {
tree.addResolution(ingredient, recipe);
}
}

public static boolean isDefaultRecipe(EmiIngredient stack, EmiRecipe recipe) {
Expand Down Expand Up @@ -227,12 +291,25 @@ public static void removeRecipe(EmiIngredient stack, EmiRecipe recipe) {
recalculate();
}

private static void recalculate() {
if (tree != null) {
tree.recalculate();
public static void calculateCombinedCosts(EmiPlayerInventory inventory) {
combinedProgress.clear();
for (MaterialTree tree : trees) {
tree.calculateProgress(inventory);
combinedProgress.merge(tree.cost);
}
combinedCost.clear();
for (MaterialTree tree : trees) {
tree.calculateCost();
combinedCost.merge(tree.cost);
}
}

private static void recalculate() {
for (MaterialTree tree : trees) {
tree.recalculate();
}
}

public static enum DefaultStatus {
EMPTY,
PARTIAL,
Expand Down
5 changes: 5 additions & 0 deletions xplat/src/main/java/dev/emi/emi/bom/MaterialTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ public MaterialTree(EmiRecipe recipe) {
recalculate();
}

public MaterialTree(MaterialNode goal, long batches) {
this.goal = goal;
this.batches = Math.max(1, batches);
}

public EmiRecipe getRecipe(EmiIngredient stack) {
EmiRecipe recipe = resolutions.get(stack);
if (recipe == null && !resolutions.containsKey(stack)) {
Expand Down
52 changes: 47 additions & 5 deletions xplat/src/main/java/dev/emi/emi/bom/TreeCost.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,61 @@ public class TreeCost {
public Map<EmiStack, FlatMaterialCost> remainders = Maps.newHashMap();
public Map<EmiStack, ChanceMaterialCost> chanceRemainders = Maps.newHashMap();

public void calculate(MaterialNode node, long batches) {
public void clear() {
costs.clear();
chanceCosts.clear();
remainders.clear();
chanceRemainders.clear();
}

public void merge(TreeCost other) {
for (FlatMaterialCost cost : other.costs.values()) {
FlatMaterialCost existing = costs.get(cost.ingredient);
if (existing == null) {
costs.put(cost.ingredient, new FlatMaterialCost(cost.ingredient, cost.amount));
} else {
existing.amount += cost.amount;
}
}
for (ChanceMaterialCost cost : other.chanceCosts.values()) {
ChanceMaterialCost existing = chanceCosts.get(cost.ingredient);
if (existing == null) {
existing = new ChanceMaterialCost(cost.ingredient, cost.amount, cost.chance);
chanceCosts.put(cost.ingredient, existing);
} else {
existing.merge(cost.amount, cost.chance);
}
existing.minBatch(cost.minBatch);
}
for (FlatMaterialCost remainder : other.remainders.values()) {
EmiStack key = (EmiStack) remainder.ingredient;
FlatMaterialCost existing = remainders.get(key);
if (existing == null) {
remainders.put(key, new FlatMaterialCost(key, remainder.amount));
} else {
existing.amount += remainder.amount;
}
}
for (ChanceMaterialCost remainder : other.chanceRemainders.values()) {
EmiStack key = (EmiStack) remainder.ingredient;
ChanceMaterialCost existing = chanceRemainders.get(key);
if (existing == null) {
existing = new ChanceMaterialCost(key, remainder.amount, remainder.chance);
chanceRemainders.put(key, existing);
} else {
existing.merge(remainder.amount, remainder.chance);
}
existing.minBatch(remainder.minBatch);
}
}

public void calculate(MaterialNode node, long batches) {
clear();
calculateCost(node, batches * node.amount, ChanceState.DEFAULT, false);
}

public void calculateProgress(MaterialNode node, long batches, EmiPlayerInventory inventory) {
costs.clear();
chanceCosts.clear();
remainders.clear();
chanceRemainders.clear();
clear();
for (EmiStack stack : inventory.inventory.values()) {
stack = stack.copy();
remainders.put(stack, new FlatMaterialCost(stack, stack.getAmount()));
Expand Down
Loading