#Minecraft Crafting

1 messages · Page 1 of 1 (latest)

rich field
#

hi guys! I am planning to replicate minecraft Crafting. do you have an idea how to implement it in general? i was thinking about just checking every slot if it has an item. but i am also planning to let the player input the items everywhere as long as it matches the general pattern (you can input any two planks in a crafting grid as long as they are vertical)
i am also storing all these recipes in json like minecraft does:

{
    "Recipes":[
        {
            "shapeless":false,
            "recipe":[
                "XXX",
                " Y ",
                " Y "
            ],
            "keys":[
                {
                    "key":"X",
                    "item":"diamond"
                },
                {
                    "key":"Y",
                    "item":"stick"
                }
            ],
            "result":"diamond_pickaxe"
        },
        {
            "shapeless":false,
            "recipe":[
                "X",
                "X",
                "Y"
            ],
            "keys":[
                {
                    "key":"X",
                    "item":"diamond"
                },
                {
                    "key":"Y",
                    "item":"stick"
                }
            ],
            "result":"diamond_sword"
        },
        {
            "shapeless":false,
            "recipe":[
                "X",
                "X"   
            ],
            "keys":[
                {
                    "key":"X",
                    "item":"diamond"
                }
            ],
            "result":"stick"
        }
    ]
}

this shows how the recipe for the diamond sword can be shifted left to right, the stick recipe can be shifted up, down, left and right and the pickaxe must be crafted exactly like it says. Unfortunatly i dont have a single clue how to implement that. any ideas?

#

