]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/server.cpp
builtin.lua
[dragonfireclient.git] / src / server.cpp
index 330ce21c2c912cdeccd8e6e8c78d74f7df6c3538..6d34a0fac1dd89f323f5775463714385f11a661f 100644 (file)
@@ -41,6 +41,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include "script.h"
 #include "scriptapi.h"
+#include "nodedef.h"
+#include "tooldef.h"
+#include "craftdef.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -685,7 +688,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                                //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
                                // Allow two blocks in queue per client
                                //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
-                               if(server->m_emerge_queue.peerItemCount(peer_id) < 25)
+                               u32 max_emerge = 25;
+                               // Make it more responsive when needing to generate stuff
+                               if(surely_not_found_on_disk)
+                                       max_emerge = 5;
+                               if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
                                {
                                        //infostream<<"Adding block to emerge queue"<<std::endl;
                                        
@@ -942,6 +949,35 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
        return checksum;
 }
 
+struct ModSpec
+{
+       std::string name;
+       std::string path;
+
+       ModSpec(const std::string &name_="", const std::string path_=""):
+               name(name_),
+               path(path_)
+       {}
+};
+
+static core::list<ModSpec> getMods(core::list<std::string> &modspaths)
+{
+       core::list<ModSpec> mods;
+       for(core::list<std::string>::Iterator i = modspaths.begin();
+                       i != modspaths.end(); i++){
+               std::string modspath = *i;
+               std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
+               for(u32 j=0; j<dirlist.size(); j++){
+                       if(!dirlist[j].dir)
+                               continue;
+                       std::string modname = dirlist[j].name;
+                       std::string modpath = modspath + DIR_DELIM + modname;
+                       mods.push_back(ModSpec(modname, modpath));
+               }
+       }
+       return mods;
+}
+
 /*
        Server
 */
