]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/server.cpp
commit before some more radical changes
[dragonfireclient.git] / src / server.cpp
index 6f04ef33a6ec2055e6c322ba5099ea616b73c8b7..b3ce9c13aeeef720b876219bf11227d0516b75dd 100644 (file)
@@ -17,10 +17,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-/*
-(c) 2010 Perttu Ahola <celeron55@gmail.com>
-*/
-
 #include "server.h"
 #include "utility.h"
 #include <iostream>
@@ -171,6 +167,28 @@ void * EmergeThread::Thread()
                                                only_from_disk,
                                                changed_blocks,
                                                lighting_invalidated_blocks);
+
+#if 0
+                               /*
+                                       While we're at it, generate some other blocks too
+                               */
+                               try
+                               {
+                                       map.emergeBlock(
+                                                       p+v3s16(0,1,0),
+                                                       only_from_disk,
+                                                       changed_blocks,
+                                                       lighting_invalidated_blocks);
+                                       map.emergeBlock(
+                                                       p+v3s16(0,-1,0),
+                                                       only_from_disk,
+                                                       changed_blocks,
+                                                       lighting_invalidated_blocks);
+                               }
+                               catch(InvalidPositionException &e)
+                               {
+                               }
+#endif
                        }
 
                        // If it is a dummy, block was not found on disk
@@ -212,23 +230,27 @@ void * EmergeThread::Thread()
                                Collect a list of blocks that have been modified in
                                addition to the fetched one.
                        */
-
-                       // Add all the "changed blocks" to modified_blocks
+                       
+                       if(lighting_invalidated_blocks.size() > 0)
+                       {
+                               /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
+                                               <<" blocks"<<std::endl;*/
+                       
+                               // 50-100ms for single block generation
+                               //TimeTaker timer("** EmergeThread updateLighting");
+                               
+                               // Update lighting without locking the environment mutex,
+                               // add modified blocks to changed blocks
+                               map.updateLighting(lighting_invalidated_blocks, modified_blocks);
+                       }
+                               
+                       // Add all from changed_blocks to modified_blocks
                        for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
                                        i.atEnd() == false; i++)
                        {
                                MapBlock *block = i.getNode()->getValue();
                                modified_blocks.insert(block->getPos(), block);
                        }
-                       
-                       /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
-                                       <<" blocks"<<std::endl;*/
-                       
-                       //TimeTaker timer("** updateLighting");
-                       
-                       // Update lighting without locking the environment mutex,
-                       // add modified blocks to changed blocks
-                       map.updateLighting(lighting_invalidated_blocks, modified_blocks);
                }
                // If we got no block, there should be no invalidated blocks
                else
@@ -522,6 +544,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                                        block_is_invalid = true;
                                }
                                
+                               /*if(block->isFullyGenerated() == false)
+                               {
+                                       block_is_invalid = true;
+                               }*/
+                               
                                v2s16 p2d(p.X, p.Z);
                                ServerMap *map = (ServerMap*)(&server->m_env.getMap());
                                v2s16 chunkpos = map->sector_to_chunk(p2d);
