Ensure to be loaded last
- SegFault22
- Member
- Posts: 872
- Joined: Mon May 21, 2012 03:17
- Location: NaN
Ensure to be loaded last
I'm working on a mod where it would be a great advantage to "force" the mod to be loaded last. I am working on an algorithm to list the mods which add items, the items which they add, and to add compatibility with the materials api/system (while respecting those mods' naming conventions, when applicable). For mods which add materials that are also added by other mods, all of the items (which are basically the same thing, but are added by separate mods) get "unified" and are treated as the same thing in recipes - the items from the mods would still be defined as separate items (so they would still stack differently), but they would be interchangeable in recipes.
If any mods which add their own materials are loaded after this mod, their items would not be detected, and compatibility with other mods' similar items would not be available. I don't want to have to name the mod with special characters that put it at the end of the list, so is there some way (other than abusing the currently existing dependencies system) to force the mod to be loaded last?
If any mods which add their own materials are loaded after this mod, their items would not be detected, and compatibility with other mods' similar items would not be available. I don't want to have to name the mod with special characters that put it at the end of the list, so is there some way (other than abusing the currently existing dependencies system) to force the mod to be loaded last?
- BrandonReese
- Member
- Posts: 839
- Joined: Wed Sep 12, 2012 00:44
- GitHub: bremaweb
- IRC: BrandonReese
- In-game: BrandonReese
- Location: USA
Re: Ensure to be loaded last
Will it not work to use minetest.after to run your function x seconds after everything has loaded?
- HeroOfTheWinds
- Member
- Posts: 470
- Joined: Wed Apr 23, 2014 23:16
- GitHub: HeroOfTheWinds
- IRC: WindHero
- Location: Hawaii
Re: Ensure to be loaded last
Considering that such a mod must have some sort of formspec or chat dialogue, it would not need to preload the other mods. It can merely compile the list when requested. And to do so, it would be very easy to reference the registered_* tables to find those items. (perhaps even tweak them?)
Since your mod causes craft items to be interchangeable if they are duplicates, this function would run whenever someone tries to craft an applicable object. Hence, it is after all mods are loaded.
Since your mod causes craft items to be interchangeable if they are duplicates, this function would run whenever someone tries to craft an applicable object. Hence, it is after all mods are loaded.
Nam ex spatio, omnes res venire possunt.
Why let the ground limit you when you can reach for the sky?
Back to college now, yay for sophomore year schedules. :P
Why let the ground limit you when you can reach for the sky?
Back to college now, yay for sophomore year schedules. :P
- rubenwardy
- Moderator
- Posts: 6978
- Joined: Tue Jun 12, 2012 18:11
- GitHub: rubenwardy
- IRC: rubenwardy
- In-game: rubenwardy
- Location: Bristol, United Kingdom
- Contact:
Re: Ensure to be loaded last
If you're adding groups to items, it needs to be done at load time as node def are sent to the client, and crafting is client side predicted. I'm not absolutely sure, confirmation on this would be needed.
My food mod handles multiple dependecies in a similar way. Although, it soft depends and adds groups to a known list of items, rather than detecting from the item name.
How about going through registered_items, then overriding register_item to catch any mods loaded after your one?
My food mod handles multiple dependecies in a similar way. Although, it soft depends and adds groups to a known list of items, rather than detecting from the item name.
How about going through registered_items, then overriding register_item to catch any mods loaded after your one?
- SegFault22
- Member
- Posts: 872
- Joined: Mon May 21, 2012 03:17
- Location: NaN
Re: Ensure to be loaded last
I would prefer not to use minetest.after for that, because any function (especially one registering items) which is executed after the timer has expired would not be usable by (or visible to) the function which makes the compatibility work. It also would leave the system idle for some time during loading, while it waits for the timer to expire. Unless there is some way to make minetest.after strictly adhere to executing the function only after all of the other mods in the mods folder have loaded, I will (unfortunately) have to get users to include every mod (which they want compatibility enabled for) in the depends.txt list of the mod.
It might be possible to include entries in the depends.txt list, followed by the question-mark-sign, for each known mod which adds considerable resource/material items, but that method offers no detection of mods which are not already known to add materials.
I will use minetest.after() for some similar issues, but not in the mod-loading/item-registering level
edit1: I intend to make registered crafting-grid recipes use groups instead of specific items, that way the items in the specified group can be used, regardless of what mod they are from. Also, since it is not possible to register more items after the mods are all loaded and the game (server) is initialized, the mod must load after the other mods (which add materials) have all been loaded, so that items (such as plates made from metals, nuggets for all metals, dust piles for all metals, and such) can be registered for the materials added by other mods, which are not included in my mod.
It might be possible to include entries in the depends.txt list, followed by the question-mark-sign, for each known mod which adds considerable resource/material items, but that method offers no detection of mods which are not already known to add materials.
I will use minetest.after() for some similar issues, but not in the mod-loading/item-registering level
edit1: I intend to make registered crafting-grid recipes use groups instead of specific items, that way the items in the specified group can be used, regardless of what mod they are from. Also, since it is not possible to register more items after the mods are all loaded and the game (server) is initialized, the mod must load after the other mods (which add materials) have all been loaded, so that items (such as plates made from metals, nuggets for all metals, dust piles for all metals, and such) can be registered for the materials added by other mods, which are not included in my mod.
- rubenwardy
- Moderator
- Posts: 6978
- Joined: Tue Jun 12, 2012 18:11
- GitHub: rubenwardy
- IRC: rubenwardy
- In-game: rubenwardy
- Location: Bristol, United Kingdom
- Contact:
Re: Ensure to be loaded last
minetest.after never runs during the load stage, always during game ticks.
My suggestion would work, you can register other items in your overridden register_item.
Please note, I think register_node calls register_item, so no need to override the former.
My suggestion would work, you can register other items in your overridden register_item.
Please note, I think register_node calls register_item, so no need to override the former.
- SegFault22
- Member
- Posts: 872
- Joined: Mon May 21, 2012 03:17
- Location: NaN
Re: Ensure to be loaded last
If minetest.after never runs during the load phase, the code registering items made from the materials (added by other mods) would be called after the server starts tick-ing. If I remember correctly, items can only be registered during the load phase. If there is some way to register items after the game (server) is initialized, there would have to be some way to prevent already existing items from turning into unknowns, after the game is initialized but before the items are registered. If there is some way around those problems, it would be possible to use minetest.after() for the purpose.
- rubenwardy
- Moderator
- Posts: 6978
- Joined: Tue Jun 12, 2012 18:11
- GitHub: rubenwardy
- IRC: rubenwardy
- In-game: rubenwardy
- Location: Bristol, United Kingdom
- Contact:
Re: Ensure to be loaded last
minetest.after is not a solution to this problem if you need to register craft recipes or items.
Why would this not work?
Why would this not work?
Code: Select all
minetest.register_craft({
output = "mymod:item",
recipe = {
{"group:ore"}
}
})
for name, data in pairs(minetest.registered_items) do
if name:find("ore") >= 0 then
local g = {}
if data.groups then
for k, v in pairs(data.groups) do
g[k] = v
end
end
g.ore = 1
minetest.override_item(name, {groups = g})
end
end
local old_reg = minetest.register_item
function minetest.register_item(name, date)
if name:find("ore") >= 0 then
if data.groups then
local g = {}
for k, v in pairs(data.groups) do
g[k] = v
end
g.ore = 1
data.groups = g
else
data.groups = {ore = 1}
end
end
old_reg(name, data)
end
- SegFault22
- Member
- Posts: 872
- Joined: Mon May 21, 2012 03:17
- Location: NaN
Re: Ensure to be loaded last
A lot of that code will work for a lot of the things I'm making the mod to do. However, the code that reads the registered items list must only execute after other mods have registered their materials, because the items (ingots, lumps, nuggets, piles of dust or grains, crystals, etc.) have to be registered before they can be read from the list and interpreted by the list-reading function as materials, for which to add items/recipes and change item definitions to include groups (which would be used as reference in crafting or other processing recipes, such that different items made of an identical material can be used interchangeably). If there is no way (by the current api) to force a mod to load last, I can get around the problem by adding all known mods which add materials to the optional dependencies (so that the mod is loaded after those mods only if they are present) - however, if a user using the mod also uses a mod which adds materials, but such mod is not indexed in the list as adding materials, they will have to add the optional dependency (and possibly report it so that the mod id can be added to the optional dependencies).
Thank you for the sample of code, some of it is structured in a way that I haven't used yet - I see where it could be used to make the existing code for the mod more efficient, and introduces more options for making the rest of the code
Thank you for the sample of code, some of it is structured in a way that I haven't used yet - I see where it could be used to make the existing code for the mod more efficient, and introduces more options for making the rest of the code
Re: Ensure to be loaded last
This is an idea for an api for use with two dimensional array(s) of object-subtypes.
ie:
allowing mods to cooperate together through a common dependency on the api.
Unfortunately, it doesn't auto register nodes by reading node groups so this would be most useful in a game where mods could be altered to make use of it. Perhaps using minetest.get_modnames to find mods and create recipes with not-necessarily-defined-yet nodes in the same way that dye mod does with flowers would be a good solution.
ie:
- not just a bucket that can be filled with various liquids but also various
types of buckets that can do the same.
or tools made of various metals:
add a metal and a new shovel, sword, pick, and axe are auto-generated;
add another tool and stone, bronze, and steel versions of it are created.
allowing mods to cooperate together through a common dependency on the api.
Unfortunately, it doesn't auto register nodes by reading node groups so this would be most useful in a game where mods could be altered to make use of it. Perhaps using minetest.get_modnames to find mods and create recipes with not-necessarily-defined-yet nodes in the same way that dye mod does with flowers would be a good solution.
Code: Select all
if not minetest then
minetest = {}
minetest.log = print
minetest.after = function(t,f) return f end
end
local meta = {} -- registration meta helper
meta.registered = {}
meta.register = {}
local func_flags = {} -- helper for method 'new_registration_func'
-- registration function for creating new categories
-- this registers two wrapper functions that loop through either of two tables
-- calling the main registration function as needed
function meta:new(tbl1_name, tbl2_name, registration_function, flag1, flag2)
local tbl1, tbl2 = {}, {}
-- register global tables
-- only the first table is saved by default
if flag1 ~= false then self.registered[tbl1_name] = tbl1 end
if flag2 == true then self.registered[tbl2_name] = tbl2 end
-- this calls register(tbl1_k, tbl2_k, tbl1_v, tbl2_v)
local register = registration_function
-- default registration function for a new tbl1 key
local func1 = function(new_key, new_val)
tbl1[new_key] = new_val
for tbl2_k,tbl2_v in pairs(tbl2) do
register(new_key, tbl2_k, new_val, tbl2_v)
end
end
-- default registration function for a new tbl2 key
local func2 = function(new_key, new_val)
tbl2[new_key] = new_val
for tbl1_k,tbl1_v in pairs(tbl1) do
register(tbl1_k, new_key, tbl1_v, new_val)
end
end
-- assign registration function for tbl1
self.register[tbl1_name] =
( self.register[tbl1_name] and func_flags[tbl1_name] ) and
function(...) return func1( self.register[tbl1_name](...) ) end
or func1
-- assign registration function for tbl2
self.register[tbl2_name] =
( self.register[tbl2_name] and func_flags[tbl2_name] ) and
function(...) return func2( self.register[tbl2_name](...) ) end
or func2
end
-- overwrite or add-to the default registration functions
-- flag causes the old or default registration function to be called with the
-- return value of the new registration function
function meta:new_registration_func(name, new_func, flag)
local old_func = self.register[name]
if flag and old_func then
self.register[name] = function(...)
return old_func( new_func(...) )
end
else
-- in case 'new_registration_func' is called before 'new'
func_flags[name] = flag
materials_api.register[name] = new_func
end
end
materials_api = meta
minetest.after(0, function()
material_api.new = nil
end)
---------- example usage ----------------
-- create new category
materials_api:new("foo", "bar", function(foo_name, bar_name, foo_val, bar_val)
-- do some application level stuff here...
minetest.log("action", "[materials_api] Registered: ".. foo_name .." ".. bar_name)
if not foo_val then minetest.log("warning", "no foo val") end
if not bar_val then minetest.log("warning", "no bar val") end
end)
-- register new item for bar
materials_api.register.bar("beer", {
image_overlay = "material_bar_beer.png"
})
-- register new item for foo
materials_api.register.foo("banana", {
image = "material_foo_banana.png"
})
-- register new item for foo
materials_api.register.foo("poptart", {
image = "material_foo_poptart.png"
})
-- register new item for bar
materials_api.register.bar("daiquiri", {
image_overlay = "material_bar_daiquiri.png"
})
-- register new item for foo
materials_api.register.foo("strawberry", {
image = "material_foo_strawberry.png"
})
Who is online
Users browsing this forum: No registered users and 16 guests