@@ -955,7 +991,9 @@ Server::Server(
        m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
        m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
        m_lua(NULL),
-       //m_scriptapi(NULL),
+       m_toolmgr(createToolDefManager()),
+       m_nodedef(createNodeDefManager()),
+       m_craftdef(createCraftDefManager()),
        m_thread(this),
        m_emergethread(this),
        m_time_counter(0),
@@ -980,7 +1018,17 @@ Server::Server(
 
        JMutexAutoLock envlock(m_env_mutex);
        JMutexAutoLock conlock(m_con_mutex);
+
+       infostream<<"m_nodedef="<<m_nodedef<<std::endl;
        
+       // Initialize default node definitions
+       content_mapnode_init(m_nodedef);
+       
+       // Path to builtin.lua
+       std::string builtinpath = porting::path_data + DIR_DELIM + "builtin.lua";
+       // Add default global mod path
+       m_modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
+
        // Initialize scripting
        
        infostream<<"Server: Initializing scripting"<<std::endl;
@@ -988,19 +1036,33 @@ Server::Server(
        assert(m_lua);
        // Export API
        scriptapi_export(m_lua, this);
-       // Load and run scripts
-       std::string defaultscript = porting::path_data + DIR_DELIM
-                       + "scripts" + DIR_DELIM + "default.lua";
-       bool success = script_load(m_lua, defaultscript.c_str());
+       // Load and run builtin.lua
+       infostream<<"Server: Loading builtin Lua stuff from \""<<builtinpath
+                       <<"\""<<std::endl;
+       bool success = script_load(m_lua, builtinpath.c_str());
        if(!success){
                errorstream<<"Server: Failed to load and run "
-                               <<defaultscript<<std::endl;
+                               <<builtinpath<<std::endl;
                assert(0);
        }
+       // Load and run "mod" scripts
+       core::list<ModSpec> mods = getMods(m_modspaths);
+       for(core::list<ModSpec>::Iterator i = mods.begin();
+                       i != mods.end(); i++){
+               ModSpec mod = *i;
+               infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
+               std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
+               bool success = script_load(m_lua, scriptpath.c_str());
+               if(!success){
+                       errorstream<<"Server: Failed to load and run "
+                                       <<scriptpath<<std::endl;
+                       assert(0);
+               }
+       }
        
        // Initialize Environment
        
-       m_env = new ServerEnvironment(new ServerMap(mapsavedir), m_lua);
+       m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, this);
 
        // Give environment reference to scripting api
        scriptapi_add_environment(m_lua, m_env);
@@ -1099,6 +1161,9 @@ Server::~Server()
 
        // Delete Environment
        delete m_env;
+
+       delete m_toolmgr;
+       delete m_nodedef;
        
        // Deinitialize scripting
        infostream<<"Server: Deinitializing scripting"<<std::endl;
@@ -1250,7 +1315,7 @@ void Server::AsyncRunStep()
                m_env->step(dtime);
        }
                
-       const float map_timer_and_unload_dtime = 5.15;
+       const float map_timer_and_unload_dtime = 2.92;
        if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
        {
                JMutexAutoLock lock(m_env_mutex);
@@ -2090,6 +2155,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                /*
                        Send some initialization data
                */
+
+               // Send tool definitions
+               SendToolDef(m_con, peer_id, m_toolmgr);
+               
+               // Send node definitions
+               SendNodeDef(m_con, peer_id, m_nodedef);
+               
+               // Send textures
+               SendTextures(peer_id);
                
                // Send player info to all players
                SendPlayerInfos();
@@ -2299,10 +2373,23 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        return;
                
                //TODO: Check that object is reasonably close
+       
+               // Get ServerRemotePlayer
+               ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
+
+               // Update wielded item
+               srp->wieldItem(item_i);
                
-               // Left click, pick object up (usually)
+               // Left click, pick/punch
                if(button == 0)
                {
+                       actionstream<<player->getName()<<" punches object "
+                                       <<obj->getId()<<std::endl;
+                       
+                       // Do stuff
+                       obj->punch(srp);
+                       
+#if 0
                        /*
                                Try creating inventory item
                        */
@@ -2371,6 +2458,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        SendInventory(player->peer_id);
                                }
                        }
+#endif
                }
                // Right click, do something with object
                if(button == 1)
@@ -2378,18 +2466,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        actionstream<<player->getName()<<" right clicks object "
                                        <<obj->getId()<<std::endl;
 
-                       // Track hp changes super-crappily
-                       u16 oldhp = player->hp;
-                       
                        // Do stuff
-                       obj->rightClick(player);
-                       
-                       // Send back stuff
-                       if(player->hp != oldhp)
-                       {
-                               SendPlayerHP(player);
-                       }
+                       obj->rightClick(srp);
                }
