+std::wstring Server::getStatusString()
+{
+ std::wostringstream os(std::ios_base::binary);
+ os<<L"# Server: ";
+ // Uptime
+ os<<L"uptime="<<m_uptime.get();
+ // Information about clients
+ os<<L", clients={";
+ 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;
+ // Get player
+ Player *player = m_env.getPlayer(client->peer_id);
+ // Get name of player
+ std::wstring name = L"unknown";
+ if(player != NULL)
+ name = narrow_to_wide(player->getName());
+ // Add name to information string
+ os<<name<<L",";
+ }
+ os<<L"}";
+ if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
+ os<<" WARNING: Map saving is disabled."<<std::endl;
+ return os.str();
+}
+
+
+void setCreativeInventory(Player *player)
+{
+ player->resetInventory();
+
+ // Give some good picks
+ {
+ InventoryItem *item = new ToolItem("STPick", 0);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new ToolItem("MesePick", 0);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+
+ /*
+ Give materials
+ */
+ assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
+
+ // add torch first
+ InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
+ player->inventory.addItem("main", item);
+
+ // Then others
+ for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
+ {
+ // Skip some materials
+ if(i == CONTENT_WATER || i == CONTENT_TORCH
+ || i == CONTENT_COALSTONE)
+ continue;
+
+ InventoryItem *item = new MaterialItem(i, 1);
+ player->inventory.addItem("main", item);
+ }
+ // Sign
+ {
+ InventoryItem *item = new MapBlockObjectItem("Sign Example text");
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+}
+
+Player *Server::emergePlayer(const char *name, const char *password,
+ u16 peer_id)
+{
+ /*
+ Try to get an existing player
+ */
+ Player *player = m_env.getPlayer(name);
+ if(player != NULL)
+ {
+ // If player is already connected, cancel
+ if(player->peer_id != 0)
+ {
+ dstream<<"emergePlayer(): Player already connected"<<std::endl;
+ return NULL;
+ }
+
+ // Got one.
+ player->peer_id = peer_id;
+
+ // Reset inventory to creative if in creative mode
+ if(g_settings.getBool("creative_mode"))
+ {
+ setCreativeInventory(player);
+ }
+
+ return player;
+ }
+
+ /*
+ If player with the wanted peer_id already exists, cancel.
+ */
+ if(m_env.getPlayer(peer_id) != NULL)
+ {
+ dstream<<"emergePlayer(): Player with wrong name but same"
+ " peer_id already exists"<<std::endl;
+ return NULL;
+ }
+
+ /*
+ Create a new player
+ */
+ {
+ player = new ServerRemotePlayer();
+ //player->peer_id = c.peer_id;
+ //player->peer_id = PEER_ID_INEXISTENT;
+ player->peer_id = peer_id;
+ player->updateName(name);
+
+ /*
+ Set player position
+ */
+
+ dstream<<"Server: Finding spawn place for player \""
+ <<player->getName()<<"\""<<std::endl;
+
+ v2s16 nodepos;
+#if 1
+ player->setPosition(intToFloat(v3s16(
+ 0,
+ 45, //64,
+ 0
+ )));
+#endif
+#if 0
+ f32 groundheight = 0;
+#if 0
+ // Try to find a good place a few times
+ for(s32 i=0; i<500; 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);
+ // 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
+ // Get block at point
+ v3s16 nodepos3d;
+ nodepos3d = v3s16(nodepos.X, groundheight+1, nodepos.Y);
+ v3s16 blockpos = getNodeBlockPos(nodepos3d);
+ ((ServerMap*)(&m_env.getMap()))->emergeBlock(blockpos);
+ // Don't go inside ground
+ try{
+ /*v3s16 footpos(nodepos.X, groundheight+1, nodepos.Y);
+ v3s16 headpos(nodepos.X, groundheight+2, nodepos.Y);*/
+ v3s16 footpos = nodepos3d + v3s16(0,0,0);
+ v3s16 headpos = nodepos3d + v3s16(0,1,0);
+ if(m_env.getMap().getNode(footpos).d != CONTENT_AIR
+ || m_env.getMap().getNode(headpos).d != CONTENT_AIR)
+ {
+ dstream<<"-> Inside ground"<<std::endl;
+ // In ground
+ continue;
+ }
+ }catch(InvalidPositionException &e)
+ {
+ dstream<<"-> Invalid position"<<std::endl;
+ // Ignore invalid position
+ continue;
+ }
+#endif
+ // Found a good place
+ dstream<<"Searched through "<<i<<" places."<<std::endl;
+ break;
+ }
+#endif
+
+ // If no suitable place was not found, go above water at least.
+ if(groundheight < WATER_LEVEL)
+ groundheight = WATER_LEVEL;
+
+ player->setPosition(intToFloat(v3s16(
+ nodepos.X,
+ //groundheight + 1,
+ groundheight + 15,
+ nodepos.Y
+ )));
+#endif
+
+ /*
+ Add player to environment
+ */
+
+ m_env.addPlayer(player);
+
+ /*
+ Add stuff to inventory
+ */
+
+ if(g_settings.getBool("creative_mode"))
+ {
+ setCreativeInventory(player);
+ }
+ else
+ {
+ /*{
+ InventoryItem *item = new ToolItem("WPick", 32000);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }*/
+ /*{
+ InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new CraftItem("Stick", 4);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new ToolItem("WPick", 32000);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new ToolItem("STPick", 32000);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }*/
+ /*// Give some lights
+ {
+ InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);
+ bool r = player->inventory.addItem("main", item);
+ assert(r == true);
+ }
+ // and some signs
+ for(u16 i=0; i<4; i++)
+ {
+ InventoryItem *item = new MapBlockObjectItem("Sign Example text");
+ bool r = player->inventory.addItem("main", item);
+ assert(r == true);
+ }*/
+ /*// Give some other stuff
+ {
+ InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
+ bool r = player->inventory.addItem("main", item);
+ assert(r == true);
+ }*/
+ }
+
+ return player;
+
+ } // create new player
+}
+
+#if 0
+void Server::UpdateBlockWaterPressure(MapBlock *block,
+ core::map<v3s16, MapBlock*> &modified_blocks)
+{
+ MapVoxelManipulator v(&m_env.getMap());
+ v.m_disable_water_climb =
+ g_settings.getBool("disable_water_climb");
+
+ VoxelArea area(block->getPosRelative(),
+ block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1));
+
+ try
+ {
+ v.updateAreaWaterPressure(area, m_flow_active_nodes);
+ }
+ catch(ProcessingLimitException &e)
+ {
+ dstream<<"Processing limit reached (1)"<<std::endl;
+ }
+
+ v.blitBack(modified_blocks);
+}
+#endif
+
+void Server::handlePeerChange(PeerChange &c)
+{
+ JMutexAutoLock envlock(m_env_mutex);
+ JMutexAutoLock conlock(m_con_mutex);
+
+ if(c.type == PEER_ADDED)
+ {
+ /*
+ Add
+ */
+
+ // Error check
+ core::map<u16, RemoteClient*>::Node *n;
+ n = m_clients.find(c.peer_id);
+ // The client shouldn't already exist
+ assert(n == NULL);
+
+ // Create client
+ RemoteClient *client = new RemoteClient();
+ client->peer_id = c.peer_id;
+ m_clients.insert(client->peer_id, client);
+
+ } // PEER_ADDED
+ else if(c.type == PEER_REMOVED)
+ {
+ /*
+ Delete
+ */
+
+ // Error check
+ core::map<u16, RemoteClient*>::Node *n;
+ n = m_clients.find(c.peer_id);
+ // The client should exist
+ assert(n != NULL);
+
+ // Collect information about leaving in chat
+ std::wstring message;
+ {
+ std::wstring name = L"unknown";
+ Player *player = m_env.getPlayer(c.peer_id);
+ if(player != NULL)
+ name = narrow_to_wide(player->getName());
+
+ message += L"*** ";
+ message += name;
+ message += L" left game";
+ if(c.timeout)
+ message += L" (timed out)";
+ }
+
+ /*// Delete player
+ {
+ m_env.removePlayer(c.peer_id);
+ }*/
+
+ // Set player client disconnected
+ {
+ Player *player = m_env.getPlayer(c.peer_id);
+ if(player != NULL)
+ player->peer_id = 0;
+ }
+
+ // Delete client
+ delete m_clients[c.peer_id];
+ m_clients.remove(c.peer_id);
+
+ // Send player info to all remaining clients
+ SendPlayerInfos();
+
+ // Send leave chat message to all remaining clients
+ BroadcastChatMessage(message);
+
+ } // PEER_REMOVED
+ else
+ {
+ assert(0);
+ }
+}
+
+void Server::handlePeerChanges()
+{
+ while(m_peer_change_queue.size() > 0)
+ {
+ PeerChange c = m_peer_change_queue.pop_front();
+
+ dout_server<<"Server: Handling peer change: "
+ <<"id="<<c.peer_id<<", timeout="<<c.timeout
+ <<std::endl;
+
+ handlePeerChange(c);
+ }
+}
+
+void dedicated_server_loop(Server &server, bool &kill)
+{
+ DSTACK(__FUNCTION_NAME);
+
+ std::cout<<DTIME<<std::endl;
+ std::cout<<"========================"<<std::endl;
+ std::cout<<"Running dedicated server"<<std::endl;
+ std::cout<<"========================"<<std::endl;
+ std::cout<<std::endl;
+
+ for(;;)
+ {
+ // This is kind of a hack but can be done like this
+ // because server.step() is very light
+ sleep_ms(30);
+ server.step(0.030);
+
+ if(server.getShutdownRequested() || kill)
+ {
+ std::cout<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
+ break;
+ }
+
+ static int counter = 0;
+ counter--;
+ if(counter <= 0)
+ {
+ counter = 10;
+
+ core::list<PlayerInfo> list = server.getPlayerInfo();
+ core::list<PlayerInfo>::Iterator i;
+ static u32 sum_old = 0;
+ u32 sum = PIChecksum(list);
+ if(sum != sum_old)
+ {
+ std::cout<<DTIME<<"Player info:"<<std::endl;
+ for(i=list.begin(); i!=list.end(); i++)
+ {
+ i->PrintLine(&std::cout);
+ }
+ }
+ sum_old = sum;
+ }
+ }
+}
+