[Solved] Merge identical nodes in craft recipe

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

[Solved] Merge identical nodes in craft recipe

by texmex » Sun Sep 30, 2018 08:53

I'm trying to write some code where I grab all craft recipes of all items respectively with. Most things work already, but I can't figure out how to count the occurances of identical items within the same craft recipe and "merge" them, that is combining them into one occurance of the item suffixed by a number equal to the number of occurances in the "old" recipe.

Essentially I want to turn
Code: Select all
   recipe = {
      {"",           "",           ""          },
      {"group:wood", "",           "group:wood"},
      {"group:wood", "group:wood", "group:wood"},
},


↳ into ↴

Code: Select all
   recipe = {{"group:wood 5"}},



Here's what I've written so far:

+ Spoiler
Last edited by texmex on Wed Oct 03, 2018 17:21, edited 3 times in total.
 

User avatar
Hybrid Dog
Member
 
Posts: 2719
Joined: Thu Nov 01, 2012 12:46

Re: Merge identical nodes in craft recipe into one, with cou

by Hybrid Dog » Tue Oct 02, 2018 17:26

You could use a table as hash map to store the counts for each item.
An item in a craft recipe could be e.g. "default:stone 3", so the item name is not necessarily the itemstring, thus I used the ItemStack function to parse the itemstring reliably.
In the end a list is created which contains the items with their count as itemstring, i.e. the "new" recipe.
Code: Select all
local item_counts = {}
for y = 1, #recipe do
   local row = recipe[y]
   for x = 1, #row do
      local item = ItemStack(row[i])
      local itemname = item:get_name()
      if item_counts[itemname] then
         item_counts[itemname] = item_counts[itemname] + item:get_count()
      else
         item_counts[itemname] = item:get_count()
      end
   end
end

local new_recipe,n = {},1
for name, count in pairs(item_counts) do
   new_recipe[n] = name .. " " .. count
   n = n+1
end

‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

Re: Merge identical nodes in craft recipe into one, with cou

by texmex » Wed Oct 03, 2018 13:20

Hmm, I'm trying the code out but the for x = 1, #row do never gets to run with local recipe = minetest.get_all_craft_recipes(a.name):

+ Spoiler
Last edited by texmex on Wed Oct 03, 2018 13:45, edited 4 times in total.
 

User avatar
12Me21
Member
 
Posts: 873
Joined: Tue Mar 05, 2013 00:36
Location: (Ignore all of my posts before 2018)
GitHub: 12Me21

Re: Merge identical nodes in craft recipe into one, with cou

by 12Me21 » Wed Oct 03, 2018 13:25

minetest.registered_items isn't an array, it uses the item names as keys.
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

Re: Merge identical nodes in craft recipe into one, with cou

by texmex » Wed Oct 03, 2018 13:30

12Me21 wrote:minetest.registered_items isn't an array, it uses the item names as keys.

Yet this works fine:

+ Spoiler