@@ -555,7 +582,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        {
                                //TODO: Get value from somewhere
                                // Allow only one block in emerge queue
-                               if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
+                               //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
+                               if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
                                {
                                        //dstream<<"Adding block to emerge queue"<<std::endl;
                                        
@@ -897,7 +925,7 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
 Server::Server(
                std::string mapsavedir
        ):
-       m_env(new ServerMap(mapsavedir)),
+       m_env(new ServerMap(mapsavedir), this),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
        m_thread(this),
        m_emergethread(this),
@@ -906,9 +934,10 @@ Server::Server(
        m_time_of_day_send_timer(0),
        m_uptime(0),
        m_mapsavedir(mapsavedir),
-       m_shutdown_requested(false)
+       m_shutdown_requested(false),
+       m_ignore_map_edit_events(false),
+       m_ignore_map_edit_events_peer_id(0)
 {
-       //m_flowwater_timer = 0.0;
        m_liquid_transform_timer = 0.0;
        m_print_info_timer = 0.0;
        m_objectdata_timer = 0.0;
@@ -920,6 +949,8 @@ Server::Server(
        m_step_dtime_mutex.Init();
        m_step_dtime = 0.0;
 
+       m_env.getMap().addEventReceiver(this);
+
        // Load players
        m_env.deSerializePlayers(m_mapsavedir);
 }
@@ -999,19 +1030,25 @@ void Server::start(unsigned short port)
        m_thread.setRun(true);
        m_thread.Start();
        
-       dout_server<<"Server started on port "<<port<<std::endl;
+       dout_server<<"Server: Started on port "<<port<<std::endl;
 }
 
 void Server::stop()
 {
        DSTACK(__FUNCTION_NAME);
+
        // Stop threads (set run=false first so both start stopping)
        m_thread.setRun(false);
        m_emergethread.setRun(false);
        m_thread.stop();
        m_emergethread.stop();
        
-       dout_server<<"Server threads stopped"<<std::endl;
+       dout_server<<"Server: Threads stopped"<<std::endl;
+
+       dout_server<<"Server: Saving players"<<std::endl;
+       // Save players
+       // FIXME: Apparently this does not do anything here
+       //m_env.serializePlayers(m_mapsavedir);
 }
 
 void Server::step(float dtime)
@@ -1189,12 +1226,18 @@ void Server::AsyncRunStep()
                }
        }
 
+       if(g_settings.getBool("enable_experimental"))
+       {
+
        /*
                Check added and deleted active objects
        */
        {
                JMutexAutoLock envlock(m_env_mutex);
                JMutexAutoLock conlock(m_con_mutex);
+               
+               // Radius inside which objects are active
+               s16 radius = 32;
 
                for(core::map<u16, RemoteClient*>::Iterator
                        i = m_clients.getIterator();
@@ -1202,8 +1245,9 @@ void Server::AsyncRunStep()
                {
                        RemoteClient *client = i.getNode()->getValue();
                        Player *player = m_env.getPlayer(client->peer_id);
+                       if(player==NULL)
+                               continue;
                        v3s16 pos = floatToInt(player->getPosition(), BS);
-                       s16 radius = 32;
 
                        core::map<u16, bool> removed_objects;
                        core::map<u16, bool> added_objects;
@@ -1267,6 +1311,9 @@ void Server::AsyncRunStep()
                                writeU8((u8*)buf, type);
                                data_buffer.append(buf, 1);
 
+                               data_buffer.append(serializeLongString(
+                                               obj->getClientInitializationData()));
+
                                // Add to known objects
                                client->m_known_objects.insert(i.getNode()->getKey(), false);
 
@@ -1348,13 +1395,12 @@ void Server::AsyncRunStep()
                                        // Compose the full new data with header
                                        ActiveObjectMessage aom = *k;
                                        std::string new_data;
-                                       // Add header (object id + length)
-                                       char header[4];
-                                       writeU16((u8*)&header[0], aom.id);
-                                       writeU16((u8*)&header[2], aom.datastring.size());
-                                       new_data.append(header, 4);
+                                       // Add object id
+                                       char buf[2];
+                                       writeU16((u8*)&buf[0], aom.id);
+                                       new_data.append(buf, 2);
                                        // Add data
-                                       new_data += aom.datastring;
+                                       new_data += serializeString(aom.datastring);
                                        // Add data to buffer
                                        if(aom.reliable)
                                                reliable_data += new_data;
@@ -1384,13 +1430,14 @@ void Server::AsyncRunStep()
                                // Send as unreliable
                                m_con.Send(client->peer_id, 0, reply, false);
                        }
-                       if(reliable_data.size() > 0 || unreliable_data.size() > 0)
+
+                       /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
                        {
                                dstream<<"INFO: Server: Size of object message data: "
                                                <<"reliable: "<<reliable_data.size()
                                                <<", unreliable: "<<unreliable_data.size()
                                                <<std::endl;
-                       }
+                       }*/
                }
 
                // Clear buffered_messages
@@ -1402,8 +1449,44 @@ void Server::AsyncRunStep()
                }
        }
 
