Add a callback: minetest.register_on_craft(itemstack, player,
authorNovatux <nathanael.courant@laposte.net>
Sat, 26 Oct 2013 09:25:28 +0000 (11:25 +0200)
committerNovatux <nathanael.courant@laposte.net>
Fri, 1 Nov 2013 14:55:34 +0000 (15:55 +0100)
old_craft_grid, craft_inv) and
minetest.register_craft_predict(itemstack, player, old_craft_grid,
craft_inv)

builtin/misc_register.lua
doc/lua_api.txt
src/inventorymanager.cpp
src/script/cpp_api/s_item.cpp
src/script/cpp_api/s_item.h
src/server.cpp

index f1d8161245c2ef8a9ebfb6dc8195e63fc010c33b..aa8399f1631770845fc18316b04df05a7905e25f 100644 (file)
@@ -230,6 +230,20 @@ function minetest.register_biome(biome)
        register_biome_raw(biome)
 end
 
+function minetest.on_craft(itemstack, player, old_craft_list, craft_inv)
+       for _, func in ipairs(minetest.registered_on_crafts) do
+               itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
+       end
+       return itemstack
+end
+
+function minetest.craft_predict(itemstack, player, old_craft_list, craft_inv)
+       for _, func in ipairs(minetest.registered_craft_predicts) do
+               itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
+       end
+       return itemstack
+end
+
 -- Alias the forbidden item names to "" so they can't be
 -- created via itemstrings (e.g. /give)
 local name
@@ -327,4 +341,6 @@ minetest.registered_on_joinplayers, minetest.register_on_joinplayer = make_regis
 minetest.registered_on_leaveplayers, minetest.register_on_leaveplayer = make_registration()
 minetest.registered_on_player_receive_fields, minetest.register_on_player_receive_fields = make_registration_reverse()
 minetest.registered_on_cheats, minetest.register_on_cheat = make_registration()
+minetest.registered_on_crafts, minetest.register_on_craft = make_registration()
+minetest.registered_craft_predicts, minetest.register_craft_predict = make_registration()
 
index 5a0d5817f284ad51359dc1bd740a982953e8a230..e94fd30a9114378951c8bdf9c1f34a33e0ecc575 100644 (file)
@@ -1145,6 +1145,15 @@ minetest.register_on_player_receive_fields(func(player, formname, fields))
 minetest.register_on_mapgen_init(func(MapgenParams))
 ^ Called just before the map generator is initialized but before the environment is initialized
 ^ MapgenParams consists of a table with the fields mgname, seed, water_level, and flags
+minetest.register_on_craft(func(itemstack, player, old_craft_grid, craft_inv))
+^ Called when player crafts something
+^ itemstack is the output
+^ old_craft_grid contains the recipe (Note: the one in the inventory is cleared)
+^ craft_inv is the inventory with the crafting grid
+^ Return either an ItemStack, to replace the output, or nil, to not modify it
+minetest.register_craft_predict(func(itemstack, player, old_craft_grid, craft_inv))
+^ The same as before, except that it is called before the player crafts, to make
+^ craft prediction, and it should not change anything.
 
 Other registration functions:
 minetest.register_chatcommand(cmd, chatcommand definition)
index c81f7a19e6515e1e71a8a10fb2a50f9c781cbe5d..1c511e9cbe69f7659e70e8a7a1d5e172285af73b 100644 (file)
@@ -724,13 +724,19 @@ void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGam
        }
 
        ItemStack crafted;
+       ItemStack craftresultitem;
        int count_remaining = count;
        bool found = getCraftingResult(inv_craft, crafted, false, gamedef);
+       PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv);
+       found = !crafted.empty();
 
        while(found && list_craftresult->itemFits(0, crafted))
        {
+               InventoryList saved_craft_list = *list_craft;
+               
                // Decrement input and add crafting output
                getCraftingResult(inv_craft, crafted, true, gamedef);
+               PLAYER_TO_SA(player)->item_OnCraft(crafted, player, &saved_craft_list, craft_inv);
                list_craftresult->addItem(0, crafted);
                mgr->setInventoryModified(craft_inv);
 
@@ -747,6 +753,8 @@ void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGam
 
                // Get next crafting result
                found = getCraftingResult(inv_craft, crafted, false, gamedef);
+               PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv);
+               found = !crafted.empty();
        }
 
        infostream<<"ICraftAction::apply(): crafted "