+
+               /*
+                       Update player state to client
+               */
+               SendPlayerHP(player);
+               UpdateCrafting(player->peer_id);
+               SendInventory(player->peer_id);
        }
        else if(command == TOSERVER_GROUND_ACTION)
        {
@@ -2430,6 +2516,33 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                NOTE: This can be used in the future to check if
                                somebody is cheating, by checking the timing.
                        */
+                       bool cannot_punch_node = false;
+
+                       MapNode n(CONTENT_IGNORE);
+
+                       try
+                       {
+                               n = m_env->getMap().getNode(p_under);
+                       }
+                       catch(InvalidPositionException &e)
+                       {
+                               infostream<<"Server: Not punching: Node not found."
+                                               <<" Adding block to emerge queue."
+                                               <<std::endl;
+                               m_emerge_queue.addBlock(peer_id,
+                                               getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
+                               cannot_punch_node = true;
+                       }
+
+                       if(cannot_punch_node)
+                               return;
+
+                       /*
+                               Run script hook
+                       */
+                       ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
+                       scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
+
                } // action == 0
 
                /*
@@ -2456,19 +2569,20 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        u8 mineral = MINERAL_NONE;
 
                        bool cannot_remove_node = false;
-
+                       
+                       MapNode n(CONTENT_IGNORE);
                        try
                        {
-                               MapNode n = m_env->getMap().getNode(p_under);
+                               n = m_env->getMap().getNode(p_under);
                                // Get mineral
-                               mineral = n.getMineral();
+                               mineral = n.getMineral(m_nodedef);
                                // Get material at position
                                material = n.getContent();
                                // If not yet cancelled
                                if(cannot_remove_node == false)
                                {
                                        // If it's not diggable, do nothing
-                                       if(content_diggable(material) == false)
+                                       if(m_nodedef->get(material).diggable == false)
                                        {
                                                infostream<<"Server: Not finishing digging: "
                                                                <<"Node not diggable"
@@ -2561,8 +2675,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                std::string toolname = titem->getToolName();
 
                                                // Get digging properties for material and tool
+                                               ToolDiggingProperties tp =
+                                                               m_toolmgr->getDiggingProperties(toolname);
                                                DiggingProperties prop =
-                                                               getDiggingProperties(material, toolname);
+                                                               getDiggingProperties(material, &tp, m_nodedef);
 
                                                if(prop.diggable == false)
                                                {
@@ -2587,16 +2703,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                InventoryItem *item = NULL;
 
                                if(mineral != MINERAL_NONE)
-                                       item = getDiggedMineralItem(mineral);
+                                       item = getDiggedMineralItem(mineral, this);
                                
                                // If not mineral
                                if(item == NULL)
                                {
-                                       std::string &dug_s = content_features(material).dug_item;
+                                       const std::string &dug_s = m_nodedef->get(material).dug_item;
                                        if(dug_s != "")
                                        {
                                                std::istringstream is(dug_s, std::ios::binary);
-                                               item = InventoryItem::deSerialize(is);
+                                               item = InventoryItem::deSerialize(is, this);
                                        }
                                }
                                
@@ -2613,25 +2729,25 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                item = NULL;
 
                                if(mineral != MINERAL_NONE)
-                                 item = getDiggedMineralItem(mineral);
+                                 item = getDiggedMineralItem(mineral, this);
                        
                                // If not mineral
                                if(item == NULL)
                                {
-                                       std::string &extra_dug_s = content_features(material).extra_dug_item;
-                                       s32 extra_rarity = content_features(material).extra_dug_item_rarity;
+                                       const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
+                                       s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
                                        if(extra_dug_s != "" && extra_rarity != 0
                                           && myrand() % extra_rarity == 0)
                                        {
-                                               std::istringstream is(extra_dug_s, std::ios::binary);
-                                               item = InventoryItem::deSerialize(is);
+                                               std::istringstream is(extra_dug_s, std::ios::binary);
+                                               item = InventoryItem::deSerialize(is, this);
                                        }
                                }
                        
                                if(item != NULL)
                                {
-                                       // Add a item to inventory
-                                       player->inventory.addItem("main", item);
+                                       // Add a item to inventory
+                                       player->inventory.addItem("main", item);
 
                                        // Send inventory
                                        UpdateCrafting(player->peer_id);
@@ -2661,6 +2777,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        continue;
                                client->SetBlocksNotSent(modified_blocks);
                        }
+
+                       /*
+                               Run script hook
+                       */
+                       ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
+                       scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
                }
                
                /*
@@ -2695,7 +2817,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                        <<" because privileges are "<<getPlayerPrivs(player)
                                                        <<std::endl;
 
-                                       if(content_features(n2).buildable_to == false
+                                       if(m_nodedef->get(n2).buildable_to == false
                                                || no_enough_privs)
                                        {
                                                // Client probably has wrong data.
@@ -2733,11 +2855,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                <<" at "<<PP(p_under)<<std::endl;
                        
                                // Calculate direction for wall mounted stuff
-                               if(content_features(n).wall_mounted)
+                               if(m_nodedef->get(n).wall_mounted)
                                        n.param2 = packDir(p_under - p_over);
 
                                // Calculate the direction for furnaces and chests and stuff
-                               if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
+                               if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
                                {
                                        v3f playerpos = player->getPosition();
                                        v3f blockpos = intToFloat(p_over, BS) - playerpos;
@@ -2804,11 +2926,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        client->SetBlocksNotSent(modified_blocks);
                                }
 
+                               /*
+                                       Run script hook
+                               */
+                               ServerRemotePlayer *srp = (ServerRemotePlayer*)player;
+                               scriptapi_environment_on_placenode(m_lua, p_over, n, srp);
+
                                /*
                                        Calculate special events
                                */
                                