im gonna be afk for a moment, so please feel free to input your ideas (:

chrome knot
#

Alright, so the gist of it is to first separate the two types of crafting, shaped and shapeless (btw the last two recipes in that JSON are incorrect, its shapeless key should be set to true, as you can put the ingredients anywhere).
Next would be to "preload" the recipe in a C# class, and then have some code make the different links between the json element (namely the letter-to-item-and-quantity link), so in the end you have yet another C# class, CraftingRecipe, abstract with the required methods (to check if the recipe matches what's in the slots of the table, to process the crafting, etc).
Then you have two subclasses, ShapedRecipe and ShapelessRecipe that override the methods, so you can both handle shaped and shapeless recipes.

chrome knot
#

To check whether a recipe matches what's in the slots, for a shaped recipe you would simply iterate through the slots.
For shapeless it's a bit more complicated, you need to determine the size of the recipe, and march the slots to see if the slots at that position match the recipe

rich field
#

hmm

chrome knot
#

Actually, I'm mixing up stuff here. The JSON is right, shapeless crafting is something else, it doesn't have a recipe key, or it's empty. That one is even easier to implement, just count if the required items are present in the crafting grid.

#

You need to march the grid when the recipe list isn't composed of 3 strings of 3 chars each

rich field
#

yes, i am still trying to figure out how to do the shifting thing. when the

string[3] recipe
contains for instance at recipe[0] not 3 but 1 letter ("X")
it can be shifted. if it contains a blank space, it cannot, the space is reserved by a blank item (" X ")

#

also, when theres just one blank field, it can still be shifted:
recipe: " Y"
possible combinations:
" Y "
" Y"

chrome knot
#

Two if statements, that check whether the pattern can be shifted in that direction. If the width is 3, it can't be shifted horizontally. If the height is 3, it can't be shifted vertically

rich field
#

i could just get (pseudo) List.Length to determain wether it can be shifted up and down, and List[i].length to check if it can be shifted right/left

chrome knot
#

Exactly

rich field
#

i would have to generate a list for all other possible recipes (shaped)

#

based on that two checks

#

idk if thats inefficient, e.g. a stick has 6 possible recipes, and searching a list takes O(n) irrc

chrome knot
#

Nah, you would march through the grid to see if a recipe matches at any position. Taking your example X (empty, X), it would do that

rich field
#

minecraft has 379 craftable items, and thats not even taking note of he sub recepies

chrome knot
#

blue square being the "origin of the search", and the red arrows where it moves the whole recipe to, to match

rich field
#

i dont understand---

#

like some sort of offset?

chrome knot
#

Yeah, let me make some more images - the first one is the first "iteration", the top-left 2 slots are checked

#

2nd iteration

#

3rd iteration

#

etc.

rich field
#

i see

chrome knot
#

You should be able to pull that (the marching movement) off with two nested for loops

#

And inside another loop that matches the actual items in the slots being checked

#

Yes, that is up to 4 nested loops

#

Not even "up to", 4 nested loops that's it

rich field
#

wait a second

#

maybe (for efficiency stuff) first check if the required items for the list matches the items in the grid

chrome knot
#

I was about to say that

#

But your flowchart is correct

rich field
#

how would i actually shift the items ? like code

chrome knot
#

I'm not going to give you the full code that works out of the box evidently

rich field
#

yea no prob lol

chrome knot
#

Start with the loop that marches right, note down the bounds of the for loop depending on the width of the recipe, and you'll be able to deduct a simple formula to automagically calculate that, depending on the width and the crafting grid size

#

Repeat the same process for the loop that marches down

#

Actually, down first, then right if you want to follow the images I posted

#

Marching right first would give a sweep like that. It's the same number of moves though, so implement any

#

(by "first" I meant "the outer loop first")

rich field
#

wtf

#

did my message just get deleted

#

s.dknbf,km.hjsdn

chrome knot
#

I think yeah, I have nothing on my side

#

Bot removes messages for various reasons, especially unformatted code

rich field
#

i was summing up the process 😐

chrome knot
#

If you're on PC you can CTRL+Z a few times

rich field
#

so, to sum it up:
0. iterate over all recipes:

  1. check if the amount and type of items required matches the items in grid

  2. create two ints, returning how much i can shift in x and y direction, Example:
    "X",
    "Y",
    "Y"
    returns 2 for horizontalShift, 0 for verticalShift

  3. in a double nested for loop i do the following:

        .2 y=0; y < verticalShift (0)
            checkBoard(shiftBoard(recipe,board, x, y))```
    
  4. craft 🙂

#

if checkBoard returns true, craft

#

oh i need the current board

chrome knot
#

That sounds good to me

rich field
#

it isnt

#

the y loop wouldnt do anything if verticalShift is zero

#

would it?

chrome knot
#

And that's exactly what you want to do

rich field
#

would checkBoard still execute?

chrome knot
#

Ah, no

rich field
#

thats the prob

#

<= isnt an option either

#

it is

#

yes it is

chrome knot
#

Yeah that works

rich field
#

xd

chrome knot
#

A sort of state machine could have worked here, where the positions would be stored in the class, and an Advance method would move it to the next position, but <= definitely works here

rich field
#

gonna deserialize the json first xD

chrome knot
#

And map the letters in the recipe to real item instances

#

For each char in the recipe -> find the corresponding item name in the list aside it -> load the item -> put it in an array

#

In the end you could have a Slot[,] that represents your recipe (item + qty), but high-level

#

Basically, for peak performance™️ recipes should be only deserialized once, afterwards they're in a collection of Recipe, that contains info about said recipe

chrome knot
#

Quantity

rich field
#

oh

#

i have a recipe index where all recipes go, they are deserialized on awake

#

i did that to my item class (i dont like scriptable objects, also modding support) and Drops

#

what should the key list be type of? List<Dictionary<string,Item>> ?

chrome knot
#

Key, as in the letters you can find in the recipe string array?

#

this thing

#

It would involve a bit of data transformation on load, but the best (and most efficient) would be a Dictionary<char, Item>

rich field
#

i could also use a class for that.. should i? probably not

chrome knot
#

Yeah, so in the end you can do

for (int row = 0; row < recipe.Length; row++)
{
  for (int col = 0; col < recipe[row].Length; col++)
  {
    char k = recipe[row][col];
    if (k == ' ') continue; // skip spaces
    
    slots[row, col] = keyDictionary[k];
  }
}
#

That maps the chars in the recipe to an Item instance present in the dictionary

#

(Item[,] slots = new Item[gridWidth, gridHeight]) <- if one day you make bigger crafting tables, or non-square ones, your code will adapt without any issue, even for marching the grid

rich field
#

nah, i am just gonna hardcode 2x2 and 3x3

#

uhm

#

how do i get the key name of an JObject?

foreach (JObject key in (JArray)Recipes["keys"])
{
   _keys.Add(new Dictionary<char, Item> { key."here"})
}
#

wait no forget it, what am i doing

#

i thought it was "X":"diamond_shovel"

chrome knot
#

Couldn't tell anyway lol, haven't used the dynamic JSON parsing thingy

rich field
#

_keys.Add(new Dictionary<char, Item> { [(char)key["key"]] = returnItem((string)key["item"]) });
i love programming 💀

chrome knot
#

What? Why do you have an unknown collection of Dictionary

#

Just Dictionary<char, Item>, otherwise you lose the performance benefits when accessing

#

dict.Add((char)key["key"], returnItem((string)key["item"]))

rich field
#

i didnt know that, i am not familliar with dicts

#

so what exactly should i do now 😅

chrome knot
rich field
#

no i mean with the dictionary

#

to add to it

chrome knot
#

where dict is your Dictionary<char, Item>

rich field
#

ohhh

chrome knot
#

The advantage in using a Dictionary (other than it's fast) is that you cannot have duplicate keys

rich field
#

i thought a dict is only one thing, i thought its:
"foo": 1

not
"foo1":1,
"foo2":2
.
.
.

chrome knot
#

So you can encounter 5 X and 2 Y, the dictionary will only have two elements

rich field
#

thats some cool stuff

#

i like Dictionaries

#

i will test the deserialization now

#

wait, gonna write a Log thing

#

huh

#

foreach (Recipe recipe in RecipeIndex.Recipes)
doesnt work at all

#

oh its not static

rich field
#

deserialization works perfec

#

now the hard part

rich field
#

ima break for today, i just came to implementig the crafting grid and the custom mechanic for the locked slot (where the result sits)

#

thank you very much for your help. i really appreciate it man. mind if i ping you tomorrow when i need help?

chrome knot
#

Sure no problem

rich field
#

thanks! goodnight! (:

rich field
#

joooooooo @chrome knot guess what

chrome knot
#

Looks really nice congrats

rich field
#

Thanks! Just fixing bugs atm

#

Also shapeless has to be worked overUnityChanFrustrated

rich field
#

@chrome knot sorry for ping but Massive progress!
Crafting is working perfectly. i implemented a crafting Table to test if your system also works on 3x3 grids. it did with a bit of tweaks here and there. also added the shift system, the double click to fill the dragged item slot (with priorities!) and the right click to add to each slot you're hovering over mechanic from minecraft. Thank you very much for your Help!

chrome knot
#

Nice, thanks for the update!

rich field
#

hi @chrome knot sorry again. i am really frustrated because i cant solve this issue and i wondered if you can give me any help

so in a function, i am checking if(inv.DragSlot.item.name == slot.slot.item.name)
on the normal slots, its working fine, but for the crafting slots, i am getting NullReference on slot.slot.item.name i thought weird, maybe didnt initialize item correctly. But that aint it. when i check manually, the string is there and i even did a Debug.Log() with the context arg checking slot.slot.item since slot.slot.item.name gives Null like i said. can you PLEASE help me, this is really getting frustrating

rich field
#

forget it, fixed this piece of crao