Creating a Mod
Creating a Mod
Hello,
As a fairly new mod creator I want to create a mod that adds new buildings and functions to the game.I know this is very complicated, but does anyone have a good tutorial for me too look at that would help achieve this? Thanks!
CJ
As a fairly new mod creator I want to create a mod that adds new buildings and functions to the game.I know this is very complicated, but does anyone have a good tutorial for me too look at that would help achieve this? Thanks!
CJ
Re: Creating a Mod
The modding has two parts: making prototypes and change the course of the game.
Now you want to make new prototypes/changing them. Now you are need to understand how it works.
We have data.raw table, where we have all items, all recipes and all buildings. If you want to know how it looks like, then you are need Notepad++ and this mod: viewtopic.php?f=135&t=45107
For first mod creating you are need to copy some code part of vanilla prototypes and change it, place this code to your mod folder and make info.json file.
Now you want to make new prototypes/changing them. Now you are need to understand how it works.
We have data.raw table, where we have all items, all recipes and all buildings. If you want to know how it looks like, then you are need Notepad++ and this mod: viewtopic.php?f=135&t=45107
For first mod creating you are need to copy some code part of vanilla prototypes and change it, place this code to your mod folder and make info.json file.
- eradicator
- Smart Inserter
- Posts: 5206
- Joined: Tue Jul 12, 2016 9:03 am
- Contact:
Re: Creating a Mod
The wiki has several tutorials. An easy first step is making new prototypes.
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Creating a Mod
Another good option is to download a good mod, and see how they do it.
A common rookie mistake is the copy paste method. Most of my mods are build on this method. Find an entity that does something similar to what you want to do (assembling machine), copy it's code, then paste it in your mod.
This isn't such a bad thing if you're creating something entirely new, since most crafting machines in the game are actually variations on the same entity type (oil refinery, chemical plant, assembling machine, centrifuge, etc.) but if you're making an assembling machine MK4 for example, it's better to look at different methods. By far the most popular is the table.deepcopy method, where you copy the entity table to a local variable, change the parts that you need/want to change, such as name=, then finally add it to data. Personally, I'm more a fan of the util.merge function.
table.deepcopy (or util.table.deepcopy) is basically copy of table = table.deepcopy(original table), and is used in this format:
util.merge makes use of table.deepcopy internally to copy tables, but what it does is apply 1 table as changes to another as it copies it.
The method is newtable = util.merge(original table, changes table), and is used in this format:
A lot of my newer mods use the util.merge method for entities, but full copy/paste type(could be fully typed) code for items and recipes. I'm not going back to replace code that still works, but when new entities are added, or I need to fix broken code due to an update (or just a big change, like to my power mod's boilers and steam engines), I am actively replacing these code blocks with util.merge blocks instead. Recipes and items will likely always be full code for me because an item is usually half a dozen lines, and a recipe maybe a full dozen, and most of the lines would be unique to that item or recipe, so if I'd be changing more than half the lines after copying them, what's the point in copying in the first place?
A common rookie mistake is the copy paste method. Most of my mods are build on this method. Find an entity that does something similar to what you want to do (assembling machine), copy it's code, then paste it in your mod.
This isn't such a bad thing if you're creating something entirely new, since most crafting machines in the game are actually variations on the same entity type (oil refinery, chemical plant, assembling machine, centrifuge, etc.) but if you're making an assembling machine MK4 for example, it's better to look at different methods. By far the most popular is the table.deepcopy method, where you copy the entity table to a local variable, change the parts that you need/want to change, such as name=, then finally add it to data. Personally, I'm more a fan of the util.merge function.
table.deepcopy (or util.table.deepcopy) is basically copy of table = table.deepcopy(original table), and is used in this format:
Code: Select all
local new_item = table.deepcopy(data.raw.item[item])
new_item.name = item_name
//other lines here.
data:extend({
new_item
})
The method is newtable = util.merge(original table, changes table), and is used in this format:
Code: Select all
data:extend({
util.merge(data.raw.item[item],
{
name = item_name
//other lines here.
}
)
})
- eradicator
- Smart Inserter
- Posts: 5206
- Joined: Tue Jul 12, 2016 9:03 am
- Contact:
Re: Creating a Mod
A notable drawback to the "merge method" is that you can not remove any keys. I.e. if you want to remove a flag or a whole property (i.e. collision_box), then with the merge method you have to remove that value after data:extend, while with deepcopy you can do it before. It's not functionally different, but i personally prefer the look of doing everything before data:extend. Oh, and merge also can't overwrite table values, which can be dangerous when you try to change..well, anything that's a table, i.e. collision_boxes, animations, fluid_boxes, flags, etcpp, because it'll just recursively merge those too. Overall i would not recommend merge until you have more modding experience.
You can still benefit from changes to the base recipes, like addition of icon_size, or new standard flags. Happens only rarely, but does happen.bobingabout wrote: ↑Mon Oct 15, 2018 8:45 amif I'd be changing more than half the lines after copying them, what's the point in copying in the first place?
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Creating a Mod
True, but I meant for readability within my mod. I guess I'm a fan of fully defining my own recipes, not just copying one with a script because I can.eradicator wrote: ↑Mon Oct 15, 2018 11:31 amYou can still benefit from changes to the base recipes, like addition of icon_size, or new standard flags. Happens only rarely, but does happen.bobingabout wrote: ↑Mon Oct 15, 2018 8:45 amif I'd be changing more than half the lines after copying them, what's the point in copying in the first place?
I guess an alternate would be to write my own template, and update that when things change.
Last edited by bobingabout on Tue Oct 16, 2018 8:14 am, edited 2 times in total.
- eradicator
- Smart Inserter
- Posts: 5206
- Joined: Tue Jul 12, 2016 9:03 am
- Contact:
Re: Creating a Mod
Sounds like a very good idea :).bobingabout wrote: ↑Tue Oct 16, 2018 7:57 amI guess an alternate would be to write my own template, and update that when things change.
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Creating a Mod
Yes, it is a bit of a drawback. if you look at my Oil boiler example (it's in my 0.17 WIP power mod, so you can't actually look at it yet), First I do the util.merge method to copy Boiler MK2 (because I want stats to match that rather than the base boiler), and on one of those lines, is the following:eradicator wrote: ↑Mon Oct 15, 2018 11:31 amA notable drawback to the "merge method" is that you can not remove any keys. I.e. if you want to remove a flag or a whole property (i.e. collision_box), then with the merge method you have to remove that value after data:extend, while with deepcopy you can do it before. It's not functionally different, but i personally prefer the look of doing everything before data:extend. Oh, and merge also can't overwrite table values, which can be dangerous when you try to change..well, anything that's a table, i.e. collision_boxes, animations, fluid_boxes, flags, etcpp, because it'll just recursively merge those too. Overall i would not recommend merge until you have more modding experience.
Code: Select all
minable = {result = "oil-boiler"},
Code: Select all
data.raw.boiler["oil-boiler"].energy_source =
{
type = "fluid",
//rest of the definition, etc.
}
And note that I define it afterwards, not as part of the merge.
So you're right, it's not perfect, but the examples where you want to delete lines are usually the minority, not the majority.
The main difference between util.merge and table.deepcopy is that with deepcopy, you edit and delete tags in the same phase, after copying, but before adding to data.raw.
with merge, you do additions and tag replacements inside the merge, but then deletions or table replacements after it.
Also like deepcopy, you could actually save the result of util.merge to a variable then add it to data in the same way you do in deepcopy, but the difference is, because you're already changing the name in the merge, you CAN pipe the result straight into data:extend if you want to, and I usually do because most merges don't require additional editing. Boiler is one of the examples where I do change the table afterwards, and there have been a couple of cases where I set a tag to nil.
- eradicator
- Smart Inserter
- Posts: 5206
- Joined: Tue Jul 12, 2016 9:03 am
- Contact:
Re: Creating a Mod
The problem with recommending it to beginning modders is that it behaves in unexpected ways. I didn't even know the thing existed before you mentioned it here, and when i looked at the source was quite astonished that it does a recursive merge instead of a first level merge as i would have expected from the name. I personally use something similar to this (heavily simplified):bobingabout wrote: ↑Tue Oct 16, 2018 8:14 amSo you're right, [the merge method is] not perfect, but the examples where you want to delete lines are usually the minority, not the majority.
Code: Select all
local function set__union_of_keys (self,table2)
for k,v in pairs(table2) do
self[k] = table.deepcopy(v)
end
return self
end
Especially if you want to remove something it becomes unintuitive. E.g:
Code: Select all
data:extend{util.merge{data.raw.container['steel-chest'],{
name = 'my-invisible-chest',
collision_box = nil,
selection_box = nil
}}
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Creating a Mod
Still, I prefer it to table.deepcopy.eradicator wrote: ↑Tue Oct 16, 2018 8:38 amThe problem with recommending it to beginning modders is that it behaves in unexpected ways. I didn't even know the thing existed before you mentioned it here, and when i looked at the source was quite astonished that it does a recursive merge instead of a first level merge as i would have expected from the name. I personally use something similar to this (heavily simplified):bobingabout wrote: ↑Tue Oct 16, 2018 8:14 amSo you're right, [the merge method is] not perfect, but the examples where you want to delete lines are usually the minority, not the majority.
note, util.table.deepcopy exists too, they're trying to put everything like that in util, the main reason it still exists outside of util is because it would break so many mods if they removed the non-util version of it. it kinda proves that merge is kind of new on the list. (also that it internally uses deepcopy proves deepcopy is older.)
Anyway... I still prefer merge over deepcopy.
I also wrote my own version of merge before merge itself was added, it's in my library, it also edits the table directly, not making a new one. I used to use it before the settings GUI was added in game to modify entire entities, since it basically just applied your edited settings table to data.
- eradicator
- Smart Inserter
- Posts: 5206
- Joined: Tue Jul 12, 2016 9:03 am
- Contact:
Re: Creating a Mod
My argument was soley that i think deepcopy is better for inexperienced modders. I'm not trying to tell you what to do ;).
Btw, i thought of another fun example with merge.
Exercise 1) We want to make a fireproof inserter. Answer the resulting flags table of each method and explain how you came to that conclusion.
The base prototypes flags look like this:
Code: Select all
--defined by the base game
{
name = "inserter",
type = "inserter",
flags = {"placeable-neutral", "placeable-player", "player-creation"}
}
Code: Select all
data:extend{util.merge{data.raw.inserter.inserter,{
name = 'my-fireproof-inserter',
flags = {'not-flammable'},
}
}}
Code: Select all
local myinserter = util.table.deepcopy(data.raw.inserter.inserter)
myinserter .name = 'my-fireproof-inserter'
table.insert(myinserter.flags,'not-flammable')
data:extend{myinserter}
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Creating a Mod
I like this one.eradicator wrote: ↑Tue Oct 16, 2018 9:56 ama) the merge method:Code: Select all
data:extend{util.merge{data.raw.inserter.inserter,{ name = 'my-fireproof-inserter', flags = {'not-flammable'}, } }}
Also you did it wrong, util.merge should open with (, not {.
Code: Select all
data:extend{util.merge(data.raw.inserter.inserter,{
name = 'my-fireproof-inserter',
flags = {'not-flammable'},
}
)
}
- eradicator
- Smart Inserter
- Posts: 5206
- Joined: Tue Jul 12, 2016 9:03 am
- Contact:
Re: Creating a Mod
That's the buggy one that removes the "placeable-neutral" flag :p.bobingabout wrote: ↑Tue Oct 16, 2018 1:56 pmI like this one.eradicator wrote: ↑Tue Oct 16, 2018 9:56 ama) the merge method:Code: Select all
data:extend{util.merge(data.raw.inserter.inserter,{ name = 'my-fireproof-inserter', flags = {'not-flammable'}, } )}
Due to the recursive nature of merge it'll overwrite the first key in flags, but keep the the others because the table being merged only has one key. So you end up with
Code: Select all
flags = {"not-flammable", "placeable-player", "player-creation"}
Code: Select all
flags = {"placeable-neutral", "placeable-player", "player-creation","not-flammable"}
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Creating a Mod
I should have known that. You can see how long it's been since I've actually sit down and modded properly. (I did actually know that, but it slipped my mind)eradicator wrote: ↑Tue Oct 16, 2018 2:04 pmDue to the recursive nature of merge it'll overwrite the first key in flags, but keep the the others because the table being merged only has one key. So you end up withinstead of the desiredCode: Select all
flags = {"not-flammable", "placeable-player", "player-creation"}
Code: Select all
flags = {"placeable-neutral", "placeable-player", "player-creation","not-flammable"}
my last real effort in factorio was on the programming side. I've done very little in the way of modding in the past... 4 or 5 months.
- eradicator
- Smart Inserter
- Posts: 5206
- Joined: Tue Jul 12, 2016 9:03 am
- Contact:
Re: Creating a Mod
And now you will serve as an eternal example of how easy it is to create hidden bugs with merge().bobingabout wrote: ↑Wed Oct 17, 2018 7:43 amI should have known that. You can see how long it's been since I've actually sit down and modded properly. (I did actually know that, but it slipped my mind)eradicator wrote: ↑Tue Oct 16, 2018 2:04 pmDue to the recursive nature of merge it'll overwrite the first key in flags, but keep the the others because the table being merged only has one key. So you end up withinstead of the desiredCode: Select all
flags = {"not-flammable", "placeable-player", "player-creation"}
Code: Select all
flags = {"placeable-neutral", "placeable-player", "player-creation","not-flammable"}
my last real effort in factorio was on the programming side. I've done very little in the way of modding in the past... 4 or 5 months.
Beginners should stick to deepcopy(). Q.E.D.
Oh, and btw we should probably get back on topic... *cough*.
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.
Re: Creating a Mod
Why util.merge does not available in control.lua?bobingabout wrote: ↑Mon Oct 15, 2018 8:45 amutil.merge makes use of table.deepcopy internally to copy tables, but what it does is apply 1 table as changes to another as it copies it.
The method is newtable = util.merge(original table, changes table), and is used in this forma
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Creating a Mod
I think you have to include it before you can use it in scripting. I'm not going to give an example though, because It's something I'd have to look into first.darkfrei wrote: ↑Sun Nov 18, 2018 2:41 pmWhy util.merge does not available in control.lua?bobingabout wrote: ↑Mon Oct 15, 2018 8:45 amutil.merge makes use of table.deepcopy internally to copy tables, but what it does is apply 1 table as changes to another as it copies it.
The method is newtable = util.merge(original table, changes table), and is used in this forma