-                               /*if(n.d == CONTENT_MESE)
+                               /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
                                {
                                        u32 count = 0;
                                        for(s16 z=-1; z<=1; z++)
@@ -2965,7 +3093,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
                if(!meta)
                        return;
-               if(meta->typeId() != CONTENT_SIGN_WALL)
+               if(meta->typeId() != LEGN(m_nodedef, "CONTENT_SIGN_WALL"))
                        return;
                SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
                signmeta->setText(text);
@@ -2977,16 +3105,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
                if(block)
                {
-                       block->setChangedFlag();
+                       block->raiseModified(MOD_STATE_WRITE_NEEDED,
+                                       "sign node text");
                }
 
-               for(core::map<u16, RemoteClient*>::Iterator
-                       i = m_clients.getIterator();
-                       i.atEnd()==false; i++)
-               {
-                       RemoteClient *client = i.getNode()->getValue();
-                       client->SetBlockNotSent(blockpos);
-               }
+               setBlockNotSent(blockpos);
        }
        else if(command == TOSERVER_INVENTORY_ACTION)
        {
@@ -3091,7 +3214,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                p.Y = stoi(fn.next(","));
                                                p.Z = stoi(fn.next(","));
                                                NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
-                                               if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
+                                               if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) {
                                                        LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
                                                        if (lcm->getOwner() != player->getName())
                                                                return;
@@ -3109,7 +3232,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                p.Y = stoi(fn.next(","));
                                                p.Z = stoi(fn.next(","));
                                                NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
-                                               if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
+                                               if(meta && meta->typeId() == LEGN(m_nodedef, "CONTENT_LOCKABLE_CHEST")) {
                                                        LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
                                                        if (lcm->getOwner() != player->getName())
                                                                return;
@@ -3430,14 +3553,12 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
                NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
                if(meta)
                        meta->inventoryModified();
-
-               for(core::map<u16, RemoteClient*>::Iterator
-                       i = m_clients.getIterator();
-                       i.atEnd()==false; i++)
-               {
-                       RemoteClient *client = i.getNode()->getValue();
-                       client->SetBlockNotSent(blockpos);
-               }
+               
+               MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
+               if(block)
+                       block->raiseModified(MOD_STATE_WRITE_NEEDED);
+               
+               setBlockNotSent(blockpos);
 
                return;
        }
@@ -3565,6 +3686,56 @@ void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
        con.Send(peer_id, 0, data, true);
 }
 
+void Server::SendToolDef(con::Connection &con, u16 peer_id,
+               IToolDefManager *tooldef)
+{
+       DSTACK(__FUNCTION_NAME);
+       std::ostringstream os(std::ios_base::binary);
+
+       /*
+               u16 command
+               u32 length of the next item
+               serialized ToolDefManager
+       */
+       writeU16(os, TOCLIENT_TOOLDEF);
+       std::ostringstream tmp_os(std::ios::binary);
+       tooldef->serialize(tmp_os);
+       os<<serializeLongString(tmp_os.str());
+
+       // Make data buffer
+       std::string s = os.str();
+       infostream<<"Server::SendToolDef(): Sending tool definitions: size="
+                       <<s.size()<<std::endl;
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendNodeDef(con::Connection &con, u16 peer_id,
+               INodeDefManager *nodedef)
+{
+       DSTACK(__FUNCTION_NAME);
+       std::ostringstream os(std::ios_base::binary);
+
+       /*
+               u16 command
+               u32 length of the next item
+               serialized NodeDefManager
+       */
+       writeU16(os, TOCLIENT_NODEDEF);
+       std::ostringstream tmp_os(std::ios::binary);
+       nodedef->serialize(tmp_os);
+       os<<serializeLongString(tmp_os.str());
+
+       // Make data buffer
+       std::string s = os.str();
+       infostream<<"Server::SendNodeDef(): Sending node definitions: size="
+                       <<s.size()<<std::endl;
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       con.Send(peer_id, 0, data, true);
+}
+
 /*
        Non-static send methods
 */
