before daynight mesh cache
[oweals/minetest.git] / src / client.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef CLIENT_HEADER
21 #define CLIENT_HEADER
22
23 #include "connection.h"
24 #include "environment.h"
25 #include "common_irrlicht.h"
26 #include "jmutex.h"
27 #include <ostream>
28
29 class ClientNotReadyException : public BaseException
30 {
31 public:
32         ClientNotReadyException(const char *s):
33                 BaseException(s)
34         {}
35 };
36
37 class Client;
38
39 class ClientUpdateThread : public JThread
40 {
41         bool run;
42         JMutex run_mutex;
43
44         Client *m_client;
45
46 public:
47
48         ClientUpdateThread(Client *client) : JThread(), run(true), m_client(client)
49         {
50                 run_mutex.Init();
51         }
52
53         void * Thread();
54
55         bool getRun()
56         {
57                 run_mutex.Lock();
58                 bool run_cached = run;
59                 run_mutex.Unlock();
60                 return run_cached;
61         }
62         void setRun(bool a_run)
63         {
64                 run_mutex.Lock();
65                 run = a_run;
66                 run_mutex.Unlock();
67         }
68 };
69
70 struct IncomingPacket
71 {
72         IncomingPacket()
73         {
74                 m_data = NULL;
75                 m_datalen = 0;
76                 m_refcount = NULL;
77         }
78         IncomingPacket(const IncomingPacket &a)
79         {
80                 m_data = a.m_data;
81                 m_datalen = a.m_datalen;
82                 m_refcount = a.m_refcount;
83                 if(m_refcount != NULL)
84                         (*m_refcount)++;
85         }
86         IncomingPacket(u8 *data, u32 datalen)
87         {
88                 m_data = new u8[datalen];
89                 memcpy(m_data, data, datalen);
90                 m_datalen = datalen;
91                 m_refcount = new s32(1);
92         }
93         ~IncomingPacket()
94         {
95                 if(m_refcount != NULL){
96                         assert(*m_refcount > 0);
97                         (*m_refcount)--;
98                         if(*m_refcount == 0){
99                                 if(m_data != NULL)
100                                         delete[] m_data;
101                         }
102                 }
103         }
104         /*IncomingPacket & operator=(IncomingPacket a)
105         {
106                 m_data = a.m_data;
107                 m_datalen = a.m_datalen;
108                 m_refcount = a.m_refcount;
109                 (*m_refcount)++;
110                 return *this;
111         }*/
112         u8 *m_data;
113         u32 m_datalen;
114         s32 *m_refcount;
115 };
116
117 // TODO: Remove this. It is not used as supposed.
118 class LazyMeshUpdater
119 {
120 public:
121         LazyMeshUpdater(Environment *env)
122         {
123                 m_env = env;
124         }
125         ~LazyMeshUpdater()
126         {
127                 /*
128                         TODO: This could be optimized. It will currently
129                         double-update some blocks.
130                 */
131                 for(core::map<v3s16, bool>::Iterator
132                                 i = m_blocks.getIterator();
133                                 i.atEnd() == false; i++)
134                 {
135                         v3s16 p = i.getNode()->getKey();
136                         m_env->updateMeshes(p);
137                 }
138                 m_blocks.clear();
139         }
140         void add(v3s16 p)
141         {
142                 m_blocks.insert(p, true);
143         }
144 private:
145         Environment *m_env;
146         core::map<v3s16, bool> m_blocks;
147 };
148
149 class Client : public con::PeerHandler
150 {
151 public:
152         /*
153                 NOTE: Every public method should be thread-safe
154         */
155         Client(IrrlichtDevice *device, const char *playername);
156         ~Client();
157         /*
158                 The name of the local player should already be set when
159                 calling this, as it is sent in the initialization.
160         */
161         void connect(Address address);
162         /*
163                 returns true when
164                         m_con.Connected() == true
165                         AND m_server_ser_ver != SER_FMT_VER_INVALID
166                 throws con::PeerNotFoundException if connection has been deleted,
167                 eg. timed out.
168         */
169         bool connectedAndInitialized();
170         /*
171                 Stuff that references the environment is valid only as
172                 long as this is not called. (eg. Players)
173                 If this throws a PeerNotFoundException, the connection has
174                 timed out.
175         */
176         void step(float dtime);
177
178         // Called from updater thread
179         // Returns dtime
180         float asyncStep();
181
182         void ProcessData(u8 *data, u32 datasize, u16 sender_peer_id);
183         // Returns true if something was received
184         bool AsyncProcessPacket(LazyMeshUpdater &mesh_updater);
185         bool AsyncProcessData();
186         void Send(u16 channelnum, SharedBuffer<u8> data, bool reliable);
187
188         //TODO: Remove
189         bool isFetchingBlocks();
190
191         // Pops out a packet from the packet queue
192         IncomingPacket getPacket();
193
194         /*void removeNode(v3s16 nodepos);
195         void addNodeFromInventory(v3s16 nodepos, u16 i);*/
196         void pressGround(u8 button, v3s16 nodepos_undersurface,
197                         v3s16 nodepos_oversurface, u16 item);
198         void clickObject(u8 button, v3s16 blockpos, s16 id, u16 item);
199         void stopDigging();
200
201         void sendSignText(v3s16 blockpos, s16 id, std::string text);
202         
203         void updateCamera(v3f pos, v3f dir);
204         
205         // Returns InvalidPositionException if not found
206         MapNode getNode(v3s16 p);
207         // Returns InvalidPositionException if not found
208         //f32 getGroundHeight(v2s16 p);
209         // Returns InvalidPositionException if not found
210         bool isNodeUnderground(v3s16 p);
211
212         // Note: The players should not be exposed outside
213         // Return value is valid until client is destroyed
214         //Player * getLocalPlayer();
215         // Return value is valid until step()
216         //core::list<Player*> getPlayers();
217         v3f getPlayerPosition();
218
219         void setPlayerControl(PlayerControl &control);
220         
221         // Returns true if the inventory of the local player has been
222         // updated from the server. If it is true, it is set to false.
223         bool getLocalInventoryUpdated();
224         // Copies the inventory of the local player to parameter
225         void getLocalInventory(Inventory &dst);
226         // TODO: Functions for sending inventory editing commands to
227         //       server
228         
229         // Gets closest object pointed by the shootline
230         // Returns NULL if not found
231         MapBlockObject * getSelectedObject(
232                         f32 max_d,
233                         v3f from_pos_f_on_map,
234                         core::line3d<f32> shootline_on_map
235         );
236
237         // Prints a line or two of info
238         void printDebugInfo(std::ostream &os);
239
240         float getDaylightRatio();
241         
242 private:
243         
244         // Virtual methods from con::PeerHandler
245         void peerAdded(con::Peer *peer);
246         void deletingPeer(con::Peer *peer, bool timeout);
247         
248         void ReceiveAll();
249         void Receive();
250         
251         void sendPlayerPos();
252         // This sends the player's current name etc to the server
253         void sendPlayerInfo();
254
255         ClientUpdateThread m_thread;
256         
257         // NOTE: If connection and environment are both to be locked,
258         // environment shall be locked first.
259
260         Environment m_env;
261         JMutex m_env_mutex;
262         
263         con::Connection m_con;
264         JMutex m_con_mutex;
265
266         /*core::map<v3s16, float> m_fetchblock_history;
267         JMutex m_fetchblock_mutex;*/
268
269         core::list<IncomingPacket> m_incoming_queue;
270         JMutex m_incoming_queue_mutex;
271
272         IrrlichtDevice *m_device;
273
274         v3f camera_position;
275         v3f camera_direction;
276         
277         // Server serialization version
278         u8 m_server_ser_ver;
279
280         float m_step_dtime;
281         JMutex m_step_dtime_mutex;
282
283         // This is behind m_env_mutex.
284         bool m_inventory_updated;
285
286         core::map<v3s16, bool> m_active_blocks;
287
288         PacketCounter m_packetcounter;
289         
290         // Access these only in main thread.
291         u32 m_time;
292         float m_time_counter;
293 };
294
295 #endif
296