Skip to content

Commit

Permalink
Merge branch '1.18' into feature/14-ce-workbench-recipes
Browse files Browse the repository at this point in the history
  • Loading branch information
paulyhedral committed Nov 30, 2024
2 parents 4993fd6 + 0c50d9c commit f62eb9a
Show file tree
Hide file tree
Showing 19 changed files with 383 additions and 73 deletions.
2 changes: 1 addition & 1 deletion .release-info/1.18/RELEASE_HASH
Original file line number Diff line number Diff line change
@@ -1 +1 @@
837abfbbb99c7be8a57552e1651f1c5addeba436
3f7a5625360952bcbd99e42b635469bff7a7f01c
2 changes: 1 addition & 1 deletion .release-info/1.18/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.38
0.1.5
9 changes: 9 additions & 0 deletions CHANGELOG/1.18/0.0.38.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 0.0.38

- `[FIX]` Remove lingering widgets when deleting a recipe from the queue
- `[NEW]` Enabled key bindings to manage display of craft list and shopping list
- `[FIX]` Fixed how recipes are looked up, so that some intermediates and raw materials
show up correctly
- `[NEW]` Enable shopping list display
- `[NEW]` Enable populating the shopping list
- `[FIX]` Fixed issue with keybinds triggering all the time
4 changes: 4 additions & 0 deletions CHANGELOG/1.18/0.1.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 0.1.1

- `[NEW]` The craft queue and shopping list overlays may now be positioned relative to the
right-edge or bottom-edge of the screen by specifying negative X or Y positions (respectively)
6 changes: 6 additions & 0 deletions CHANGELOG/1.18/0.1.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# 0.1.5

- `[NEW]` When an end product's recipe intermediates have multiple variations, the "least expensive"
one is chosen
- `[NEW]` Added hotkey to clear the shopping list
- `[NEW]` Items in the queue and shopping list are now sorted by name
7 changes: 0 additions & 7 deletions CHANGELOG/1.18/current.md
Original file line number Diff line number Diff line change
@@ -1,7 +0,0 @@
- `[FIX]` Remove lingering widgets when deleting a recipe from the queue
- `[NEW]` Enabled key bindings to manage display of craft list and shopping list
- `[FIX]` Fixed how recipes are looked up, so that some intermediates and raw materials
show up correctly
- `[NEW]` Enable shopping list display
- `[NEW]` Enable populating the shopping list
- `[FIX]` Fixed issue with keybinds triggering all the time
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,4 @@

## Contributing


Download it from [CurseForge](https://www.curseforge.com/minecraft/mc-mods/craft-tracker) or [Modrinth](https://modrinth.com/mod/craft-tracker).

Want to know more about the mod? Take a peek at the [wiki](https://github.com/sweetrpg/CraftTracker/wiki)!
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ forge_version_range=[40.2.17,)
minecraft_version_range=[1.18, 1.19)

curseforge_project_id=626455
curseforge_release_type=alpha
curseforge_release_type=beta

modrinth_project_id=6eqIziNz
modrinth_release_type=alpha
modrinth_release_type=beta

# JEI
jei_version=1.18.2:9.7.2.281
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ else if(KeyUtil.isKeyDown(event.getKey()) &&

handlePopulateShoppingList();
}
else if(KeyUtil.isKeyDown(event.getKey()) &&
ModKeyBindings.CLEAR_SHOPPING_LIST_MAPPING.matches(event.getKey(), event.getScanCode())) {
CraftTracker.LOGGER.debug("#onKeyInput: CLEAR_SHOPPING_LIST_MAPPING");

handleClearShoppingList();
}

return;
}
Expand Down Expand Up @@ -130,6 +136,15 @@ private static void handleToggleCraftList() {
}
}

private static void handleClearShoppingList() {
CraftTracker.LOGGER.debug("#handleClearShoppingList");

var player = Minecraft.getInstance().player;
var sMgr = ShoppingListManager.INSTANCE;

sMgr.clearItems(player);
}