+       } // enable_experimental
+
+       /*
+               Send queued-for-sending map edit events.
+       */
+       {
+               while(m_unsent_map_edit_queue.size() != 0)
+               {
+                       MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
+
+                       if(event->type == MEET_ADDNODE)
+                       {
+                               dstream<<"Server: MEET_ADDNODE"<<std::endl;
+                               sendAddNode(event->p, event->n, event->already_known_by_peer);
+                       }
+                       else if(event->type == MEET_REMOVENODE)
+                       {
+                               dstream<<"Server: MEET_REMOVENODE"<<std::endl;
+                               sendRemoveNode(event->p, event->already_known_by_peer);
+                       }
+                       else if(event->type == MEET_OTHER)
+                       {
+                               dstream<<"WARNING: Server: MEET_OTHER not implemented"
+                                               <<std::endl;
+                       }
+                       else
+                       {
+                               dstream<<"WARNING: Server: Unknown MapEditEvent "
+                                               <<((u32)event->type)<<std::endl;
+                       }
+
+                       delete event;
+               }
+       }
+
        /*
                Send object positions
+               TODO: Get rid of MapBlockObjects
        */
        {
                float &counter = m_objectdata_timer;
@@ -1630,10 +1713,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                // Now answer with a TOCLIENT_INIT
                
-               SharedBuffer<u8> reply(2+1+6);
+               SharedBuffer<u8> reply(2+1+6+8);
                writeU16(&reply[0], TOCLIENT_INIT);
                writeU8(&reply[2], deployed);
-               writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
+               writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
+               //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
+               
                // Send as reliable
                m_con.Send(peer_id, 0, reply, true);
 
@@ -1959,32 +2044,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        /*
                                Send the removal to all other clients
                        */
-
-                       // Create packet
-                       u32 replysize = 8;
-                       SharedBuffer<u8> reply(replysize);
-                       writeU16(&reply[0], TOCLIENT_REMOVENODE);
-                       writeS16(&reply[2], p_under.X);
-                       writeS16(&reply[4], p_under.Y);
-                       writeS16(&reply[6], p_under.Z);
-
-                       for(core::map<u16, RemoteClient*>::Iterator
-                               i = m_clients.getIterator();
-                               i.atEnd() == false; i++)
-                       {
-                               // Get client and check that it is valid
-                               RemoteClient *client = i.getNode()->getValue();
-                               assert(client->peer_id == i.getNode()->getKey());
-                               if(client->serialization_version == SER_FMT_VER_INVALID)
-                                       continue;
-
-                               // Don't send if it's the same one
-                               if(peer_id == client->peer_id)
-                                       continue;
-
-                               // Send as reliable
-                               m_con.Send(client->peer_id, 0, reply, true);
-                       }
+                       sendRemoveNode(p_under, peer_id);
                        
                        /*
                                Update and send inventory
@@ -2058,33 +2118,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                Remove the node
                                (this takes some time so it is done after the quick stuff)
                        */
+                       m_ignore_map_edit_events = true;
                        m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
-
-#if 0
-                       /*
-                               Update water
-                       */
-                       
-                       // Update water pressure around modification
-                       // This also adds it to m_flow_active_nodes if appropriate
-
-                       MapVoxelManipulator v(&m_env.getMap());
-                       v.m_disable_water_climb =
-                                       g_settings.getBool("disable_water_climb");
-                       
-                       VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1));
-
-                       try
-                       {
-                               v.updateAreaWaterPressure(area, m_flow_active_nodes);
-                       }
-                       catch(ProcessingLimitException &e)
-                       {
-                               dstream<<"Processing limit reached (1)"<<std::endl;
-                       }
-                       
-                       v.blitBack(modified_blocks);
-#endif
+                       m_ignore_map_edit_events = false;
                }
                
                /*
@@ -2145,17 +2181,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                n.d = mitem->getMaterial();
                                if(content_features(n.d).wall_mounted)
                                        n.dir = packDir(p_under - p_over);
-
-                               // Create packet
-                               u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver);
-                               SharedBuffer<u8> reply(replysize);
-                               writeU16(&reply[0], TOCLIENT_ADDNODE);
-                               writeS16(&reply[2], p_over.X);
-                               writeS16(&reply[4], p_over.Y);
-                               writeS16(&reply[6], p_over.Z);
-                               n.serialize(&reply[8], peer_ser_ver);
-                               // Send as reliable
-                               m_con.SendToAll(0, reply, true);
+                               
+                               /*
+                                       Send to all players
+                               */
+                               sendAddNode(p_over, n, 0);
                                
                                /*
                                        Handle inventory
@@ -2178,7 +2208,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        This takes some time so it is done after the quick stuff
                                */
                                core::map<v3s16, MapBlock*> modified_blocks;
+                               m_ignore_map_edit_events = true;
                                m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