@@ -4015,6 +4186,129 @@ void Server::SendBlocks(float dtime)
        }
 }
 
+struct SendableTexture
+{
+       std::string name;
+       std::string path;
+       std::string data;
+
+       SendableTexture(const std::string &name_="", const std::string path_="",
+                       const std::string &data_=""):
+               name(name_),
+               path(path_),
+               data(data_)
+       {}
+};
+
+void Server::SendTextures(u16 peer_id)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
+       
+       /* Read textures */
+       
+       // Put 5kB in one bunch (this is not accurate)
+       u32 bytes_per_bunch = 5000;
+       
+       core::array< core::list<SendableTexture> > texture_bunches;
+       texture_bunches.push_back(core::list<SendableTexture>());
+       
+       u32 texture_size_bunch_total = 0;
+       core::list<ModSpec> mods = getMods(m_modspaths);
+       for(core::list<ModSpec>::Iterator i = mods.begin();
+                       i != mods.end(); i++){
+               ModSpec mod = *i;
+               std::string texturepath = mod.path + DIR_DELIM + "textures";
+               std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
+               for(u32 j=0; j<dirlist.size(); j++){
+                       if(dirlist[j].dir) // Ignode dirs
+                               continue;
+                       std::string tname = dirlist[j].name;
+                       std::string tpath = texturepath + DIR_DELIM + tname;
+                       // Read data
+                       std::ifstream fis(tpath.c_str(), std::ios_base::binary);
+                       if(fis.good() == false){
+                               errorstream<<"Server::SendTextures(): Could not open \""
+                                               <<tname<<"\" for reading"<<std::endl;
+                               continue;
+                       }
+                       std::ostringstream tmp_os(std::ios_base::binary);
+                       bool bad = false;
+                       for(;;){
+                               char buf[1024];
+                               fis.read(buf, 1024);
+                               std::streamsize len = fis.gcount();
+                               tmp_os.write(buf, len);
+                               texture_size_bunch_total += len;
+                               if(fis.eof())
+                                       break;
+                               if(!fis.good()){
+                                       bad = true;
+                                       break;
+                               }
+                       }
+                       if(bad){
+                               errorstream<<"Server::SendTextures(): Failed to read \""
+                                               <<tname<<"\""<<std::endl;
+                               continue;
+                       }
+                       /*infostream<<"Server::SendTextures(): Loaded \""
+                                       <<tname<<"\""<<std::endl;*/
+                       // Put in list
+                       texture_bunches[texture_bunches.size()-1].push_back(
+                                       SendableTexture(tname, tpath, tmp_os.str()));
+                       
+                       // Start next bunch if got enough data
+                       if(texture_size_bunch_total >= bytes_per_bunch){
+                               texture_bunches.push_back(core::list<SendableTexture>());
+                               texture_size_bunch_total = 0;
+                       }
+               }
+       }
+
+       /* Create and send packets */
+       
+       u32 num_bunches = texture_bunches.size();
+       for(u32 i=0; i<num_bunches; i++)
+       {
+               /*
+                       u16 command
+                       u16 total number of texture bunches
+                       u16 index of this bunch
+                       u32 number of textures in this bunch
+                       for each texture {
+                               u16 length of name
+                               string name
+                               u32 length of data
+                               data
+                       }
+               */
+               std::ostringstream os(std::ios_base::binary);
+
+               writeU16(os, TOCLIENT_TEXTURES);
+               writeU16(os, num_bunches);
+               writeU16(os, i);
+               writeU32(os, texture_bunches[i].size());
+               
+               for(core::list<SendableTexture>::Iterator
+                               j = texture_bunches[i].begin();
+                               j != texture_bunches[i].end(); j++){
+                       os<<serializeString(j->name);
+                       os<<serializeLongString(j->data);
+               }
+               
+               // Make data buffer
+               std::string s = os.str();
+               infostream<<"Server::SendTextures(): bunch "<<i<<"/"<<num_bunches
+                               <<" textures="<<texture_bunches[i].size()
+                               <<" size=" <<s.size()<<std::endl;
+               SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+               // Send as reliable
+               m_con.Send(peer_id, 0, data, true);
+       }
+}
+
 /*
        Something random
 */
