]> git.lizzy.rs Git - dragonfireclient.git/blob - src/environment.cpp
comments
[dragonfireclient.git] / src / environment.cpp
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 #include "environment.h"
21
22 Environment::Environment(Map *map, std::ostream &dout):
23                 m_dout(dout)
24 {
25         m_map = map;
26         m_daynight_ratio = 0.2;
27 }
28
29 Environment::~Environment()
30 {
31         // Deallocate players
32         for(core::list<Player*>::Iterator i = m_players.begin();
33                         i != m_players.end(); i++)
34         {
35                 delete (*i);
36         }
37         
38         // The map is removed by the SceneManager
39         m_map->drop();
40         //delete m_map;
41 }
42
43 void Environment::step(float dtime)
44 {
45         DSTACK(__FUNCTION_NAME);
46         /*
47                 Run Map's timers
48         */
49         //TimeTaker maptimerupdatetimer("m_map->timerUpdate()", g_device);
50         // 0ms
51         m_map->timerUpdate(dtime);
52         //maptimerupdatetimer.stop();
53
54         /*
55                 Get the highest speed some player is going
56         */
57         //TimeTaker playerspeed("playerspeed", g_device);
58         // 0ms
59         f32 maximum_player_speed = 0.001; // just some small value
60         for(core::list<Player*>::Iterator i = m_players.begin();
61                         i != m_players.end(); i++)
62         {
63                 f32 speed = (*i)->getSpeed().getLength();
64                 if(speed > maximum_player_speed)
65                         maximum_player_speed = speed;
66         }
67         //playerspeed.stop();
68         
69         // Maximum time increment (for collision detection etc)
70         // Allow 0.1 blocks per increment
71         // time = distance / speed
72         f32 dtime_max_increment = 0.1*BS / maximum_player_speed;
73         // Maximum time increment is 10ms or lower
74         if(dtime_max_increment > 0.01)
75                 dtime_max_increment = 0.01;
76         
77         //TimeTaker playerupdate("playerupdate", g_device);
78         
79         /*
80                 Stuff that has a maximum time increment
81         */
82         // Don't allow overly huge dtime
83         if(dtime > 0.5)
84                 dtime = 0.5;
85
86         u32 loopcount = 0;
87         do
88         {
89                 loopcount++;
90
91                 f32 dtime_part;
92                 if(dtime > dtime_max_increment)
93                         dtime_part = dtime_max_increment;
94                 else
95                         dtime_part = dtime;
96                 dtime -= dtime_part;
97                 
98                 /*
99                         Handle players
100                 */
101                 for(core::list<Player*>::Iterator i = m_players.begin();
102                                 i != m_players.end(); i++)
103                 {
104                         Player *player = *i;
105
106                         v3f playerpos = player->getPosition();
107                         
108                         // Apply physics to local player
109                         bool haxmode = g_settings.getBool("haxmode");
110                         if(player->isLocal() && haxmode == false)
111                         {
112                                 // Apply gravity to local player
113                                 v3f speed = player->getSpeed();
114                                 speed.Y -= 9.81 * BS * dtime_part * 2;
115
116                                 /*
117                                         Apply water resistance
118                                 */
119                                 if(player->in_water)
120                                 {
121                                         f32 max_down = 1.0*BS;
122                                         if(speed.Y < -max_down) speed.Y = -max_down;
123
124                                         f32 max = 2.5*BS;
125                                         if(speed.getLength() > max)
126                                         {
127                                                 speed = speed / speed.getLength() * max;
128                                         }
129                                 }
130
131                                 player->setSpeed(speed);
132                         }
133
134                         /*
135                                 Move the player.
136                                 For local player, this also calculates collision detection.
137                         */
138                         player->move(dtime_part, *m_map);
139                         
140                         /*
141                                 Update lighting on remote players on client
142                         */
143                         u8 light = LIGHT_MAX;
144                         try{
145                                 // Get node at feet
146                                 v3s16 p = floatToInt(playerpos + v3f(0,BS/4,0));
147                                 MapNode n = m_map->getNode(p);
148                                 light = n.getLightBlend(m_daynight_ratio);
149                         }
150                         catch(InvalidPositionException &e) {}
151                         player->updateLight(light);
152
153                         /*
154                                 Add footsteps to grass
155                         */
156                         // Get node that is at BS/4 under player
157                         v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0));
158                         try{
159                                 MapNode n = m_map->getNode(bottompos);
160                                 if(n.d == CONTENT_GRASS)
161                                 {
162                                         n.d = CONTENT_GRASS_FOOTSTEPS;
163                                         m_map->setNode(bottompos, n);
164 #ifndef SERVER
165                                         // Update mesh on client
166                                         if(m_map->mapType() == MAPTYPE_CLIENT)
167                                         {
168                                                 v3s16 p_blocks = getNodeBlockPos(bottompos);
169                                                 MapBlock *b = m_map->getBlockNoCreate(p_blocks);
170                                                 b->updateMesh(m_daynight_ratio);
171                                         }
172 #endif
173                                 }
174                         }
175                         catch(InvalidPositionException &e)
176                         {
177                         }
178                 }
179         }
180         while(dtime > 0.001);
181         
182         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
183 }
184
185 Map & Environment::getMap()
186 {
187         return *m_map;
188 }
189
190 void Environment::addPlayer(Player *player)
191 {
192         DSTACK(__FUNCTION_NAME);
193         /*
194                 Check that only one local player exists and peer_ids are unique.
195                 Exception: there can be multiple players with peer_id=0
196         */
197 #ifndef SERVER
198         /*
199                 It is a failure if player is local and there already is a local
200                 player
201         */
202         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
203 #endif
204         if(player->peer_id != 0)
205                 assert(getPlayer(player->peer_id) == NULL);
206         m_players.push_back(player);
207 }
208
209 void Environment::removePlayer(u16 peer_id)
210 {
211         DSTACK(__FUNCTION_NAME);
212 re_search:
213         for(core::list<Player*>::Iterator i = m_players.begin();
214                         i != m_players.end(); i++)
215         {
216                 Player *player = *i;
217                 if(player->peer_id != peer_id)
218                         continue;
219                 
220                 delete player;
221                 m_players.erase(i);
222                 // See if there is an another one
223                 // (shouldn't be, but just to be sure)
224                 goto re_search;
225         }
226 }
227
228 #ifndef SERVER
229 LocalPlayer * Environment::getLocalPlayer()
230 {
231         for(core::list<Player*>::Iterator i = m_players.begin();
232                         i != m_players.end(); i++)
233         {
234                 Player *player = *i;
235                 if(player->isLocal())
236                         return (LocalPlayer*)player;
237         }
238         return NULL;
239 }
240 #endif
241
242 Player * Environment::getPlayer(u16 peer_id)
243 {
244         for(core::list<Player*>::Iterator i = m_players.begin();
245                         i != m_players.end(); i++)
246         {
247                 Player *player = *i;
248                 if(player->peer_id == peer_id)
249                         return player;
250         }
251         return NULL;
252 }
253
254 Player * Environment::getPlayer(const char *name)
255 {
256         for(core::list<Player*>::Iterator i = m_players.begin();
257                         i != m_players.end(); i++)
258         {
259                 Player *player = *i;
260                 if(strcmp(player->getName(), name) == 0)
261                         return player;
262         }
263         return NULL;
264 }
265
266 core::list<Player*> Environment::getPlayers()
267 {
268         return m_players;
269 }
270
271 core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
272 {
273         core::list<Player*> newlist;
274         for(core::list<Player*>::Iterator
275                         i = m_players.begin();
276                         i != m_players.end(); i++)
277         {
278                 Player *player = *i;
279                 
280                 if(ignore_disconnected)
281                 {
282                         // Ignore disconnected players
283                         if(player->peer_id == 0)
284                                 continue;
285                 }
286
287                 newlist.push_back(player);
288         }
289         return newlist;
290 }
291
292 void Environment::printPlayers(std::ostream &o)
293 {
294         o<<"Players in environment:"<<std::endl;
295         for(core::list<Player*>::Iterator i = m_players.begin();
296                         i != m_players.end(); i++)
297         {
298                 Player *player = *i;
299                 o<<"Player peer_id="<<player->peer_id<<std::endl;
300         }
301 }
302
303 #ifndef SERVER
304 void Environment::updateMeshes(v3s16 blockpos)
305 {
306         m_map->updateMeshes(blockpos, m_daynight_ratio);
307 }
308
309 void Environment::expireMeshes(bool only_daynight_diffed)
310 {
311         m_map->expireMeshes(only_daynight_diffed);
312 }
313 #endif
314
315 void Environment::setDayNightRatio(u32 r)
316 {
317         m_daynight_ratio = r;
318 }
319
320 u32 Environment::getDayNightRatio()
321 {
322         return m_daynight_ratio;
323 }
324