Page 1 of 1

Understanding Lua

Posted: Mon Feb 09, 2026 10:19 pm
by Aethyrium
Hello friends!

-- Needless exposition
I am a long (long... long...) time Factorio player, but very new to modding. And by very new, I mean I like just started this week (and this is my first real foray into programming). And that journey started with learning how Lua works. So I ran through the Lua crash course on Codecademy, after which I felt like I had a fair rudimentary understanding of the language - enough that when I looked at other code, I felt confident I roughly (emphasis: "rough" - based on complexity of code) understood what was happening. So today I jumped right in to execute what I felt like a was a fairly basic idea for a mod (modifying a base recipe) just to put skills to the test. Many problems later, and a couple of hours later, my mod functions and does what I want it to do. Yay!

While I'd like to do some expanding to my mod, now that I have a portion of it working, I'd like to understand some things, and improve my coding here so I can establish good habits early. So...

-- My Mod
At the most basic, I wanted to add a teeny bit of complexity while preserving default ratio to the transport belt cost - also I wanted to increase general use of iron sticks. My answer was to add 2 sticks to the transport belt recipe, increase gears to 2, and produce 4 belts instead of two. This is where I landed, and it works - it's tested in game and functions (let's ignore that sticks require Electric Energy Distribution 1... I'll figure out how to fix that later / if I keep working on this particular project).

Code: Select all

data.raw.recipe["transport-belt"].ingredients =
	{
		{type = "item", name = "iron-plate", amount = 1},
		{type = "item", name = "iron-gear-wheel", amount = 2},
		{type = "item", name = "iron-stick", amount = 2},
	}
data.raw.recipe["transport-belt"].results = {{type="item", name="transport-belt", amount=4}}
-- The Questions
Of which, I have three... point five(ish) half a dozen. Specific questions are bolded.

First, is that while trying to figure out how to do this, and troubleshooting the various errors I had, I came across this thread/solution to the problem: viewtopic.php?t=40209

In this example mod, the code they use is very small:

Code: Select all

data.raw.recipe["transport-belt"].ingredients =
{
	{"copper-plate", 1},
	{"iron-gear-wheel", 2}
}
And boy did I try to make that work. I kept getting errors (something something dictionary ROOT.data.raw... I broke quality (actually recycling according to the error) at one point. It was wild). Now, once I found a mod on the portal that did something similar to mine (basic recipe tweaks... which I am thinking can be done multiple ways depending at what stage you do it at, but this seems beyond me at the moment), I saw that they were using the full breakout like I am using in my 'finalized' mod. Which is what I thought to do initially, and had I done, would have saved me like at least an hour - but as this solution said solved, I really tried to make it work for me.

