diff options
author | Perttu Ahola <celeron55@gmail.com> | 2010-11-27 01:02:21 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2010-11-27 01:02:21 +0200 |
commit | 4e249fb3fbf75f0359758760d88e22aa5b14533c (patch) | |
tree | 323087d05efbd2ace27b316d4f017cf812a31992 /src/server.h | |
download | minetest-4e249fb3fbf75f0359758760d88e22aa5b14533c.tar.gz minetest-4e249fb3fbf75f0359758760d88e22aa5b14533c.tar.bz2 minetest-4e249fb3fbf75f0359758760d88e22aa5b14533c.zip |
Initial files
Diffstat (limited to 'src/server.h')
-rw-r--r-- | src/server.h | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/src/server.h b/src/server.h new file mode 100644 index 000000000..5c856333a --- /dev/null +++ b/src/server.h @@ -0,0 +1,388 @@ +/* +(c) 2010 Perttu Ahola <celeron55@gmail.com> +*/ + +#ifndef SERVER_HEADER +#define SERVER_HEADER + +#include "connection.h" +#include "environment.h" +#include "common_irrlicht.h" +#include <string> + +#ifdef _WIN32 + #include <windows.h> + #define sleep_ms(x) Sleep(x) +#else + #include <unistd.h> + #define sleep_ms(x) usleep(x*1000) +#endif + +struct QueuedBlockEmerge +{ + v3s16 pos; + // key = peer_id, value = flags + core::map<u16, u8> peer_ids; +}; + +/* + This is a thread-safe class. +*/ +class BlockEmergeQueue +{ +public: + BlockEmergeQueue() + { + m_mutex.Init(); + } + + ~BlockEmergeQueue() + { + JMutexAutoLock lock(m_mutex); + + core::list<QueuedBlockEmerge*>::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) + { + 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<QueuedBlockEmerge*>::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<QueuedBlockEmerge*>::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(); + } + +private: + core::list<QueuedBlockEmerge*> 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<PlayerInfo> &l); + +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() + { + } + + // Connection and environment should be locked when this is called + void SendBlocks(Server *server, float dtime); + + // 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<v3s16, bool> &stepped_blocks + ); + + void GotBlock(v3s16 p); + + void SentBlock(v3s16 p); + + void SetBlockNotSent(v3s16 p); + void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks); + + void BlockEmerged(); + + // Increments timeouts and removes timed-out blocks from list + //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 "<<peer_id<<": " + <<"m_num_blocks_in_emerge_queue=" + <<m_num_blocks_in_emerge_queue.get() + <<", m_blocks_sent.size()="<<m_blocks_sent.size() + <<", m_blocks_sending.size()="<<m_blocks_sending.size() + <<", m_nearest_unsent_d="<<m_nearest_unsent_d + <<std::endl; + } + + // Time from last placing or removing blocks + MutexedVariable<float> m_time_from_building; + +private: + /* + All members that are accessed by many threads should + obviously be behind a mutex. The threads include: + - main thread (calls step()) + - server thread (calls AsyncRunStep() and Receive()) + - emerge thread + */ + + //TODO: core::map<v3s16, MapBlock*> m_active_blocks + + // Number of blocks in the emerge queue that have this client as + // a receiver. Used for throttling network usage. + MutexedVariable<s16> m_num_blocks_in_emerge_queue; + + /* + Blocks that have been sent to client. + - These don't have to be sent again. + - A block is cleared from here when client says it has + deleted it from it's memory + + Key is position, value is dummy. + No MapBlock* is stored here because the blocks can get deleted. + */ + core::map<v3s16, bool> m_blocks_sent; + s16 m_nearest_unsent_d; + v3s16 m_last_center; + JMutex m_blocks_sent_mutex; + /* + Blocks that are currently on the line. + This is used for throttling the sending of blocks. + - The size of this list is limited to some value + Block is added when it is sent with BLOCKDATA. + Block is removed when GOTBLOCKS is received. + Value is time from sending. (not used at the moment) + */ + core::map<v3s16, float> m_blocks_sending; + JMutex m_blocks_sending_mutex; +}; + +class Server : public con::PeerHandler +{ +public: + /* + NOTE: Every public method should be thread-safe + */ + Server( + std::string mapsavedir, + bool creative_mode, + MapgenParams mapgen_params + ); + ~Server(); + void start(unsigned short port); + void stop(); + void step(float dtime); + void AsyncRunStep(); + void Receive(); + void ProcessData(u8 *data, u32 datasize, u16 peer_id); + + /*void Send(u16 peer_id, u16 channelnum, + SharedBuffer<u8> data, bool reliable);*/ + + // Environment and Connection must be locked when called + void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver); + //void SendBlock(u16 peer_id, MapBlock *block, u8 ver); + //TODO: Sending of many blocks in a single packet + + // Environment and Connection must be locked when called + //void SendSectorMeta(u16 peer_id, core::list<v2s16> ps, u8 ver); + + core::list<PlayerInfo> getPlayerInfo(); + +private: + + // Virtual methods from con::PeerHandler. + // As of now, these create and remove clients and players. + // TODO: Make it possible to leave players on server. + void peerAdded(con::Peer *peer); + void deletingPeer(con::Peer *peer, bool timeout); + + // Envlock and conlock should be locked when calling these + void SendObjectData(float dtime); + void SendPlayerInfos(); + void SendInventory(u16 peer_id); + // Sends blocks to clients + void SendBlocks(float dtime); + + // When called, connection mutex should be locked + RemoteClient* getClient(u16 peer_id); + + // NOTE: If connection and environment are both to be locked, + // environment shall be locked first. + + JMutex m_env_mutex; + Environment m_env; + + JMutex m_con_mutex; + con::Connection m_con; + core::map<u16, RemoteClient*> m_clients; // Behind the con mutex + + float m_step_dtime; + JMutex m_step_dtime_mutex; + + ServerThread m_thread; + EmergeThread m_emergethread; + + BlockEmergeQueue m_emerge_queue; + + bool m_creative_mode; + + friend class EmergeThread; + friend class RemoteClient; +}; + +#endif + |