+                               m_ignore_map_edit_events = false;
                                
                                /*
                                        Calculate special events
@@ -2590,41 +2622,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
        }
 }
 
-/*void Server::Send(u16 peer_id, u16 channelnum,
-               SharedBuffer<u8> data, bool reliable)
-{
-       JMutexAutoLock lock(m_con_mutex);
-       m_con.Send(peer_id, channelnum, data, reliable);
-}*/
-
-void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
+void Server::onMapEditEvent(MapEditEvent *event)
 {
-       DSTACK(__FUNCTION_NAME);
-       /*
-               Create a packet with the block in the right format
-       */
-       
-       std::ostringstream os(std::ios_base::binary);
-       block->serialize(os, ver);
-       std::string s = os.str();
-       SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
-
-       u32 replysize = 8 + blockdata.getSize();
-       SharedBuffer<u8> reply(replysize);
-       v3s16 p = block->getPos();
-       writeU16(&reply[0], TOCLIENT_BLOCKDATA);
-       writeS16(&reply[2], p.X);
-       writeS16(&reply[4], p.Y);
-       writeS16(&reply[6], p.Z);
-       memcpy(&reply[8], *blockdata, blockdata.getSize());
-
-       /*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                       <<":  \tpacket size: "<<replysize<<std::endl;*/
-       
-       /*
-               Send packet
-       */
-       m_con.Send(peer_id, 1, reply, true);
+       dstream<<"Server::onMapEditEvent()"<<std::endl;
+       if(m_ignore_map_edit_events)
+               return;
+       MapEditEvent *e = event->clone();
+       m_unsent_map_edit_queue.push_back(e);
 }
 
 core::list<PlayerInfo> Server::getPlayerInfo()
@@ -2754,6 +2758,10 @@ void Server::SendPlayerInfos()
        m_con.SendToAll(0, data, true);
 }
 
+/*
+       Craft checking system
+*/
+
 enum ItemSpecType
 {
        ITEM_NONE,
@@ -3104,6 +3112,95 @@ void Server::BroadcastChatMessage(const std::wstring &message)
        }
 }
 
+void Server::sendRemoveNode(v3s16 p, u16 ignore_id)
+{
+       // Create packet
+       u32 replysize = 8;
+       SharedBuffer<u8> reply(replysize);
+       writeU16(&reply[0], TOCLIENT_REMOVENODE);
+       writeS16(&reply[2], p.X);
+       writeS16(&reply[4], p.Y);
+       writeS16(&reply[6], p.Z);
+
+       for(core::map<u16, RemoteClient*>::Iterator
+               i = m_clients.getIterator();
+               i.atEnd() == false; i++)
+       {
+               // Get client and check that it is valid
+               RemoteClient *client = i.getNode()->getValue();
+               assert(client->peer_id == i.getNode()->getKey());
+               if(client->serialization_version == SER_FMT_VER_INVALID)
+                       continue;
+
+               // Don't send if it's the same one
+               if(client->peer_id == ignore_id)
+                       continue;
+
+               // Send as reliable
+               m_con.Send(client->peer_id, 0, reply, true);
+       }
+}
+
+void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id)
+{
+       for(core::map<u16, RemoteClient*>::Iterator
+               i = m_clients.getIterator();
+               i.atEnd() == false; i++)
+       {
+               // Get client and check that it is valid
+               RemoteClient *client = i.getNode()->getValue();
+               assert(client->peer_id == i.getNode()->getKey());
+               if(client->serialization_version == SER_FMT_VER_INVALID)
+                       continue;
+
+               // Don't send if it's the same one
+               if(client->peer_id == ignore_id)
+                       continue;
+
+               // Create packet
+               u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
+               SharedBuffer<u8> reply(replysize);
+               writeU16(&reply[0], TOCLIENT_ADDNODE);
+               writeS16(&reply[2], p.X);
+               writeS16(&reply[4], p.Y);
+               writeS16(&reply[6], p.Z);
+               n.serialize(&reply[8], client->serialization_version);
+
+               // Send as reliable
+               m_con.Send(client->peer_id, 0, reply, true);
+       }
+}
+
+void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
+{
+       DSTACK(__FUNCTION_NAME);
+       /*
+               Create a packet with the block in the right format
+       */
+       
+       std::ostringstream os(std::ios_base::binary);
+       block->serialize(os, ver);
+       std::string s = os.str();
+       SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
+
+       u32 replysize = 8 + blockdata.getSize();
+       SharedBuffer<u8> reply(replysize);
+       v3s16 p = block->getPos();
+       writeU16(&reply[0], TOCLIENT_BLOCKDATA);
+       writeS16(&reply[2], p.X);
+       writeS16(&reply[4], p.Y);
+       writeS16(&reply[6], p.Z);
+       memcpy(&reply[8], *blockdata, blockdata.getSize());
+
+       /*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
+                       <<":  \tpacket size: "<<replysize<<std::endl;*/
+       
+       /*
+               Send packet
+       */
+       m_con.Send(peer_id, 1, reply, true);
+}
+
 void Server::SendBlocks(float dtime)
 {
        DSTACK(__FUNCTION_NAME);
@@ -3230,6 +3327,36 @@ void setCreativeInventory(Player *player)
        /*
                Give materials
        */
+       
+       // CONTENT_IGNORE-terminated list
+       u8 material_items[] = {
+               CONTENT_TORCH,
+               CONTENT_MUD,
+               CONTENT_STONE,
+               CONTENT_SAND,
+               CONTENT_TREE,
+               CONTENT_LEAVES,
+               CONTENT_MESE,
+               CONTENT_WATERSOURCE,
+               CONTENT_CLOUD,
+               CONTENT_FURNACE,
+               CONTENT_SIGN_WALL,
+               CONTENT_IGNORE
+       };
+       
+       u8 *mip = material_items;
+       for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
+       {
+               if(*mip == CONTENT_IGNORE)
+                       break;
+
+               InventoryItem *item = new MaterialItem(*mip, 1);
+               player->inventory.addItem("main", item);
+
+               mip++;
+       }
+
+#if 0
        assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
        
        // add torch first
@@ -3247,6 +3374,8 @@ void setCreativeInventory(Player *player)
                InventoryItem *item = new MaterialItem(i, 1);
                player->inventory.addItem("main", item);
        }