private static void handlePopulateShoppingList() {
CraftTracker.LOGGER.debug("#handlePopulateShoppingList");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ public class CraftQueueOverlay {
CraftTracker.LOGGER.trace("CRAFT_QUEUE");

var mgr = CraftingQueueManager.INSTANCE;
var products = mgr.getEndProducts();
var products = mgr.getEndProducts().stream().sorted((i1, i2) -> {
var item1 = ForgeRegistries.ITEMS.getValue(i1.getItemId());
var item2 = ForgeRegistries.ITEMS.getValue(i2.getItemId());
return item1.getDescription().getString().compareTo(item2.getDescription().getString());
}).toList();

switch(CTRuntime.INSTANCE.queueOverlayRequestedState) {
case SHOW:
Expand Down Expand Up @@ -129,8 +133,13 @@ public class CraftQueueOverlay {
CraftTracker.LOGGER.trace("yPos (after intermediates title): {}", yPos);

// items
for(int i = 0; i < mgr.getIntermediates().size(); i++) {
var inter = mgr.getIntermediates().get(i);
var sortedIntermediates = mgr.getIntermediates().stream().sorted((i1, i2) -> {
var item1 = ForgeRegistries.ITEMS.getValue(i1.getItemId());
var item2 = ForgeRegistries.ITEMS.getValue(i2.getItemId());
return item1.getDescription().getString().compareTo(item2.getDescription().getString());
}).toList();
for(int i = 0; i < sortedIntermediates.size(); i++) {
var inter = sortedIntermediates.get(i);

var item = ForgeRegistries.ITEMS.getValue(inter.getItemId());
var stack = item.getDefaultInstance();
Expand Down Expand Up @@ -179,8 +188,13 @@ public class CraftQueueOverlay {
CraftTracker.LOGGER.trace("yPos (after materials title): {}", yPos);

// items
for(int i = 0; i < mgr.getRawMaterials().size(); i++) {
var m = mgr.getRawMaterials().get(i);
var sortedMaterials = mgr.getRawMaterials().stream().sorted((i1, i2) -> {
var item1 = ForgeRegistries.ITEMS.getValue(i1.getItemId());
var item2 = ForgeRegistries.ITEMS.getValue(i2.getItemId());
return item1.getDescription().getString().compareTo(item2.getDescription().getString());
}).toList();
for(int i = 0; i < sortedMaterials.size(); i++) {
var m = sortedMaterials.get(i);

var item = ForgeRegistries.ITEMS.getValue(m.getItemId());
var stack = item.getDefaultInstance();
Expand Down Expand Up @@ -229,8 +243,13 @@ public class CraftQueueOverlay {
CraftTracker.LOGGER.trace("yPos: {}", yPos);

// items
for(int i = 0; i < mgr.getFuel().size(); i++) {
var f = mgr.getFuel().get(i);
var sortedFuels = mgr.getFuel().stream().sorted((i1, i2) -> {
var item1 = ForgeRegistries.ITEMS.getValue(i1.getItemId());
var item2 = ForgeRegistries.ITEMS.getValue(i2.getItemId());
return item1.getDescription().getString().compareTo(item2.getDescription().getString());
}).toList();
for(int i = 0; i < sortedFuels.size(); i++) {
var f = sortedFuels.get(i);

var item = ForgeRegistries.ITEMS.getValue(f.getItemId());
var stack = item.getDefaultInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ public class ShoppingListOverlay {
break;
}


var x = ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_X.get();
if(x < 0) {
x = width - (ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_WIDTH.get() + Math.abs(x));
}
var y = ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_Y.get();
var olWidth = Math.min((ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_X.get() + ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_WIDTH.get()), width - 10);
var olHeight = Math.min((ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_Y.get() + ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_HEIGHT.get()), height - 10);
if(x < 0) {
y = width - (ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_HEIGHT.get() + Math.abs(y));
}
var olWidth = Math.min((x + ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_WIDTH.get()), width - 10);
var olHeight = Math.min((y + ConfigHandler.CLIENT.SHOPPING_LIST_OVERLAY_HEIGHT.get()), height - 10);
var backgroundColor = 0x5f5f5f5f; // TODO: get from config?
var borderColor = 0x1f1f1f1f; // TODO: get from config?

Expand Down Expand Up @@ -87,8 +92,13 @@ public class ShoppingListOverlay {
var inventory = Minecraft.getInstance().player.getInventory();

// items
for(int i = 0; i < mgr.getItems().size(); i++) {
var m = mgr.getItems().get(i);
var sortedItems = mgr.getItems().stream().sorted((i1, i2) -> {
var item1 = ForgeRegistries.ITEMS.getValue(i1.getItemId());
var item2 = ForgeRegistries.ITEMS.getValue(i2.getItemId());
return item1.getDescription().getString().compareTo(item2.getDescription().getString());
}).toList();
for(int i = 0; i < sortedItems.size(); i++) {
var m = sortedItems.get(i);

var item = ForgeRegistries.ITEMS.getValue(m.getItemId());
var stack = item.getDefaultInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ public ClientConfig(ForgeConfigSpec.Builder builder) {
builder.push("CraftQueue");

CRAFT_QUEUE_OVERLAY_HIDE_EMPTY = builder.comment("Sets whether the craft queue overlay should be displayed only when it has items in it.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_CRAFT_QUEUE_HIDE_EMPTY).define("craft_queue_hide_empty", true);
CRAFT_QUEUE_OVERLAY_X = builder.comment("Sets the X screen location for the craft queue overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_CRAFT_QUEUE_X).defineInRange("craft_queue_x", 10, 0, 10000);
CRAFT_QUEUE_OVERLAY_Y = builder.comment("Sets the Y screen location for the craft queue overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_CRAFT_QUEUE_Y).defineInRange("craft_queue_y", 60, 0, 10000);
CRAFT_QUEUE_OVERLAY_X = builder.comment("Sets the X screen location for the craft queue overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_CRAFT_QUEUE_X).defineInRange("craft_queue_x", 10, -1000, 10000);
CRAFT_QUEUE_OVERLAY_Y = builder.comment("Sets the Y screen location for the craft queue overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_CRAFT_QUEUE_Y).defineInRange("craft_queue_y", 60, -1000, 10000);
CRAFT_QUEUE_OVERLAY_WIDTH = builder.comment("Sets the width of the craft queue overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_CRAFT_QUEUE_WIDTH).defineInRange("craft_queue_width", 300, 100, 10000);
CRAFT_QUEUE_OVERLAY_HEIGHT = builder.comment("Sets the height of the craft queue overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_CRAFT_QUEUE_HEIGHT).defineInRange("craft_queue_height", 500, 100, 10000);

Expand All @@ -65,8 +65,8 @@ public ClientConfig(ForgeConfigSpec.Builder builder) {
builder.push("ShoppingList");

SHOPPING_LIST_OVERLAY_HIDE_EMPTY = builder.comment("Sets whether the 'shopping list' overlay should be displayed only when it has items in it.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_SHOPPING_LIST_HIDE_EMPTY).define("shopping_list_hide_empty", true);
SHOPPING_LIST_OVERLAY_X = builder.comment("Sets the X screen location for the 'shopping list' overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_SHOPPING_LIST_X).defineInRange("shopping_list_x", 10, 0, 10000);
SHOPPING_LIST_OVERLAY_Y = builder.comment("Sets the Y screen location for the 'shopping list' overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_SHOPPING_LIST_Y).defineInRange("shopping_list_y", 60, 0, 10000);
SHOPPING_LIST_OVERLAY_X = builder.comment("Sets the X screen location for the 'shopping list' overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_SHOPPING_LIST_X).defineInRange("shopping_list_x", -10, -1000, 10000);
SHOPPING_LIST_OVERLAY_Y = builder.comment("Sets the Y screen location for the 'shopping list' overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_SHOPPING_LIST_Y).defineInRange("shopping_list_y", 60, -1000, 10000);
SHOPPING_LIST_OVERLAY_WIDTH = builder.comment("Sets the width of the 'shopping list' overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_SHOPPING_LIST_WIDTH).defineInRange("shopping_list_width", 300, 100, 10000);
SHOPPING_LIST_OVERLAY_HEIGHT = builder.comment("Sets the height of the 'shopping list' overlay.").translation(Constants.TRANSLATION_KEY_CONFIG_CLIENT_SHOPPING_LIST_HEIGHT).defineInRange("shopping_list_height", 500, 100, 10000);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,7 @@ public void addProduct(Player player, ResourceLocation itemId, int quantity) {
endProducts.compute(itemId, (rl, p) -> p == null ? product :
new CraftingQueueProduct(p.getItemId(), p.getRecipes(), p.getQuantity() + quantity));

// CraftingQueueStorage.get(level).putData(itemId, quantity);

computeAll();

// PacketHandler.sendToPlayer(this.player, new UpdateCraftQueueData(this.getEndProducts()));
}
else {
CraftTracker.LOGGER.info("Not adding {} to queue, since there are no recipes for it.", itemId);
Expand Down Expand Up @@ -167,6 +163,10 @@ public void removeProduct(Player player, ResourceLocation itemId) {
CraftTracker.LOGGER.debug("CraftingQueueManager#removeProduct: {}", itemId);

this.endProducts.remove(itemId);

computeAll();

this.save(player);
}

public void removeProduct(Player player, ResourceLocation itemId, int quantity) {
Expand Down Expand Up @@ -307,7 +307,8 @@ public void computeRecipe(Recipe recipe, int recipeQuantity) {
});
}

this.computeRecipe(subRecipes.get(0), recipeQuantity);
int subIndex = RecipeUtil.chooseLeastExpensiveOf(subRecipes);
this.computeRecipe(subRecipes.get(subIndex), recipeQuantity);
}
});
}
Expand Down
116 changes: 108 additions & 8 deletions src/main/java/com/sweetrpg/crafttracker/common/util/RecipeUtil.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,67 @@
package com.sweetrpg.crafttracker.common.util;

import com.sweetrpg.crafttracker.CraftTracker;
import com.sweetrpg.crafttracker.common.lib.Constants;
import net.minecraft.client.Minecraft;
import net.minecraft.core.NonNullList;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.util.Tuple;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class RecipeUtil {

private static Map<ResourceLocation, Integer> ingredientCostsByTag = new HashMap<>();
private static Map<ResourceLocation, Integer> ingredientCostOverrides = new HashMap<>();

static {
var mgr = Minecraft.getInstance().getResourceManager();

var ingCostsResource = new ResourceLocation(Constants.MOD_ID, "ingredient-costs.properties");
try {
var costs = mgr.getResource(ingCostsResource);
var props = new Properties();
props.load(costs.getInputStream());
props.entrySet().forEach(entry -> {
var key = new ResourceLocation((String) entry.getKey());
var value = Integer.parseInt((String) entry.getValue());
ingredientCostsByTag.put(key, value);
});
}
catch (IOException e) {
CraftTracker.LOGGER.error("I/O exception when trying to load ingredient costs file", e);
}

var ingOverridesResource = new ResourceLocation(Constants.MOD_ID, "ingredient-overrides.properties");
try {
var costs = mgr.getResource(ingOverridesResource);
var props = new Properties();
props.load(costs.getInputStream());
props.entrySet().forEach(entry -> {
var key = new ResourceLocation((String) entry.getKey());
var value = Integer.parseInt((String) entry.getValue());
ingredientCostOverrides.put(key, value);
});
}
catch (IOException e) {
CraftTracker.LOGGER.error("I/O exception when trying to load ingredient overrides file", e);
}
}

public static List<? extends Recipe<?>> getRecipesFor(ResourceLocation itemId) {
CraftTracker.LOGGER.debug("RecipeUtil#getRecipesFor: {}", itemId);

var mgr = Minecraft.getInstance().level.getRecipeManager();
var recipes = mgr.getRecipes().stream()
.filter(r -> r.getResultItem().getItem().getRegistryName().equals(itemId))
.collect(Collectors.toUnmodifiableList());
.toList();

CraftTracker.LOGGER.debug("RecipeUtil#getRecipesFor: recipes {}", recipes);
return recipes;
Expand All @@ -30,12 +71,71 @@ public static boolean areIngredientsSame(NonNullList<Ingredient> ingredients) {
CraftTracker.LOGGER.debug("RecipeUtil#areIngredientsSame: {}", ingredients);

Set<String> ing = ingredients.stream()
.map((i) -> Arrays.asList(i.getItems()))
.filter((l) -> !l.isEmpty())
.map((l) -> l.get(0))
.map((i) -> i.getItem().getRegistryName().toString())
.map(i -> Arrays.asList(i.getItems()))
.filter(l -> !l.isEmpty())
.map(l -> l.get(0))
.map(i -> i.getItem().getRegistryName().toString())
.collect(Collectors.toSet());

return ing.size() == 1;
}

public static int calculateRecipeCost(Recipe<?> recipe) {
CraftTracker.LOGGER.debug("RecipeUtil#calculateRecipeCost: {}", recipe);

return recipe.getIngredients().stream()
.map(RecipeUtil::getIngredientCost)
.reduce(0, Integer::sum);
}

public static int getIngredientCost(Ingredient ingredient) {
CraftTracker.LOGGER.debug("RecipeUtil#getIngredientCost: {}", ingredient);

for(ItemStack stack : ingredient.getItems()) {
// is the item in the override list?
var itemId = stack.getItem().getRegistryName();
if(ingredientCostOverrides.containsKey(itemId)) {
CraftTracker.LOGGER.debug("found item {} in override list", itemId);
return ingredientCostOverrides.get(itemId);
}

// it's not, so check its tags
if(stack.hasTag()) {
for(TagKey<Item> tag : stack.getTags().toList()) {
var tagId = tag.location();
if(ingredientCostsByTag.containsKey(tagId)) {
CraftTracker.LOGGER.debug("found item {} in tag list", tagId);
return ingredientCostsByTag.get(tagId);
}
}
}
}

return 1;
}

public static int chooseLeastExpensiveOf(List<? extends Recipe<?>> recipes) {
CraftTracker.LOGGER.debug("RecipeUtil#chooseLeastExpensiveOf: {}", recipes);

List<Tuple<ResourceLocation, Integer>> recipeCosts = new ArrayList<>();

for(Recipe<?> recipe : recipes) {
var cost = RecipeUtil.calculateRecipeCost(recipe);
var tuple = new Tuple<>(recipe.getId(), cost);

recipeCosts.add(tuple);
}

int lowestCostIndex = 0;
int lowestCost = Integer.MAX_VALUE;
for(int i = 0; i < recipeCosts.size(); i++) {
var cost = recipeCosts.get(i).getB();
if(cost < lowestCost) {
lowestCostIndex = i;
lowestCost = cost;
}
}

return lowestCostIndex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class TextUtils {
private static final MutableComponent NO_EFFECTS = (new TranslatableComponent("effect.none")).withStyle(ChatFormatting.GRAY);

/**
* Syntactic sugar for custom translation keys. Always prefixed with the mod's ID in lang files (e.g. farmersdelight.your.key.here).
* Syntactic sugar for custom translation keys. Always prefixed with the mod's ID in lang files (e.g. crafttracker.your.key.here).
*/
public static MutableComponent getTranslation(String type, String key, Object... args) {
return new TranslatableComponent(type + "." + Constants.MOD_ID + "." + key, args);
Expand Down
Loading

0 comments on commit f62eb9a

Please sign in to comment.