doc updates; CMake works reasonably well now.
[oweals/minetest.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 #include "main.h" // g_device for timing debug
22
23 Environment::Environment(Map *map, std::ostream &dout):
24                 m_dout(dout)
25 {
26         m_map = map;
27         m_daynight_ratio = 0.2;
28 }
29
30 Environment::~Environment()
31 {
32         // Deallocate players
33         for(core::list<Player*>::Iterator i = m_players.begin();
34                         i != m_players.end(); i++)
35         {
36                 delete (*i);
37         }
38         
39         // The map is removed by the SceneManager
40         m_map->drop();
41         //delete m_map;
42 }
43
44 void Environment::step(float dtime)
45 {
46         DSTACK(__FUNCTION_NAME);
47         /*
48                 Run Map's timers
49         */
50         //TimeTaker maptimerupdatetimer("m_map->timerUpdate()", g_device);
51         // 0ms
52         m_map->timerUpdate(dtime);
53         //maptimerupdatetimer.stop();
54
55         /*
56                 Get the highest speed some player is going
57         */
58         //TimeTaker playerspeed("playerspeed", g_device);
59         // 0ms
60         f32 maximum_player_speed = 0.001; // just some small value
61         for(core::list<Player*>::Iterator i = m_players.begin();
62                         i != m_players.end(); i++)
63         {
64                 f32 speed = (*i)->getSpeed().getLength();
65                 if(speed > maximum_player_speed)
66                         maximum_player_speed = speed;
67         }
68         //playerspeed.stop();
69         
70         // Maximum time increment (for collision detection etc)
71         // Allow 0.1 blocks per increment
72         // time = distance / speed
73         f32 dtime_max_increment = 0.1*BS / maximum_player_speed;
74         // Maximum time increment is 10ms or lower
75         if(dtime_max_increment > 0.01)
76                 dtime_max_increment = 0.01;
77         
78         //TimeTaker playerupdate("playerupdate", g_device);
79         
80         /*
81                 Stuff that has a maximum time increment
82         */
83         // Don't allow overly huge dtime
84         if(dtime > 0.5)
85                 dtime = 0.5;
86
87         u32 loopcount = 0;
88         do
89         {
90                 loopcount++;
91
92                 f32 dtime_part;
93                 if(dtime > dtime_max_increment)
94                         dtime_part = dtime_max_increment;
95                 else
96                         dtime_part = dtime;
97                 dtime -= dtime_part;
98                 
99                 /*
100                         Handle players
101                 */
102                 for(core::list<Player*>::Iterator i = m_players.begin();
103                                 i != m_players.end(); i++)
104                 {
105                         Player *player = *i;
106
107                         v3f playerpos = player->getPosition();
108                         
109                         // Apply physics to local player
110                         if(player->isLocal())
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.0*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         //Check that only one local player exists and peer_ids are unique
194 #ifndef SERVER
195         assert(player->isLocal() == false || getLocalPlayer() == NULL);
196 #endif
197         assert(getPlayer(player->peer_id) == NULL);
198         m_players.push_back(player);
199 }
200
201 void Environment::removePlayer(u16 peer_id)
202 {
203         DSTACK(__FUNCTION_NAME);
204 re_search:
205         for(core::list<Player*>::Iterator i = m_players.begin();
206                         i != m_players.end(); i++)
207         {
208                 Player *player = *i;
209                 if(player->peer_id != peer_id)
210                         continue;
211                 
212                 delete player;
213                 m_players.erase(i);
214                 // See if there is an another one
215                 // (shouldn't be, but just to be sure)
216                 goto re_search;
217         }
218 }
219
220 #ifndef SERVER
221 LocalPlayer * Environment::getLocalPlayer()
222 {
223         for(core::list<Player*>::Iterator i = m_players.begin();
224                         i != m_players.end(); i++)
225         {
226                 Player *player = *i;
227                 if(player->isLocal())
228                         return (LocalPlayer*)player;
229         }
230         return NULL;
231 }
232 #endif
233
234 Player * Environment::getPlayer(u16 peer_id)
235 {
236         for(core::list<Player*>::Iterator i = m_players.begin();
237                         i != m_players.end(); i++)
238         {
239                 Player *player = *i;
240                 if(player->peer_id == peer_id)
241                         return player;
242         }
243         return NULL;
244 }
245
246 core::list<Player*> Environment::getPlayers()
247 {
248         return m_players;
249 }
250
251 void Environment::printPlayers(std::ostream &o)
252 {
253         o<<"Players in environment:"<<std::endl;
254         for(core::list<Player*>::Iterator i = m_players.begin();
255                         i != m_players.end(); i++)
256         {
257                 Player *player = *i;
258                 o<<"Player peer_id="<<player->peer_id<<std::endl;
259         }
260 }
261
262 #ifndef SERVER
263 void Environment::updateMeshes(v3s16 blockpos)
264 {
265         m_map->updateMeshes(blockpos, m_daynight_ratio);
266 }
267
268 void Environment::expireMeshes(bool only_daynight_diffed)
269 {
270         m_map->expireMeshes(only_daynight_diffed);
271 }
272 #endif
273
274 void Environment::setDayNightRatio(u32 r)
275 {
276         m_daynight_ratio = r;
277 }
278
279 u32 Environment::getDayNightRatio()
280 {
281         return m_daynight_ratio;
282 }
283