(Sorry, I wrote "ipairs" where in reality I use a "pairs" function, and I didn't publish my "values" function.)
 

User avatar
12Me21
Member
 
Posts: 873
Joined: Tue Mar 05, 2013 00:36
Location: (Ignore all of my posts before 2018)
GitHub: 12Me21

Re: Merge identical nodes in craft recipe into one, with cou

by 12Me21 » Wed Oct 03, 2018 13:45

Make sure this is running after all mods have loaded.

EDIT:
the output of minetest.get_all_craft_recipes is: (from lua_api.txt)
Code: Select all
    * recipe entry table:
        * `method`: 'normal' or 'cooking' or 'fuel'
        * `width`: 0-3, 0 means shapeless recipe
        * `items`: indexed [1-9] table with recipe items
        * `output`: string with item name and quantity

The input items aren't split into rows.

Try this:

Code: Select all
local function combine(recipe)
   local item_counts = {}
   for _, itemstring in pairs(recipe.items) do -- must use pairs here because some slots are nil.
      local stack = ItemStack(itemstring)
      local item_name = stack:get_name()
      item_counts[item_name] = (item_counts[item_name] or 0) + stack:get_count()
   end
   return item_counts
end

minetest.register_on_mods_loaded(function()
   for name in pairs(minetest.registered_items) do
      local recipes = minetest.get_all_craft_recipes(name)
      if recipes then
         for _, recipe in ipairs(recipes) do
            print(dump(combine(recipe)))
         end
      end
   end
end)
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

Re: Merge identical nodes in craft recipe into one, with cou

by texmex » Wed Oct 03, 2018 15:44

Wow, I didn't know register_on_mods_loaded even existed. That will be super useful instead of soft depend on every other little mod!

Your function looks super slick, but it returns
Code: Select all
{["group:wood"] = 5,}

and not

Code: Select all
{{"group:wood 5"}},
 

User avatar
12Me21
Member
 
Posts: 873
Joined: Tue Mar 05, 2013 00:36
Location: (Ignore all of my posts before 2018)
GitHub: 12Me21

Re: Merge identical nodes in craft recipe into one, with cou

by 12Me21 » Wed Oct 03, 2018 15:51

texmex wrote:Wow, I didn't know register_on_mods_loaded even existed. That will be super useful instead of soft depend on every other little mod!

I think that was added in 5.0, but before that it was common to use minetest.after(0, function).
texmex wrote:Your function looks super slick, but it returns
Code: Select all
{
   ["default:stick"] = 2,
   ["default:brick"] = 4
}


and not

Code: Select all
{{"group:wood 5"}},

Oh, right
just replace `return item_counts` with something like
Code: Select all
   local stacks = {}
   for name, count in pairs(item_counts) do
      table.insert(stacks, name.." "..count)
   end
   return stacks

I'm not sure whether items with metadata are allowed in recipes... That would break this.
 

User avatar
Hybrid Dog
Member
 
Posts: 2719
Joined: Thu Nov 01, 2012 12:46

Re: Merge identical nodes in craft recipe into one, with cou

by Hybrid Dog » Wed Oct 03, 2018 16:23

Sorry, I didn't read the api.
Converting the hashmap to a list should still work, as 12Me21 already showed.
I generally don't use table.insert.
Code: Select all
local new_recipe = {}
for name, count in pairs(item_counts) do
   new_recipe[#new_recipe+1] = name .. " " .. count
end

‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

Re: Merge identical nodes in craft recipe into one, with cou

by texmex » Wed Oct 03, 2018 17:17

Thank you both, you've been immensely helpful!

I ended up building on 12Me21's solution and with the (for me) newly discovered register_on_mods_loaded function:

Code: Select all
local function combine(recipe)
   local item_counts = {}
   for _, itemstring in pairs(recipe.items) do -- must use pairs here because some slots are nil.
      local stack = ItemStack(itemstring)
      local item_name = stack:get_name()
      item_counts[item_name] = (item_counts[item_name] or 0) + stack:get_count()
   end
   local stacks = {}
   for name, count in pairs(item_counts) do
      table.insert(stacks, name.." "..count)
   end
   return stacks
end

minetest.register_on_mods_loaded(function()
   for name in spairs(minetest.registered_items) do
      local recipes = minetest.get_all_craft_recipes(name)
      if recipes then
         for _, recipe in ipairs(recipes) do
            if recipe.method == "normal" then
               crafting.register_recipe({
                  type = "inv",
                  output = recipe.output,
                  items = combine(recipe),
                  always_known = true,
               })
            end
         end
      end
   end
end)


(spairs is pairs but sorted)

Now I can finally haz grid-less crafting!

Image
Attachments
crafting.png
(59.2 KiB) Not downloaded yet
Last edited by texmex on Thu Oct 11, 2018 06:40, edited 1 time in total.
 

User avatar
Hybrid Dog
Member
 
Posts: 2719
Joined: Thu Nov 01, 2012 12:46

Re: [Solved] Merge identical nodes in craft recipe

by Hybrid Dog » Wed Oct 03, 2018 19:49

Did you consider special recipes yet?
* Shapeless recipes are already grid-less I think, so you may want to handle them differently. recipe.width is 0 in this case.
* There're also replacements, where you get more than one itemstack as crafting output, an item in the craft grid is replaced with another one: https://github.com/minetest/minetest/bl ... .txt#L6130
* Mods might register functions which are executed when the player crafts something: https://github.com/minetest/minetest/bl ... .txt#L3669, a mod may for example make the player be teleported somewhere when it crafts something.

‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

Re: [Solved] Merge identical nodes in craft recipe

by texmex » Thu Oct 04, 2018 08:16

Nope, I haven't yet. This is merely to carry over the majority of MTG recipes to the other system in order to build and iterate upon it but not with the goal of having complete feature parity.
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

Re: [Solved] Merge identical nodes in craft recipe

by texmex » Thu Oct 11, 2018 06:39

Hybrid Dog wrote:* Shapeless recipes are already grid-less I think, so you may want to handle them differently. recipe.width is 0 in this case.

I think they work equally good as the otherones, not seeing why I should treat them differently.

Hybrid Dog wrote:* There're also replacements, where you get more than one itemstack as crafting output, an item in the craft grid is replaced with another one: https://github.com/minetest/minetest/bl ... .txt#L6130


Can you show me a replacement recipe? I haven't found a single one in MTG at least, that's not a cooking recipe. (this code is only supposed to handle normal ones)

Hybrid Dog wrote:* Mods might register functions which are executed when the player crafts something: https://github.com/minetest/minetest/bl ... .txt#L3669, a mod may for example make the player be teleported somewhere when it crafts something.


I think that works already, at least the awards mod is able to detect crafted recipes.
 

User avatar
Hybrid Dog
Member
 
Posts: 2719
Joined: Thu Nov 01, 2012 12:46

Re: [Solved] Merge identical nodes in craft recipe

by Hybrid Dog » Thu Oct 11, 2018 09:24


‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪‮
‮‪
 

User avatar
texmex
Member
 
Posts: 1590
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: texmex

Re: [Solved] Merge identical nodes in craft recipe

by texmex » Thu Oct 11, 2018 09:45

Hybrid Dog wrote:Here's a replacement recipe: https://github.com/minetest-mods/moretr ... s.lua#L110

You're right, the recipe is craftable but the replacements aren't added. Not too interested in tending to since that requires changes to the crafting mod itself, of which I know nothing but the API.
 


Return to Modding Discussion



Who is online

Users browsing this forum: Google [Bot] and 7 guests