Now my best guess here is that this is just old language that doesn't work anymore, which clicked once I got mine working. So my guess here is that the code from the linked thread doesn't work, because the way the code works in 2.0 is just not compatible with that formatting anymore. Can I get confirmation that this is the case, or otherwise, an explanation as to why that exact coding does not seem to work anymore (I couldn't make it work, even with direct copy)?

Question two is a little more in the weeds. In the code that functions there is this line:

Code: Select all

data.raw.recipe["transport-belt"].results = {{type="item", name="transport-belt", amount=4}}
If I were to break this down with my rudimentary understanding of Lua (please forgive any verbiage errors).
  • data.raw is calling the "master table" of information compiled by the game.
  • .recipe is designating a subsection of that.
  • ["transport-belt"] is selecting the object from that subsection that I want to mess with.
  • '.results =' is changing the variable that is the results of that object.
  • {{type="item", name="transport-belt", amount="4""}} are defining what you get.
Assuming my understanding is correct (and please correct me if I'm wrong!) my question (and bonus questions) here is: What is the purpose of the double {{}} around the last part, defining what you get? I (think I) understand why the first set of brackets is needed, we're creating a table to be referenced. But what is the second set of brackets actually doing, it isn't (as far as I can tell) attached to anything else?

Bonus questions about this here are that on the data.raw page of the wiki, it suggests that the '.recipe' potion of this code could be replaced with ["recipe"] in the same way we call the transport belt. So it'd look like this:

Code: Select all

data.raw.["recipe"]["transport-belt"].results = ...
Is this accurate? And if it is accurate, is there a preferred choice between which method is used, or if both, when is "generally considered" appropriate to use one over the other? Additionally, does that mean we couple replace '.results' with ["results"]? If not, can you explain why? And if that's the case, could you replace ["transport-belt"] with .transport-belt, and if not, why not?

Actually, on that note, why does '.results' work at all? Based on my understanding 'results =' is a variable we've defined <somewhere>. In this case in the recipe. I am guessing based on context that the 'thing.thing.thing.thing' format is a way for the code to read a table (which was present in my little Lua course, I have just since done some extra reading and am vaguely familiar) and that the way that data.raw works (basically) is that it compiles things into a table that can be read by the code in a file-like structure so it's basically the same thing as data/raw/recipes/transport-belt/results and the reason we're able to call it is because of tabling much earlier on... If this is way off base and too much to explain to a novice, I understand.

And the final question which isn't really about the mod or Lua specifically, is just about formatting conventions - which the internet seems to have mixed opinions on. How many spaces before a new line of code 2-3-4 (vs. tab in note++ which is what I have been using, and appears equal to 4). Nesting vs. not nesting? Are there objective formatting conventions I should be aware of out of the gate that aren't just "your" personal preference, or is this mostly a personal preference sort of thing?

-- Outro
That... Ended up being a lot. Sorry about that! Just a quick preemptive thank you to anyone who reads through this. And an extra thanks to anyone who can shed light on one or more of these questions for me, I really appreciate your time and assistance!

Re: Understanding Lua

Posted: Mon Feb 09, 2026 11:12 pm
by eugenekay
Aethyrium wrote: Mon Feb 09, 2026 10:19 pmCan I get confirmation that this is the case, or otherwise, an explanation as to why that exact coding does not seem to work anymore (I couldn't make it work, even with direct copy)?
Yes, version 2.0 changed how recipe ingredients are specified. There used to be a shorthand format for compatibility. The Quality mod chokes if a Recipe does not have a valid Ingredients because it auto-generates recipes for each quality level… it is generally easiest/faster to disable the DLC mods when experimenting with recipe changes unless they require a Space Age item - or use Logic to detect if they are enabled and conditionally add support.
Question two is a little more in the weeds. In the code that functions there is this line:

Code: Select all

data.raw.recipe["transport-belt"].results = {{type="item", name="transport-belt", amount=4}}
If I were to break this down with my rudimentary understanding of Lua (please forgive any verbiage errors).
  • data.raw is calling the "master table" of information compiled by the game.
  • .recipe is designating a subsection of that.
  • ["transport-belt"] is selecting the object from that subsection that I want to mess with.
  • '.results =' is changing the variable that is the results of that object.
  • {{type="item", name="transport-belt", amount="4""}} are defining what you get.
Assuming my understanding is correct (and please correct me if I'm wrong!) my question (and bonus questions) here is: What is the purpose of the double {{}} around the last part, defining what you get? I (think I) understand why the first set of brackets is needed, we're creating a table to be referenced. But what is the second set of brackets actually doing, it isn't (as far as I can tell) attached to anything else?
The outer brackets are defining a ProductPrototype; the inner brackets define a (or multiple) Item/FluidProductPrototype within that wrapper.
Bonus questions about this here are that on the data.raw page of the wiki, it suggests that the '.recipe' potion of this code could be replaced with ["recipe"] in the same way we call the transport belt. So it'd look like this:

Code: Select all

data.raw.["recipe"]["transport-belt"].results = ...
Is this accurate? And if it is accurate, is there a preferred choice between which method is used, or if both, when is "generally considered" appropriate to use one over the other? Additionally, does that mean we couple replace '.results' with ["results"]? If not, can you explain why? And if that's the case, could you replace ["transport-belt"] with .transport-belt, and if not, why not?

Actually, on that note, why does '.results' work at all? Based on my understanding 'results =' is a variable we've defined <somewhere>. In this case in the recipe. I am guessing based on context that the 'thing.thing.thing.thing' format is a way for the code to read a table (which was present in my little Lua course, I have just since done some extra reading and am vaguely familiar) and that the way that data.raw works (basically) is that it compiles things into a table that can be read by the code in a file-like structure so it's basically the same thing as data/raw/recipes/transport-belt/results and the reason we're able to call it is because of tabling much earlier on... If this is way off base and too much to explain to a novice, I understand.
Named properties (like “results”) can be accessed as either a .method; or as a a ["property"]. This is just Lua syntax being weird because it’s an interpreted language. I think Members of an array can only be accessed by name, eg ["transport-belt"]
And the final question which isn't really about the mod or Lua specifically, is just about formatting conventions - which the internet seems to have mixed opinions on. How many spaces before a new line of code 2-3-4 (vs. tab in note++ which is what I have been using, and appears equal to 4). Nesting vs. not nesting? Are there objective formatting conventions I should be aware of out of the gate that aren't just "your" personal preference, or is this mostly a personal preference sort of thing?
There is no single authority on spaces-per-indent-level in Lua. I like to use Tab characters, which are normally 8 characters wide.

Good Luck!

Re: Understanding Lua

Posted: Tue Feb 10, 2026 12:18 am
by Aethyrium
Yes, version 2.0 changed how recipe ingredients are specified. There used to be a shorthand format for compatibility. The Quality mod chokes if a Recipe does not have a valid Ingredients because it auto-generates recipes for each quality level… it is generally easiest/faster to disable the DLC mods when experimenting with recipe changes unless they require a Space Age item - or use Logic to detect if they are enabled and conditionally add support.
Oh perfect, I'm glad I was right about this. Good to know disabling mods and what have you, I will keep that in mind. Thank you!
The outer brackets are defining a ProductPrototype; the inner brackets define a (or multiple) Item/FluidProductPrototype within that wrapper.
I think I'm following this. As I look at the code again, I'm recognizing that this (seems) to functionally be happening on the ingredient line as well.

Code: Select all

	{
		{type = "item", name = "iron-plate", amount = 1},
		{type = "item", name = "iron-gear-wheel", amount = 2}, -- input increased from 1 to 2
		{type = "item", name = "iron-stick", amount = 2}, -- input added
	}
Could also be written

Code: Select all

	{{type = "item", name = "iron-plate", amount = 1}, {type = "item", name = "iron-gear-wheel", amount = 2}, {type = "item", name = "iron-stick", amount = 2}}
...Of course this second writing also asks that you not have eyes, and I suspect is the sort of thing that makes anyone who programs regularly want to lynch you. But a little testing seems to suggest that it works just as well in practice. It could be written then also as something like:

Code: Select all

	{{type = "item", name = "iron-plate", amount = 1},
	{type = "item", name = "iron-gear-wheel", amount = 2},
	{type = "item", name = "iron-stick", amount = 2}}
As some kind of middle ground? My point being that these are all "stylistic" choices, rather than "functional" ones, right?

And as I was mucking around in the code, I was just wondering the same thing about some of the code written in the game:

Code: Select all

data.raw.recipe["transport-belt"].results = {{type="item", name="transport-belt", amount=2}}
Has no spaces between type = "item", etc, but it could be written that way to maintain the same formatting as the ingredients above - or vice versa, the ingredients could be written without the spaces. For example, the above can seamlessly be written as:

Code: Select all

data.raw.recipe["transport-belt"].results = {{type = "item", name = "transport-belt", amount = 2}}
Right?
Named properties (like “results”) can be accessed as either a .method; or as a a ["property"]. This is just Lua syntax being weird because it’s an interpreted language. I think Members of an array can only be accessed by name, eg ["transport-belt"]

There is no single authority on spaces-per-indent-level in Lua. I like to use Tab characters, which are normally 8 characters wide.
This is very informative, thank you!

Re: Understanding Lua

Posted: Tue Feb 10, 2026 12:27 am
by eugenekay
Aethyrium wrote: Tue Feb 10, 2026 12:18 amAs some kind of middle ground? My point being that these are all "stylistic" choices, rather than "functional" ones, right?
Correct, whitespace is stripped out by the Lua interpreter at runtime outside of "quoted strings". The first format is probably the sanest for readability.

Re: Understanding Lua

Posted: Wed Feb 11, 2026 10:54 pm
by Aethyrium
Correct, whitespace is stripped out by the Lua interpreter at runtime outside of "quoted strings". The first format is probably the sanest for readability.
You're the best. Thank you!

Okay so, I return with new things to understand. I have made my mod, and I'm feeling pretty comfortable with what I did. But I hunger for more. I don't think the mod I made was particularly revolutionary (which was the point!) but kicked open the door. I'd like to try my hands at some things a bit more advanced which I think I will almost assuredly eventually have questions about. But in the meantime, can someone explain the data lifecycle to me like I'm 5?

I have read: https://lua-api.factorio.com/latest/aux ... cycle.html

And I think I understand the gist of it. But not... How or why to make use of that information? I've seen some general information that can be summarized as "create stuff as early in the lifecycle as possible", which makes me wonder... Why ever use anything other than 'data'? While making my mod, one of the things I haven't gotten to work is adding the sounds for new items, which caused crashes. I am not entirely sure why yet, but I have assumed that this has to do with load order and the mod trying to call sounds which aren't loaded yet... So that's a thing to figure out. So my question isn't really about that specifically it's about the three stages more broadly.

What goes where? Why use 'data.updates'? Or maybe not why but when should you? Same with 'data.final.fixes'. What should you edit in 'data' vs. 'data-updates' vs 'data.final.fixes'?

I think it's a three stage structure that's throwing me for a loop. Based on the naming and how distinct the stages are, I can see 'data.final.fixes' as some sort of "execute these these functions once everything else is sorted out and polish it off". This seems like if you wanted to "hard" override something, you'd do it here. But then why is there the middle stage at all?

Bonus question, when is it correct (or maybe when is it NOT correct) to use 'data:extend'? At first I didn't even realize this was ever necessary, as I don't have it in my recipe adjustments for the mod that is definitely working. But I do have it in the added intermediates code, and I seem to recall (though I've processed so much information in two days that maybe I'm misremembering) that when I initially didn't have it, I ran into issues. So what defines when this is or isn't needed? It seems like, omnipresent when I look at other mods, but... The difference there (as I type it) might be that one thing is modifying a thing that already exists, wherein the other is adding a thing that doesn't exist. Is that key?

Re: Understanding Lua

Posted: Wed Feb 11, 2026 11:42 pm
by eugenekay
Aethyrium wrote: Wed Feb 11, 2026 10:54 pmWhat goes where? Why use 'data.updates'? Or maybe not why but when should you? Same with 'data.final.fixes'. What should you edit in 'data' vs. 'data-updates' vs 'data.final.fixes'?

I think it's a three stage structure that's throwing me for a loop. Based on the naming and how distinct the stages are, I can see 'data.final.fixes' as some sort of "execute these these functions once everything else is sorted out and polish it off". This seems like if you wanted to "hard" override something, you'd do it here. But then why is there the middle stage at all?
Data is for standalone definition, like those provided by the Base Game. This is where you should define “new” prototype data which doesn’t have any dependencies.

Data-Updates allows you to modify the Data loaded by other Mods, such as changing recipes or modifying item stats.

Data-final-fixes is a hackjob that should be avoided if at all possible. Sometimes it is necessary for adding cross-mod compatibility or overriding Data-updates that you don’t want.

Re: Understanding Lua

Posted: Thu Feb 12, 2026 1:20 am
by Nidan
Aethyrium wrote: Mon Feb 09, 2026 10:19 pm Are there objective formatting conventions I should be aware of out of the gate that aren't just "your" personal preference
Even this is a personal recommendation, but if there's one thing: be consistent. Coding style is a topic of endless debate that always boils down to taste. Do whatever feels most reasonable/readable to you and stick to that. When editing other people's code, use the style they've been using.
eugenekay wrote: Mon Feb 09, 2026 11:12 pm Named properties (like “results”) can be accessed as either a .method; or as a a ["property"]. This is just Lua syntax being weird because it’s an interpreted language. I think Members of an array can only be accessed by name, eg ["transport-belt"]
.foo and ["foo"] are mostly equivalent and interchangeable in Lua. ["foo"] always works, the .foo variant is a shorthand (syntactic sugar) to make Lua look more similar to other languages, but only works for names/identifiers (only consisting of letters and digits). E.g. in .transport-belt the - will be treated as minus/subtraction operator. The beginning of chapter 3 of the Lua Reference Manual has more details.

Speaking of the reference manual, if you don't mind some technical reading, read chapter 3. That and chapter 6 is basically all you need when writing Lua. (Of course, add facorios Lua API doc when writing factorio mods.) Ignore chapters 4 and 5, those are the parts the factorio devs need for providing their Lua API.
Aethyrium wrote: Mon Feb 09, 2026 10:19 pm Actually, on that note, why does […] work at all?
In factorios prototype stage, we're just putting tables within table within tables. That a construct like data.raw.recipes["transport-belt"].results = {{type = "item", name = "transport-belt", amount = 4}} happens to have a particular meaning is because the devs decided to expose access to the games data that way. Nothing is stopping us from assigning nonsense like data.raw["the greatest programmer in the world"] = "me", but the game will either ignore it or complain.
Aethyrium wrote: Wed Feb 11, 2026 10:54 pm When is it correct (or maybe when is it NOT correct) to use 'data:extend'?
The official documentation (https://lua-api.factorio.com/latest/typ ... tml#extend , https://lua-api.factorio.com/latest/typ ... ethod.html) is a bit sparse: "It's the primary way to add prototypes to the data table." So, if you're adding new prototypes (items, recipes, technologies, etc.), use data:extend, it probably does some magic aside from sorting things into the correct data.raw.x entry; if you're interacting with an already existing prototype, access it via data.raw.
Aethyrium wrote: Wed Feb 11, 2026 10:54 pm What goes where? Why use 'data.updates'? Or maybe not why but when should you? Same with 'data.final.fixes'. What should you edit in 'data' vs. 'data-updates' vs 'data.final.fixes'?
Try to be done as early as possible (says the one whose mod only has data-final-fixes…); later stages are for compatibility between mods.

Re: Understanding Lua

Posted: Sat Feb 14, 2026 7:16 pm
by Aethyrium
Even this is a personal recommendation, but if there's one thing: be consistent. Coding style is a topic of endless debate that always boils down to taste. Do whatever feels most reasonable/readable to you and stick to that. When editing other people's code, use the style they've been using.
Haha. Consistency I can do! I actually spent a bit of time just starring at my code, and comparing it to other bits, internalizing what I wanted to do. This was great advice.
Data is for standalone definition, like those provided by the Base Game. This is where you should define “new” prototype data which doesn’t have any dependencies.

Data-Updates allows you to modify the Data loaded by other Mods, such as changing recipes or modifying item stats.

Data-final-fixes is a hackjob that should be avoided if at all possible. Sometimes it is necessary for adding cross-mod compatibility or overriding Data-updates that you don’t want.
The official documentation (https://lua-api.factorio.com/latest/typ ... tml#extend , https://lua-api.factorio.com/latest/typ ... ethod.html) is a bit sparse: "It's the primary way to add prototypes to the data table." So, if you're adding new prototypes (items, recipes, technologies, etc.), use data:extend, it probably does some magic aside from sorting things into the correct data.raw.x entry; if you're interacting with an already existing prototype, access it via data.raw.

Try to be done as early as possible (says the one whose mod only has data-final-fixes…); later stages are for compatibility between mods.
Between these, I think I pretty well understand. Thank you both, this helped immensely (and let me understand some of what I was seeing in other mods as I was exploring!).
.foo and ["foo"] are mostly equivalent and interchangeable in Lua. ["foo"] always works, the .foo variant is a shorthand (syntactic sugar) to make Lua look more similar to other languages, but only works for names/identifiers (only consisting of letters and digits). E.g. in .transport-belt the - will be treated as minus/subtraction operator. The beginning of chapter 3 of the Lua Reference Manual has more details.

Speaking of the reference manual, if you don't mind some technical reading, read chapter 3. That and chapter 6 is basically all you need when writing Lua. (Of course, add facorios Lua API doc when writing factorio mods.) Ignore chapters 4 and 5, those are the parts the factorio devs need for providing their Lua API.
Oh the first part of this, about why '.transport-belt' doesn't work is really helpful, thank you. I totally see that. And chapter suggestions do help! I was looking at that reference manual. I shall consume that this week.
In factorios prototype stage, we're just putting tables within table within tables. That a construct like data.raw.recipes["transport-belt"].results = {{type = "item", name = "transport-belt", amount = 4}} happens to have a particular meaning is because the devs decided to expose access to the games data that way. Nothing is stopping us from assigning nonsense like data.raw["the greatest programmer in the world"] = "me", but the game will either ignore it or complain.
If I am understanding you correctly (and I think I am!) this aligns with my guess/understanding of why and how this was working. I appreciate that, thank you!

Okay so today we have some new stuff... And a new question or two.

After finishing(ish, gotta go fix that sound issue) my belts mod and learning the changelog format (which is probably unneeded, but I wanted to know) I started thinking I wanted to play with something else. So I started tackling mining and looking at modding the mining processing just for giggles. First up was changing mining time to fit with the grander vision I have. It took me a minute to figure out that I needed '.minable' ahead of '.mining_time =', which didn't make a ton of sense to me until I went back and realized the ores are actually functions and the 'minable' thing is in the function itself, not in the definition of each ore. But this was made more confusing by the fact that it is in uranium ore and crude oil. Which I can't figure out why they're written differently... Yet.

But actually the real problem came when I was trying to modify the results. In the base code, results aren't defined inside of the ores (iron, copper, stone), but are to differing degrees in uranium and crude oil. And I this really threw me. I looked, initially, at the ores sort of like items and expected there to be a 'result(s) =' somewhere, but couldn't find it. Cue forty-five minutes of me searching everywhere for this being defined somewhere else. Giving them a:

Code: Select all

data.raw.resource["iron-ore"].minable.results = x
Did not produce the expected outcome. Nor did changing results to result. And nothing seemed to work...

Eventually this led me to the API Docs (which I find terribly intimidating, but I think mostly on account of I just don't really understand how to use it / read it... Yet!) and my first real attempt to understand them. So I went and tried to wrap my brain around that, found the MinableProperties (why do we we use '.minable' and not '.minableproperties', and is there a place this defined somewhere/where all of... Types(?) and how they get typed in the code are?) and because I had accidentally found my way to the 'mining_time' solution I was able to intuit (I hope...) that each of the properties listed in the miningproperty type were things that one could add after a dot. 'minable.fluid_amount =' or 'minable.mining_trigger' (even if this is an example and I don't yet understand what you'd do with this specific one).

So excitedly trying to figure that out. I try to define results. That does nothing. Hrm! Read a little further. Try to define result, which apparently doesn't load if results isn't defined (and based on that I couldn't make it work, I thought for some reason this was just some weirdness I didn't understnad about why results wasn't used in mining). Still no working. Now I'd only seen up to this point results be used to define what gets used when... Get to count finally and have a big AH HA! moment. Redefine count, works exactly the way I want it too. Yay! But also confused...

So the questions are...

Why doesn't '.minable.results =' return an adjusted amount of resources?

...As I was typing this I had an epiphany. I was going to compare to the results of a recipe (like say, iron plate) and realized that the code is actually different. Defining results has that double wrapper I asked about above, and those results are calling a specific thing of everything being spelled out, not just the amount. And a moment of testing later, I realize this is correct and that:

Code: Select all

data.raw.resource["iron-ore"].minable.results = 
	{
		{type = "item", name = "iron-ore", amount = 25}
	}
Does, in fact, produce the outcome that I expected initially. Turns out, you just have to do things the right way. Funny how that works.

Okay, so, other questions that still matter...

What is the difference between: 'results', 'result', and 'count'? (My guess is that these are just relics, used in differing places throughout the code, and so any of them are feasible, but they could be condensed into a single thing if someone was to go through and "clean up" the various entries)

Is there a reason that the ores use count, rather than having a defined result(s?)? (I'm guessing this is just because having a default number that can be applied to each ore is easier coding than rewriting unique result(s) lines for every individual entry, but just in case I'm wrong about that)

In places where count is used, is there a reason to use that over individually defined results? Or I guess the other way makes more sense, is there a reason to use individually defined results over using the count that exists and modifying that? I think I'm trying to 'optimize the code' here in that, I want it to be as seamless as is reasonable (for the game sake, and my own good habit sake). So maybe the actual question here is, is there a specific reason to each/any of these, or are they more or less freely interchangeable where applicable?

Re: Understanding Lua

Posted: Sun Feb 15, 2026 6:37 am
by Pi-C
Aethyrium wrote: Sat Feb 14, 2026 7:16 pm Eventually this led me to the API Docs (which I find terribly intimidating, but I think mostly on account of I just don't really understand how to use it / read it... Yet!) and my first real attempt to understand them. So I went and tried to wrap my brain around that, found the MinableProperties (why do we we use '.minable' and not '.minableproperties', and is there a place this defined somewhere/where all of... Types(?) and how they get typed in the code are?)
.minable is shorter than .minableproperties, while MinableProperties is more descriptive. So the first is easier to use in code, and the second is better for use in the documentation to describe a certain type of properties. For example, the game knows not just MinableProperties, but also LightProperties – if you check out the list of types, you'll see that all types have rather telling names that hint at in which context they are used.
and because I had accidentally found my way to the 'mining_time' solution I was able to intuit (I hope...) that each of the properties listed in the miningproperty type were things that one could add after a dot. 'minable.fluid_amount =' or 'minable.mining_trigger'
Have a look at Lua's lexical conventions – if you have table keys with names that contain illegal characters, you must use ["brackets"], otherwise you can use dots for brevity. By the way, you can use the serpent library to better visualize the structure of a table. For example, if you run this

Code: Select all

log(serpent.block(data.raw.item["stone-furnace"]))
you will see that the nested tables are indented for each level of subtables.
What is the difference between: 'results', 'result', and 'count'? (My guess is that these are just relics, used in differing places throughout the code, and so any of them are feasible, but they could be condensed into a single thing if someone was to go through and "clean up" the various entries)
You should distinguish between results on the one hand, and result + count on the other. Using results is more versatile. As you can see in the description of MinableProperties, results is an array of ProductPrototypes. Arrays can have >1 elements, so you could give players several different things when they are mining something (this makes more sense for entities than resources, e.g. you could return copper wire + wood when a small powerpole is mined). Moreover, ProductPrototype comprises both ItemProductPrototype and FluidProductPrototype, so you can also return fluids!

In contrast, the combination of result and count is a shorthand that you can use when you want to return just one type of item (result is an ItemID, i.e. the name of the item prototype, while count is an integer specifying the amount of items you want to return).
Is there a reason that the ores use count, rather than having a defined result(s?)?
If you "mined" (rather: deconstructed) a building, car, transport belt etc., it would make sense to return different items or even fluids – but if you went out to mine coal, you'd be interested in coal only, so it wouldn't be necessary to define results: name and amount of the item returned are sufficient in this case.

There is one catch, though: if both results and result/count are defined, only the things defined in results will be used, while whatever is specified in result/count will be ignored.

Also, it is possible to define neither results nor result: In this case, the object owning the MinableProperties can be mined but the player will receive nothing. While that doesn't really make sense for a ResourceEntityPrototype, it can be useful for an EntityPrototype.

Re: Understanding Lua

Posted: Sun Feb 15, 2026 9:53 am
by Pi-C
Pi-C wrote: Sun Feb 15, 2026 6:37 am Moreover, ProductPrototype comprises both ItemProductPrototype and FluidProductPrototype, so you can also return fluids!
You may also want to use results for shenanigans like a probability that mining will yield anything, a random yield amount within a given range, spoiled products, etc. Using result/count is rather basic in contrast as it allows only for yielding a fixed amount of exactly one item.