+#endif
+
        // Sign
        {
                InventoryItem *item = new MapBlockObjectItem("Sign Example text");
@@ -3311,37 +3440,43 @@ Player *Server::emergePlayer(const char *name, const char *password,
                                <<player->getName()<<"\""<<std::endl;
 
                v2s16 nodepos;
-#if 1
+#if 0
                player->setPosition(intToFloat(v3s16(
                                0,
                                45, //64,
                                0
                ), BS));
 #endif
-#if 0
-               f32 groundheight = 0;
-#if 0
+#if 1
+               s16 groundheight = 0;
+#if 1
                // Try to find a good place a few times
-               for(s32 i=0; i<500; i++)
+               for(s32 i=0; i<1000; i++)
                {
                        s32 range = 1 + i;
                        // We're going to try to throw the player to this position
                        nodepos = v2s16(-range + (myrand()%(range*2)),
                                        -range + (myrand()%(range*2)));
                        v2s16 sectorpos = getNodeSectorPos(nodepos);
-                       // Get sector
-                       m_env.getMap().emergeSector(sectorpos);
-                       // Get ground height at point
-                       groundheight = m_env.getMap().getGroundHeight(nodepos, true);
-                       // The sector should have been generated -> groundheight exists
-                       assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
+                       // Get sector (NOTE: Don't get because it's slow)
+                       //m_env.getMap().emergeSector(sectorpos);
+                       // Get ground height at point (fallbacks to heightmap function)
+                       groundheight = m_env.getServerMap().findGroundLevel(nodepos);
                        // Don't go underwater
                        if(groundheight < WATER_LEVEL)
                        {
                                //dstream<<"-> Underwater"<<std::endl;
                                continue;
                        }
-#if 0 // Doesn't work, generating blocks is a bit too complicated for doing here
+                       // Don't go to high places
+                       if(groundheight > WATER_LEVEL + 4)
+                       {
+                               //dstream<<"-> Underwater"<<std::endl;
+                               continue;
+                       }
+
+#if 0
+// Doesn't work, generating blocks is a bit too complicated for doing here
                        // Get block at point
                        v3s16 nodepos3d;
                        nodepos3d = v3s16(nodepos.X, groundheight+1, nodepos.Y);
@@ -3367,6 +3502,7 @@ Player *Server::emergePlayer(const char *name, const char *password,
                                continue;
                        }
 #endif
+
                        // Found a good place
                        dstream<<"Searched through "<<i<<" places."<<std::endl;
                        break;
@@ -3379,10 +3515,9 @@ Player *Server::emergePlayer(const char *name, const char *password,
 
                player->setPosition(intToFloat(v3s16(
                                nodepos.X,
-                               //groundheight + 1,
-                               groundheight + 15,
+                               groundheight + 5, // Accomodate mud
                                nodepos.Y
-               )));
+               ), BS));
 #endif
 
                /*