From 4e249fb3fbf75f0359758760d88e22aa5b14533c Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 27 Nov 2010 01:02:21 +0200 Subject: Initial files --- src/server.cpp | 2115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2115 insertions(+) create mode 100644 src/server.cpp (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp new file mode 100644 index 000000000..a5f55ab5d --- /dev/null +++ b/src/server.cpp @@ -0,0 +1,2115 @@ +/* +(c) 2010 Perttu Ahola +*/ + +#include "server.h" +#include "utility.h" +#include +#include "clientserver.h" +#include "map.h" +#include "jmutexautolock.h" +#include "main.h" +#include "constants.h" + +void * ServerThread::Thread() +{ + ThreadStarted(); + + DSTACK(__FUNCTION_NAME); + + while(getRun()) + { + try{ + m_server->AsyncRunStep(); + + //dout_server<<"Running m_server->Receive()"<Receive(); + } + catch(con::NoIncomingDataException &e) + { + } +#if CATCH_UNHANDLED_EXCEPTIONS + /* + This is what has to be done in threads to get suitable debug info + */ + catch(std::exception &e) + { + dstream<m_emerge_queue.pop(); + if(qptr == NULL) + break; + + SharedPtr q(qptr); + + v3s16 &p = q->pos; + + //derr_server<<"EmergeThread::Thread(): running"<::Iterator i; + for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++) + { + //u16 peer_id = i.getNode()->getKey(); + + // Check flags + u8 flags = i.getNode()->getValue(); + if((flags & TOSERVER_GETBLOCK_FLAG_OPTIONAL) == false) + optional = false; + + } + } + + /*dstream<<"EmergeThread: p=" + <<"("<isDummy()) + { + //dstream<<"EmergeThread: Got a dummy block"< 0) + { + dout_server<::Iterator i = changed_blocks.getIterator(); + i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + v3s16 p = block->getPos(); + dout_server<<"("<::Iterator i = changed_blocks.getIterator(); + i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + modified_blocks.insert(block->getPos(), block); + } + + //TimeTaker timer("** updateLighting", g_device); + // 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 + { + assert(lighting_invalidated_blocks.size() == 0); + } + + }//envlock + + /* + Set sent status of modified blocks on clients + */ + + // NOTE: Server's clients are also behind the connection mutex + JMutexAutoLock lock(m_server->m_con_mutex); + + /* + Add the originally fetched block to the modified list + */ + if(got_block) + { + modified_blocks.insert(p, block); + } + + /* + Set the modified blocks unsent for all the clients + */ + + for(core::map::Iterator + i = m_server->m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + + if(modified_blocks.size() > 0) + { + // Remove block from sent history + client->SetBlocksNotSent(modified_blocks); + } + + if(q->peer_ids.find(client->peer_id) != NULL) + { + // Decrement emerge queue count of client + client->BlockEmerged(); + } + } + + } +#if CATCH_UNHANDLED_EXCEPTIONS + }//try + /* + This is what has to be done in threads to get suitable debug info + */ + catch(std::exception &e) + { + dstream<= MAX_SIMULTANEOUS_BLOCK_SENDS) + { + //dstream<<"Not sending any blocks, Queue full."<m_env.getPlayer(peer_id); + + v3f playerpos = player->getPosition(); + v3f playerspeed = player->getSpeed(); + + v3s16 center_nodepos = floatToInt(playerpos); + + v3s16 center = getNodeBlockPos(center_nodepos); + + /* + Find out what block the player is going to next and set + center to it. + + Don't react to speeds under the initial value of highest_speed + */ + /*f32 highest_speed = 0.1 * BS; + v3s16 dir(0,0,0); + if(abs(playerspeed.X) > highest_speed) + { + highest_speed = playerspeed.X; + if(playerspeed.X > 0) + dir = v3s16(1,0,0); + else + dir = v3s16(-1,0,0); + } + if(abs(playerspeed.Y) > highest_speed) + { + highest_speed = playerspeed.Y; + if(playerspeed.Y > 0) + dir = v3s16(0,1,0); + else + dir = v3s16(0,-1,0); + } + if(abs(playerspeed.Z) > highest_speed) + { + highest_speed = playerspeed.Z; + if(playerspeed.Z > 0) + dir = v3s16(0,0,1); + else + dir = v3s16(0,0,-1); + } + + center += dir;*/ + + /* + Calculate the starting value of the block finder radius. + + The radius shall be the last used value minus the + maximum moved distance. + */ + /*s16 d_start = m_last_block_find_d; + if(max_moved >= d_start) + { + d_start = 0; + } + else + { + d_start -= max_moved; + }*/ + + s16 last_nearest_unsent_d; + s16 d_start; + { + JMutexAutoLock lock(m_blocks_sent_mutex); + + if(m_last_center != center) + { + m_nearest_unsent_d = 0; + m_last_center = center; + } + + static float reset_counter = 0; + reset_counter += dtime; + if(reset_counter > 5.0) + { + reset_counter = 0; + m_nearest_unsent_d = 0; + } + + last_nearest_unsent_d = m_nearest_unsent_d; + + d_start = m_nearest_unsent_d; + } + + u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS; + + { + SharedPtr lock(m_time_from_building.getLock()); + m_time_from_building.m_value += dtime; + /* + Check the time from last addNode/removeNode. + Decrease send rate if player is building stuff. + */ + if(m_time_from_building.m_value + < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING) + { + maximum_simultaneous_block_sends + = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS; + } + } + + // Serialization version used + //u8 ser_version = serialization_version; + + //bool has_incomplete_blocks = false; + + /* + TODO: Get this from somewhere + TODO: Values more than 7 make placing and removing blocks very + sluggish when the map is being generated. This is + because d is looped every time from 0 to d_max if no + blocks are found for sending. + */ + //s16 d_max = 7; + s16 d_max = 8; + + //TODO: Get this from somewhere (probably a bigger value) + s16 d_max_gen = 5; + + //dstream<<"Starting from "< list; + getFacePositions(list, d); + + core::list::Iterator li; + for(li=list.begin(); li!=list.end(); li++) + { + v3s16 p = *li + center; + + /* + Send throttling + - Don't allow too many simultaneous transfers + + Also, don't send blocks that are already flying. + */ + { + JMutexAutoLock lock(m_blocks_sending_mutex); + + if(m_blocks_sending.size() + >= maximum_simultaneous_block_sends) + { + /*dstream<<"Not sending more blocks. Queue full. " + < MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + continue; + + bool generate = d <= d_max_gen; + + // Limit the generating area vertically to half + if(abs(p.Y - center.Y) > d_max_gen / 2) + generate = false; + + /* + Don't send already sent blocks + */ + { + JMutexAutoLock lock(m_blocks_sent_mutex); + + if(m_blocks_sent.find(p) != NULL) + continue; + } + + /* + Check if map has this block + */ + MapBlock *block = NULL; + try + { + block = server->m_env.getMap().getBlockNoCreate(p); + } + catch(InvalidPositionException &e) + { + } + + bool surely_not_found_on_disk = false; + if(block != NULL) + { + /*if(block->isIncomplete()) + { + has_incomplete_blocks = true; + continue; + }*/ + + if(block->isDummy()) + { + surely_not_found_on_disk = true; + } + } + + /* + If block has been marked to not exist on disk (dummy) + and generating new ones is not wanted, skip block. TODO + */ + if(generate == false && surely_not_found_on_disk == true) + { + // get next one. + continue; + } + + /* + Add inexistent block to emerge queue. + */ + if(block == NULL || surely_not_found_on_disk) + { + // Block not found. + SharedPtr lock + (m_num_blocks_in_emerge_queue.getLock()); + + //TODO: Get value from somewhere + //TODO: Balance between clients + //if(server->m_emerge_queue.size() < 1) + + // Allow only one block in emerge queue + if(m_num_blocks_in_emerge_queue.m_value == 0) + { + // Add it to the emerge queue and trigger the thread + + u8 flags = 0; + if(generate == false) + flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL; + + { + m_num_blocks_in_emerge_queue.m_value++; + } + + server->m_emerge_queue.addBlock(peer_id, p, flags); + server->m_emergethread.trigger(); + } + + // get next one. + continue; + } + + /* + Send block + */ + + /*dstream<<"RemoteClient::SendBlocks(): d="<SendBlockNoLock(peer_id, block, serialization_version); + + /* + Add to history + */ + SentBlock(p); + } + } + + // Don't add anything here. The loop breaks by returning. +} + +void RemoteClient::SendObjectData( + Server *server, + float dtime, + core::map &stepped_blocks + ) +{ + DSTACK(__FUNCTION_NAME); + + // Can't send anything without knowing version + if(serialization_version == SER_FMT_VER_INVALID) + { + dstream<<"RemoteClient::SendObjectData(): Not sending, no version." + < players = server->m_env.getPlayers(); + + // Write player count + u16 playercount = players.size(); + writeU16(buf, playercount); + os.write((char*)buf, 2); + + core::list::Iterator i; + for(i = players.begin(); + i != players.end(); i++) + { + Player *player = *i; + + v3f pf = player->getPosition(); + v3f sf = player->getSpeed(); + + v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100); + v3s32 speed_i (sf.X*100, sf.Y*100, sf.Z*100); + s32 pitch_i (player->getPitch() * 100); + s32 yaw_i (player->getYaw() * 100); + + writeU16(buf, player->peer_id); + os.write((char*)buf, 2); + writeV3S32(buf, position_i); + os.write((char*)buf, 12); + writeV3S32(buf, speed_i); + os.write((char*)buf, 12); + writeS32(buf, pitch_i); + os.write((char*)buf, 4); + writeS32(buf, yaw_i); + os.write((char*)buf, 4); + } + + /* + Get and write object data + */ + + /* + Get nearby blocks. + + For making players to be able to build to their nearby + environment (building is not possible on blocks that are not + in memory): + - Set blocks changed + - Add blocks to emerge queue if they are not found + */ + + Player *player = server->m_env.getPlayer(peer_id); + + v3f playerpos = player->getPosition(); + v3f playerspeed = player->getSpeed(); + + v3s16 center_nodepos = floatToInt(playerpos); + v3s16 center = getNodeBlockPos(center_nodepos); + + s16 d_max = ACTIVE_OBJECT_D_BLOCKS; + + core::map blocks; + + for(s16 d = 0; d <= d_max; d++) + { + core::list list; + getFacePositions(list, d); + + core::list::Iterator li; + for(li=list.begin(); li!=list.end(); li++) + { + v3s16 p = *li + center; + + /* + Ignore blocks that haven't been sent to the client + */ + { + JMutexAutoLock sentlock(m_blocks_sent_mutex); + if(m_blocks_sent.find(p) == NULL) + continue; + } + + try + { + + // Get block + MapBlock *block = server->m_env.getMap().getBlockNoCreate(p); + + // Step block if not in stepped_blocks and add to stepped_blocks + if(stepped_blocks.find(p) == NULL) + { + block->stepObjects(dtime, true); + stepped_blocks.insert(p, true); + block->setChangedFlag(); + } + + // Add block to queue + blocks.insert(p, block); + + } //try + catch(InvalidPositionException &e) + { + // Not in memory + // Add it to the emerge queue and trigger the thread. + // Fetch the block only if it is on disk. + + // Grab and increment counter + SharedPtr lock + (m_num_blocks_in_emerge_queue.getLock()); + m_num_blocks_in_emerge_queue.m_value++; + + // Add to queue as an anonymous fetch from disk + u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL; + server->m_emerge_queue.addBlock(0, p, flags); + server->m_emergethread.trigger(); + } + } + } + + /* + Write objects + */ + + u16 blockcount = blocks.size(); + + // Write block count + writeU16(buf, blockcount); + os.write((char*)buf, 2); + + for(core::map::Iterator + i = blocks.getIterator(); + i.atEnd() == false; i++) + { + v3s16 p = i.getNode()->getKey(); + // Write blockpos + writeV3S16(buf, p); + os.write((char*)buf, 6); + // Write objects + MapBlock *block = i.getNode()->getValue(); + block->serializeObjects(os, serialization_version); + } + + /* + Send data + */ + + // Make data buffer + std::string s = os.str(); + SharedBuffer data((u8*)s.c_str(), s.size()); + // Send as unreliable + server->m_con.Send(peer_id, 0, data, false); +} + +void RemoteClient::GotBlock(v3s16 p) +{ + JMutexAutoLock lock(m_blocks_sending_mutex); + JMutexAutoLock lock2(m_blocks_sent_mutex); + if(m_blocks_sending.find(p) != NULL) + m_blocks_sending.remove(p); + else + dstream<<"RemoteClient::GotBlock(): Didn't find in" + " m_blocks_sending"< 15) + { + dstream<<"RemoteClient::SentBlock(): " + <<"m_blocks_sending.size()=" + < &blocks) +{ + JMutexAutoLock sendinglock(m_blocks_sending_mutex); + JMutexAutoLock sentlock(m_blocks_sent_mutex); + + m_nearest_unsent_d = 0; + + for(core::map::Iterator + i = blocks.getIterator(); + i.atEnd()==false; i++) + { + v3s16 p = i.getNode()->getKey(); + + if(m_blocks_sending.find(p) != NULL) + m_blocks_sending.remove(p); + if(m_blocks_sent.find(p) != NULL) + m_blocks_sent.remove(p); + } +} + +void RemoteClient::BlockEmerged() +{ + SharedPtr lock(m_num_blocks_in_emerge_queue.getLock()); + assert(m_num_blocks_in_emerge_queue.m_value > 0); + m_num_blocks_in_emerge_queue.m_value--; +} + +/*void RemoteClient::RunSendingTimeouts(float dtime, float timeout) +{ + JMutexAutoLock sendinglock(m_blocks_sending_mutex); + + core::list remove_queue; + for(core::map::Iterator + i = m_blocks_sending.getIterator(); + i.atEnd()==false; i++) + { + v3s16 p = i.getNode()->getKey(); + float t = i.getNode()->getValue(); + t += dtime; + i.getNode()->setValue(t); + + if(t > timeout) + { + remove_queue.push_back(p); + } + } + for(core::list::Iterator + i = remove_queue.begin(); + i != remove_queue.end(); i++) + { + m_blocks_sending.remove(*i); + } +}*/ + +/* + PlayerInfo +*/ + +PlayerInfo::PlayerInfo() +{ + name[0] = 0; +} + +void PlayerInfo::PrintLine(std::ostream *s) +{ + (*s)< 2.0) + dtime = 2.0; + { + JMutexAutoLock lock(m_step_dtime_mutex); + m_step_dtime += dtime; + } +} + +void Server::AsyncRunStep() +{ + DSTACK(__FUNCTION_NAME); + float dtime; + { + JMutexAutoLock lock1(m_step_dtime_mutex); + dtime = m_step_dtime; + if(dtime < 0.001) + return; + m_step_dtime = 0.0; + } + + //dstream<<"Server steps "<serialization_version; + u8 peer_ser_ver = getClient(peer->id)->serialization_version; + + try + { + + if(datasize < 2) + return; + + ToServerCommand command = (ToServerCommand)readU16(&data[0]); + + if(command == TOSERVER_INIT) + { + // [0] u16 TOSERVER_INIT + // [2] u8 SER_FMT_VER_HIGHEST + // [3] u8[20] player_name + + if(datasize < 3) + return; + + derr_server<id<serialization_version = deployed; + getClient(peer->id)->pending_serialization_version = deployed; + + if(deployed == SER_FMT_VER_INVALID) + { + derr_server<= 20+3) + { + data[20+3-1] = 0; + player->updateName((const char*)&data[3]); + } + + // Now answer with a TOCLIENT_INIT + + SharedBuffer reply(2+1+6); + writeU16(&reply[0], TOCLIENT_INIT); + writeU8(&reply[2], deployed); + writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0))); + // Send as reliable + m_con.Send(peer_id, 0, reply, true); + + return; + } + if(command == TOSERVER_INIT2) + { + derr_server<id<id)->serialization_version + = getClient(peer->id)->pending_serialization_version; + + /* + Send some initialization data + */ + + // Send player info to all players + SendPlayerInfos(); + + // Send inventory to player + SendInventory(peer->id); + + return; + } + + if(peer_ser_ver == SER_FMT_VER_INVALID) + { + derr_server<GotBlock(p); + } + } + else if(command == TOSERVER_DELETEDBLOCKS) + { + if(datasize < 2+1) + return; + + /* + [0] u16 command + [2] u8 count + [3] v3s16 pos_0 + [3+6] v3s16 pos_1 + ... + */ + + u16 count = data[2]; + for(u16 i=0; iSetBlockNotSent(p); + } + } + else if(command == TOSERVER_CLICK_OBJECT) + { + if(datasize < 13) + return; + + /* + [0] u16 command + [2] u8 button (0=left, 1=right) + [3] v3s16 block + [9] s16 id + [11] u16 item + */ + u8 button = readU8(&data[2]); + v3s16 p; + p.X = readS16(&data[3]); + p.Y = readS16(&data[5]); + p.Z = readS16(&data[7]); + s16 id = readS16(&data[9]); + //u16 item_i = readU16(&data[11]); + + MapBlock *block = NULL; + try + { + block = m_env.getMap().getBlockNoCreate(p); + } + catch(InvalidPositionException &e) + { + derr_server<<"PICK_OBJECT block not found"<getObject(id); + + if(obj == NULL) + { + derr_server<<"PICK_OBJECT object not found"<inventory.getUsedSlots() == player->inventory.getSize()) + { + dout_server<<"Player inventory has no free space"<getInventoryString()); + player->inventory.addItem(item); + SendInventory(player->peer_id); + } + + // Remove from block + block->removeObject(id); + } + } + else if(command == TOSERVER_CLICK_GROUND) + { + if(datasize < 17) + return; + /* + length: 17 + [0] u16 command + [2] u8 button (0=left, 1=right) + [3] v3s16 nodepos_undersurface + [9] v3s16 nodepos_abovesurface + [15] u16 item + */ + u8 button = readU8(&data[2]); + v3s16 p_under; + p_under.X = readS16(&data[3]); + p_under.Y = readS16(&data[5]); + p_under.Z = readS16(&data[7]); + v3s16 p_over; + p_over.X = readS16(&data[9]); + p_over.Y = readS16(&data[11]); + p_over.Z = readS16(&data[13]); + u16 item_i = readU16(&data[15]); + + //TODO: Check that target is reasonably close + + /* + Left button digs ground + */ + if(button == 0) + { + + core::map modified_blocks; + + u8 material; + + try + { + // Get material at position + material = m_env.getMap().getNode(p_under).d; + // If it's air, do nothing + if(material == MATERIAL_AIR) + { + return; + } + // Otherwise remove it + m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + } + catch(InvalidPositionException &e) + { + derr_server<<"Server: Ignoring REMOVENODE: Node not found" + <id)->m_time_from_building.set(0.0); + + // Create packet + u32 replysize = 8; + SharedBuffer 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); + // Send as reliable + m_con.SendToAll(0, reply, true); + + if(m_creative_mode == false) + { + // Add to inventory and send inventory + InventoryItem *item = new MaterialItem(material, 1); + player->inventory.addItem(item); + SendInventory(player->peer_id); + } + + } // button == 0 + /* + Right button places blocks and stuff + */ + else if(button == 1) + { + + // Get item + InventoryItem *item = player->inventory.getItem(item_i); + + // If there is no item, it is not possible to add it anywhere + if(item == NULL) + return; + + /* + Handle material items + */ + if(std::string("MaterialItem") == item->getName()) + { + MaterialItem *mitem = (MaterialItem*)item; + + MapNode n; + n.d = mitem->getMaterial(); + + try{ + // Don't add a node if there isn't air + MapNode n2 = m_env.getMap().getNode(p_over); + if(n2.d != MATERIAL_AIR) + return; + + core::map modified_blocks; + m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); + } + catch(InvalidPositionException &e) + { + derr_server<<"Server: Ignoring ADDNODE: Node not found" + <id)->m_time_from_building.set(0.0); + + if(m_creative_mode == false) + { + // Remove from inventory and send inventory + if(mitem->getCount() == 1) + player->inventory.deleteItem(item_i); + else + mitem->remove(1); + // Send inventory + SendInventory(peer_id); + } + + // Create packet + u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver); + SharedBuffer 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); + } + /* + Handle block object items + */ + else if(std::string("MBOItem") == item->getName()) + { + MapBlockObjectItem *oitem = (MapBlockObjectItem*)item; + + /*dout_server<<"Trying to place a MapBlockObjectItem: " + "inventorystring=\"" + <getInventoryString() + <<"\""<getPosRelative(); + v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map); + + v3f pos = intToFloat(p_over); + pos -= block_pos_f_on_map; + + /*dout_server<<"pos=" + <<"("<createObject + (pos, player->getYaw(), player->getPitch()); + + if(obj == NULL) + derr_server<<"WARNING: oitem created NULL object" + <addObject(obj); + + //dout_server<<"Placed object"<inventory.deleteItem(item_i); + // Send inventory + SendInventory(peer_id); + } + } + + } // button == 1 + /* + Catch invalid buttons + */ + else + { + derr_server<<"WARNING: Server: Invalid button " + <getObject(id); + if(obj == NULL) + { + derr_server<<"Error while setting sign text: " + "object not found"<getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN) + { + derr_server<<"Error while setting sign text: " + "object is not a sign"<setText(text); + + obj->getBlock()->setChangedFlag(); + } + else + { + derr_server<<"WARNING: Server::ProcessData(): Ignoring " + "unknown command "<::Iterator i = ps.begin(); + core::list sendlist; + for(;;) + { + if(sendlist.size() == 255 || i == ps.end()) + { + if(sendlist.size() == 0) + break; + /* + [0] u16 command + [2] u8 sector count + [3...] v2s16 pos + sector metadata + */ + std::ostringstream os(std::ios_base::binary); + u8 buf[4]; + + writeU16(buf, TOCLIENT_SECTORMETA); + os.write((char*)buf, 2); + + writeU8(buf, sendlist.size()); + os.write((char*)buf, 1); + + for(core::list::Iterator + j = sendlist.begin(); + j != sendlist.end(); j++) + { + // Write position + writeV2S16(buf, *j); + os.write((char*)buf, 4); + + /* + Write ClientMapSector metadata + */ + + /* + [0] u8 serialization version + [1] s16 corners[0] + [3] s16 corners[1] + [5] s16 corners[2] + [7] s16 corners[3] + size = 9 + + In which corners are in these positions + v2s16(0,0), + v2s16(1,0), + v2s16(1,1), + v2s16(0,1), + */ + + // Write version + writeU8(buf, ver); + os.write((char*)buf, 1); + + // Write corners + // TODO: Get real values + s16 corners[4]; + ((ServerMap&)m_env.getMap()).getSectorCorners(*j, corners); + + writeS16(buf, corners[0]); + os.write((char*)buf, 2); + writeS16(buf, corners[1]); + os.write((char*)buf, 2); + writeS16(buf, corners[2]); + os.write((char*)buf, 2); + writeS16(buf, corners[3]); + os.write((char*)buf, 2); + } + + SharedBuffer data((u8*)os.str().c_str(), os.str().size()); + + /*dstream<<"Server::SendSectorMeta(): sending packet" + " with "< Server::getPlayerInfo() +{ + DSTACK(__FUNCTION_NAME); + JMutexAutoLock envlock(m_env_mutex); + JMutexAutoLock conlock(m_con_mutex); + + core::list list; + + core::list players = m_env.getPlayers(); + + core::list::Iterator i; + for(i = players.begin(); + i != players.end(); i++) + { + PlayerInfo info; + + Player *player = *i; + try{ + con::Peer *peer = m_con.GetPeer(player->peer_id); + info.id = peer->id; + info.address = peer->address; + info.avg_rtt = peer->avg_rtt; + } + catch(con::PeerNotFoundException &e) + { + // Outdated peer info + info.id = 0; + info.address = Address(0,0,0,0,0); + info.avg_rtt = 0.0; + } + + snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName()); + info.position = player->getPosition(); + + list.push_back(info); + } + + return list; +} + +void Server::peerAdded(con::Peer *peer) +{ + DSTACK(__FUNCTION_NAME); + dout_server<<"Server::peerAdded(): peer->id=" + <id<::Node *n; + n = m_clients.find(peer->id); + // The client shouldn't already exist + assert(n == NULL); + + // Create client + RemoteClient *client = new RemoteClient(); + client->peer_id = peer->id; + m_clients.insert(client->peer_id, client); + + // Create player + { + // Already locked when called + //JMutexAutoLock envlock(m_env_mutex); + + Player *player = m_env.getPlayer(peer->id); + + // The player shouldn't already exist + assert(player == NULL); + + player = new RemotePlayer(); + player->peer_id = peer->id; + + /* + Set player position + */ + + // Get zero sector (it could have been unloaded to disk) + m_env.getMap().emergeSector(v2s16(0,0)); + // Get ground height at origin + f32 groundheight = m_env.getMap().getGroundHeight(v2s16(0,0), true); + // The zero sector should have been generated + assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE); + // Don't go underwater + if(groundheight < WATER_LEVEL) + groundheight = WATER_LEVEL; + + player->setPosition(intToFloat(v3s16( + 0, + groundheight + 1, + 0 + ))); + + /* + Add player to environment + */ + + m_env.addPlayer(player); + + /* + Add stuff to inventory + */ + + if(m_creative_mode) + { + // Give all materials + assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE); + for(u16 i=0; iinventory.addItem(item); + } + // Sign + { + InventoryItem *item = new MapBlockObjectItem("Sign Example text"); + bool r = player->inventory.addItem(item); + assert(r == true); + } + // Rat + { + InventoryItem *item = new MapBlockObjectItem("Rat"); + bool r = player->inventory.addItem(item); + assert(r == true); + } + } + else + { + // Give some lights + { + InventoryItem *item = new MaterialItem(3, 999); + bool r = player->inventory.addItem(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(item); + assert(r == true); + } + /*// and some rats + for(u16 i=0; i<4; i++) + { + InventoryItem *item = new MapBlockObjectItem("Rat"); + bool r = player->inventory.addItem(item); + assert(r == true); + }*/ + } + } +} + +void Server::deletingPeer(con::Peer *peer, bool timeout) +{ + DSTACK(__FUNCTION_NAME); + dout_server<<"Server::deletingPeer(): peer->id=" + <id<<", timeout="<::Node *n; + n = m_clients.find(peer->id); + // The client should exist + assert(n != NULL); + + // Delete player + { + // Already locked when called + //JMutexAutoLock envlock(m_env_mutex); + m_env.removePlayer(peer->id); + } + + // Delete client + delete m_clients[peer->id]; + m_clients.remove(peer->id); + + // Send player info to all clients + SendPlayerInfos(); +} + +void Server::SendObjectData(float dtime) +{ + DSTACK(__FUNCTION_NAME); + + core::map stepped_blocks; + + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + u16 peer_id = i.getNode()->getKey(); + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == peer_id); + + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + + client->SendObjectData(this, dtime, stepped_blocks); + } +} + +void Server::SendPlayerInfos() +{ + DSTACK(__FUNCTION_NAME); + + //JMutexAutoLock envlock(m_env_mutex); + + core::list players = m_env.getPlayers(); + + u32 player_count = players.getSize(); + u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count; + + SharedBuffer data(datasize); + writeU16(&data[0], TOCLIENT_PLAYERINFO); + + u32 start = 2; + core::list::Iterator i; + for(i = players.begin(); + i != players.end(); i++) + { + Player *player = *i; + + /*dstream<<"Server sending player info for player with " + "peer_id="<peer_id<peer_id); + snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName()); + start += 2+PLAYERNAME_SIZE; + } + + //JMutexAutoLock conlock(m_con_mutex); + + // Send as reliable + m_con.SendToAll(0, data, true); +} + +void Server::SendInventory(u16 peer_id) +{ + DSTACK(__FUNCTION_NAME); + + //JMutexAutoLock envlock(m_env_mutex); + + Player* player = m_env.getPlayer(peer_id); + + std::ostringstream os; + //os.imbue(std::locale("C")); + + player->inventory.serialize(os); + + std::string s = os.str(); + + SharedBuffer data(s.size()+2); + writeU16(&data[0], TOCLIENT_INVENTORY); + memcpy(&data[2], s.c_str(), s.size()); + + //JMutexAutoLock conlock(m_con_mutex); + + // Send as reliable + m_con.Send(peer_id, 0, data, true); +} + +void Server::SendBlocks(float dtime) +{ + DSTACK(__FUNCTION_NAME); + //dstream<<"Server::SendBlocks(): BEGIN"<::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + + //dstream<<"Server::SendBlocks(): sending blocks for client "<peer_id<peer_id; + client->SendBlocks(this, dtime); + } + + //dstream<<"Server::SendBlocks(): END"<::Node *n; + n = m_clients.find(peer_id); + // A client should exist for all peers + assert(n != NULL); + return n->getValue(); +} + + -- cgit v1.2.3