/* (c) 2010 Perttu Ahola */ #ifndef SERVER_HEADER #define SERVER_HEADER #include "connection.h" #include "environment.h" #include "common_irrlicht.h" #include #ifdef _WIN32 #include #define sleep_ms(x) Sleep(x) #else #include #define sleep_ms(x) usleep(x*1000) #endif struct QueuedBlockEmerge { v3s16 pos; // key = peer_id, value = flags core::map peer_ids; }; /* This is a thread-safe class. */ class BlockEmergeQueue { public: BlockEmergeQueue() { m_mutex.Init(); } ~BlockEmergeQueue() { JMutexAutoLock lock(m_mutex); core::list::Iterator i; for(i=m_queue.begin(); i!=m_queue.end(); i++) { QueuedBlockEmerge *q = *i; delete q; } } /* peer_id=0 adds with nobody to send to */ void addBlock(u16 peer_id, v3s16 pos, u8 flags) { DSTACK(__FUNCTION_NAME); JMutexAutoLock lock(m_mutex); if(peer_id != 0) { /* Find if block is already in queue. If it is, update the peer to it and quit. */ core::list::Iterator i; for(i=m_queue.begin(); i!=m_queue.end(); i++) { QueuedBlockEmerge *q = *i; if(q->pos == pos) { q->peer_ids[peer_id] = flags; return; } } } /* Add the block */ QueuedBlockEmerge *q = new QueuedBlockEmerge; q->pos = pos; if(peer_id != 0) q->peer_ids[peer_id] = flags; m_queue.push_back(q); } // Returned pointer must be deleted // Returns NULL if queue is empty QueuedBlockEmerge * pop() { JMutexAutoLock lock(m_mutex); core::list::Iterator i = m_queue.begin(); if(i == m_queue.end()) return NULL; QueuedBlockEmerge *q = *i; m_queue.erase(i); return q; } u32 size() { JMutexAutoLock lock(m_mutex); return m_queue.size(); } u32 peerItemCount(u16 peer_id) { JMutexAutoLock lock(m_mutex); u32 count = 0; core::list::Iterator i; for(i=m_queue.begin(); i!=m_queue.end(); i++) { QueuedBlockEmerge *q = *i; if(q->peer_ids.find(peer_id) != NULL) count++; } return count; } private: core::list m_queue; JMutex m_mutex; }; class SimpleThread : public JThread { bool run; JMutex run_mutex; public: SimpleThread(): JThread(), run(true) { run_mutex.Init(); } virtual ~SimpleThread() {} virtual void * Thread() = 0; bool getRun() { JMutexAutoLock lock(run_mutex); return run; } void setRun(bool a_run) { JMutexAutoLock lock(run_mutex); run = a_run; } void stop() { setRun(false); while(IsRunning()) sleep_ms(100); } }; class Server; class ServerThread : public SimpleThread { Server *m_server; public: ServerThread(Server *server): SimpleThread(), m_server(server) { } void * Thread(); }; class EmergeThread : public SimpleThread { Server *m_server; public: EmergeThread(Server *server): SimpleThread(), m_server(server) { } void * Thread(); void trigger() { setRun(true); if(IsRunning() == false) { Start(); } } }; struct PlayerInfo { u16 id; char name[PLAYERNAME_SIZE]; v3f position; Address address; float avg_rtt; PlayerInfo(); void PrintLine(std::ostream *s); }; u32 PIChecksum(core::list &l); /* Used for queueing and sorting block transfers in containers Lower priority number means higher priority. */ struct PrioritySortedBlockTransfer { PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id) { priority = a_priority; pos = a_pos; peer_id = a_peer_id; } bool operator < (PrioritySortedBlockTransfer &other) { return priority < other.priority; } float priority; v3s16 pos; u16 peer_id; }; class RemoteClient { public: // peer_id=0 means this client has no associated peer // NOTE: If client is made allowed to exist while peer doesn't, // this has to be set to 0 when there is no peer. // Also, the client must be moved to some other container. u16 peer_id; // The serialization version to use with the client u8 serialization_version; // Version is stored in here after INIT before INIT2 u8 pending_serialization_version; RemoteClient(): m_time_from_building(0.0) //m_num_blocks_in_emerge_queue(0) { peer_id = 0; serialization_version = SER_FMT_VER_INVALID; pending_serialization_version = SER_FMT_VER_INVALID; m_nearest_unsent_d = 0; m_blocks_sent_mutex.Init(); m_blocks_sending_mutex.Init(); } ~RemoteClient() { } /* Finds block that should be sent next to the client. Environment should be locked when this is called. dtime is used for resetting send radius at slow interval */ void GetNextBlocks(Server *server, float dtime, core::array &dest); // Connection and environment should be locked when this is called // steps() objects of blocks not found in active_blocks, then // adds those blocks to active_blocks void SendObjectData( Server *server, float dtime, core::map &stepped_blocks ); void GotBlock(v3s16 p); void SentBlock(v3s16 p); void SetBlockNotSent(v3s16 p); void SetBlocksNotSent(core::map &blocks); //void BlockEmerged(); /*bool IsSendingBlock(v3s16 p) { JMutexAutoLock lock(m_blocks_sending_mutex); return (m_blocks_sending.find(p) != NULL); }*/ s32 SendingCount() { JMutexAutoLock lock(m_blocks_sending_mutex); return m_blocks_sending.size(); } // Increments timeouts and removes timed-out blocks from list // NOTE: This doesn't fix the server-not-sending-block bug // because it is related to emerging, not sending. //void RunSendingTimeouts(float dtime, float timeout); void PrintInfo(std::ostream &o) { JMutexAutoLock l2(m_blocks_sent_mutex); JMutexAutoLock l3(m_blocks_sending_mutex); o<<"RemoteClient "<