@@ -4088,14 +4382,19 @@ void Server::UpdateCrafting(u16 peer_id)
                }
                if(clist && rlist && player->craftresult_is_preview)
                {
-                       InventoryItem *items[9];
-                       for(u16 i=0; i<9; i++)
-                       {
-                               items[i] = clist->getItem(i);
+                       // Get result of crafting grid
+                       
+                       std::vector<InventoryItem*> items;
+                       for(u16 i=0; i<9; i++){
+                               if(clist->getItem(i) == NULL)
+                                       items.push_back(NULL);
+                               else
+                                       items.push_back(clist->getItem(i)->clone());
                        }
+                       CraftPointerInput cpi(3, items);
                        
-                       // Get result of crafting grid
-                       InventoryItem *result = craft_get_result(items);
+                       InventoryItem *result = m_craftdef->getCraftResult(cpi, this);
+                       //InventoryItem *result = craft_get_result(items, this);
                        if(result)
                                rlist->addItem(result);
                }
@@ -4170,6 +4469,42 @@ void Server::notifyPlayers(const std::wstring msg)
        BroadcastChatMessage(msg);
 }
 
+// IGameDef interface
+// Under envlock
+IToolDefManager* Server::getToolDefManager()
+{
+       return m_toolmgr;
+}
+INodeDefManager* Server::getNodeDefManager()
+{
+       return m_nodedef;
+}
+ICraftDefManager* Server::getCraftDefManager()
+{
+       return m_craftdef;
+}
+ITextureSource* Server::getTextureSource()
+{
+       return NULL;
+}
+u16 Server::allocateUnknownNodeId(const std::string &name)
+{
+       return m_nodedef->allocateDummy(name);
+}
+
+IWritableToolDefManager* Server::getWritableToolDefManager()
+{
+       return m_toolmgr;
+}
+IWritableNodeDefManager* Server::getWritableNodeDefManager()
+{
+       return m_nodedef;
+}
+IWritableCraftDefManager* Server::getWritableCraftDefManager()
+{
+       return m_craftdef;
+}
+
 v3f findSpawnPos(ServerMap &map)
 {
        //return v3f(50,50,50)*BS;
@@ -4259,7 +4594,7 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
                        player->inventory_backup = new Inventory();
                        *(player->inventory_backup) = player->inventory;
                        // Set creative inventory
-                       craft_set_creative_inventory(player);
+                       craft_set_creative_inventory(player, this);
                }
 
                return player;
@@ -4313,11 +4648,11 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
                        player->inventory_backup = new Inventory();
                        *(player->inventory_backup) = player->inventory;
                        // Set creative inventory
-                       craft_set_creative_inventory(player);
+                       craft_set_creative_inventory(player, this);
                }
                else if(g_settings->getBool("give_initial_stuff"))
                {
-                       craft_give_initial_stuff(player);
+                       craft_give_initial_stuff(player, this);
                }
 
                return player;