index b4536ac63b95b49184a5096abb31e000b6637a7d..1d5f218cf1e20c07b84540b1cc6443b5465746cb 100644 (file)
@@ -22,9 +22,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "common/c_converter.h"
 #include "common/c_content.h"
 #include "lua_api/l_item.h"
+#include "lua_api/l_inventory.h"
 #include "server.h"
 #include "log.h"
 #include "util/pointedthing.h"
+#include "inventory.h"
+#include "inventorymanager.h"
 
 bool ScriptApiItem::item_OnDrop(ItemStack &item,
                ServerActiveObject *dropper, v3f pos)
@@ -86,6 +89,54 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
        return true;
 }
 
+bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
+               const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "minetest");
+       lua_getfield(L, -1, "on_craft");
+       LuaItemStack::create(L, item);
+       objectrefGetOrCreate(user);
+       
+       //Push inventory list
+       std::vector<ItemStack> items;
+       for(u32 i=0; i<old_craft_grid->getSize(); i++)
+               items.push_back(old_craft_grid->getItem(i));
+       push_items(L, items);
+
+       InvRef::create(L, craft_inv);
+       if(lua_pcall(L, 4, 1, 0))
+               scriptError("error: %s", lua_tostring(L, -1));
+       if(!lua_isnil(L, -1))
+               item = read_item(L,-1, getServer());
+       return true;
+}
+
+bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
+               const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
+{
+       SCRIPTAPI_PRECHECKHEADER
+
+       lua_getglobal(L, "minetest");
+       lua_getfield(L, -1, "craft_predict");
+       LuaItemStack::create(L, item);
+       objectrefGetOrCreate(user);
+       
+       //Push inventory list
+       std::vector<ItemStack> items;
+       for(u32 i=0; i<old_craft_grid->getSize(); i++)
+               items.push_back(old_craft_grid->getItem(i));
+       push_items(L, items);
+
+       InvRef::create(L, craft_inv);
+       if(lua_pcall(L, 4, 1, 0))
+               scriptError("error: %s", lua_tostring(L, -1));
+       if(!lua_isnil(L, -1))
+               item = read_item(L,-1, getServer());
+       return true;
+}
+
 // Retrieves minetest.registered_items[name][callbackname]
 // If that is nil or on error, return false and stack is unchanged
 // If that is a function, returns true and pushes the
index 0f2b160429d1ec432d4914f3b22b696fa49e90f8..4964dd5b422a467b5674454ae9b5cb9b7417a032 100644 (file)
@@ -29,6 +29,8 @@ class ServerActiveObject;
 struct ItemDefinition;
 class LuaItemStack;
 class ModApiItemMod;
+class InventoryList;
+class InventoryLocation;
 
 class ScriptApiItem
 : virtual public ScriptApiBase
@@ -40,6 +42,10 @@ public:
                        ServerActiveObject *placer, const PointedThing &pointed);
        bool item_OnUse(ItemStack &item,
                        ServerActiveObject *user, const PointedThing &pointed);
+       bool item_OnCraft(ItemStack &item, ServerActiveObject *user,
+                       const InventoryList *old_craft_grid, const InventoryLocation &craft_inv);
+       bool item_CraftPredict(ItemStack &item, ServerActiveObject *user,
+                       const InventoryList *old_craft_grid, const InventoryLocation &craft_inv);
 
 protected:
        friend class LuaItemStack;
index 8350b7013a9cefe1bc600c3eae843b5d04608bb7..c29ec3d83583de73c670ba7bc2dae0035f0ddfcc 100644 (file)
@@ -4775,7 +4775,10 @@ void Server::UpdateCrafting(u16 peer_id)
 
        // Get a preview for crafting
        ItemStack preview;
+       InventoryLocation loc;
+       loc.setPlayer(player->getName());
        getCraftingResult(&player->inventory, preview, false, this);
+       m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
 
        // Put the new preview in
        InventoryList *plist = player->inventory.getList("craftpreview");