d9d8b13aeb046d4754cfe3936dfe6359225d2c7a
[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_daylight_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         delete m_map;
40 }
41
42 void Environment::step(float dtime)
43 {
44         DSTACK(__FUNCTION_NAME);
45         /*
46                 Run Map's timers
47         */
48         //TimeTaker maptimerupdatetimer("m_map->timerUpdate()", g_device);
49         // 0ms
50         m_map->timerUpdate(dtime);
51         //maptimerupdatetimer.stop();
52
53         /*
54                 Get the highest speed some player is going
55         */
56         //TimeTaker playerspeed("playerspeed", g_device);
57         // 0ms
58         f32 maximum_player_speed = 0.001; // just some small value
59         for(core::list<Player*>::Iterator i = m_players.begin();
60                         i != m_players.end(); i++)
61         {
62                 f32 speed = (*i)->getSpeed().getLength();
63                 if(speed > maximum_player_speed)
64                         maximum_player_speed = speed;
65         }
66         //playerspeed.stop();
67         
68         // Maximum time increment (for collision detection etc)
69         // Allow 0.1 blocks per increment
70         // time = distance / speed
71         f32 dtime_max_increment = 0.1*BS / maximum_player_speed;
72         // Maximum time increment is 10ms or lower
73         if(dtime_max_increment > 0.01)
74                 dtime_max_increment = 0.01;
75         
76         //TimeTaker playerupdate("playerupdate", g_device);
77         
78         /*
79                 Stuff that has a maximum time increment
80         */
81         // Don't allow overly huge dtime
82         if(dtime > 0.5)
83                 dtime = 0.5;
84
85         u32 loopcount = 0;
86         do
87         {
88                 loopcount++;
89
90                 f32 dtime_part;
91                 if(dtime > dtime_max_increment)
92                         dtime_part = dtime_max_increment;
93                 else
94                         dtime_part = dtime;
95                 dtime -= dtime_part;
96                 
97                 /*
98                         Handle players
99                 */
100                 for(core::list<Player*>::Iterator i = m_players.begin();
101                                 i != m_players.end(); i++)
102                 {
103                         Player *player = *i;
104                         
105                         // Apply physics to local player
106                         if(player->isLocal())
107                         {
108                                 // Apply gravity to local player
109                                 v3f speed = player->getSpeed();
110                                 speed.Y -= 9.81 * BS * dtime_part * 2;
111
112                                 /*
113                                         Apply water resistance
114                                 */
115                                 if(player->in_water)
116                                 {
117                                         f32 max_down = 1.0*BS;
118                                         if(speed.Y < -max_down) speed.Y = -max_down;
119
120                                         f32 max = 2.0*BS;
121                                         if(speed.getLength() > max)
122                                         {
123                                                 speed = speed / speed.getLength() * max;
124                                         }
125                                 }
126
127                                 player->setSpeed(speed);
128                         }
129
130                         /*
131                                 Move the player.
132                                 For local player, this also calculates collision detection.
133                         */
134                         player->move(dtime_part, *m_map);
135                         
136                         /*
137                                 Add footsteps to grass
138                         */
139                         //TimeTaker footsteptimer("footstep", g_device);
140                         // 0ms
141                         v3f playerpos = player->getPosition();
142                         // Get node that is at BS/4 under player
143                         v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0));
144                         try{
145                                 MapNode n = m_map->getNode(bottompos);
146                                 if(n.d == CONTENT_GRASS)
147                                 {
148                                         n.d = CONTENT_GRASS_FOOTSTEPS;
149                                         m_map->setNode(bottompos, n);
150
151                                         // Update mesh on client
152                                         if(m_map->mapType() == MAPTYPE_CLIENT)
153                                         {
154                                                 v3s16 p_blocks = getNodeBlockPos(bottompos);
155                                                 MapBlock *b = m_map->getBlockNoCreate(p_blocks);
156                                                 b->updateMesh(m_daylight_ratio);
157                                         }
158                                 }
159                         }
160                         catch(InvalidPositionException &e)
161                         {
162                         }
163                         //footsteptimer.stop();
164                 }
165         }
166         while(dtime > 0.001);
167         
168         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
169 }
170
171 Map & Environment::getMap()
172 {
173         return *m_map;
174 }
175
176 void Environment::addPlayer(Player *player)
177 {
178         DSTACK(__FUNCTION_NAME);
179         //Check that only one local player exists and peer_ids are unique
180         assert(player->isLocal() == false || getLocalPlayer() == NULL);
181         assert(getPlayer(player->peer_id) == NULL);
182         m_players.push_back(player);
183 }
184
185 void Environment::removePlayer(u16 peer_id)
186 {
187         DSTACK(__FUNCTION_NAME);
188 re_search:
189         for(core::list<Player*>::Iterator i = m_players.begin();
190                         i != m_players.end(); i++)
191         {
192                 Player *player = *i;
193                 if(player->peer_id != peer_id)
194                         continue;
195                 
196                 delete player;
197                 m_players.erase(i);
198                 // See if there is an another one
199                 // (shouldn't be, but just to be sure)
200                 goto re_search;
201         }
202 }
203
204 LocalPlayer * Environment::getLocalPlayer()
205 {
206         for(core::list<Player*>::Iterator i = m_players.begin();
207                         i != m_players.end(); i++)
208         {
209                 Player *player = *i;
210                 if(player->isLocal())
211                         return (LocalPlayer*)player;
212         }
213         return NULL;
214 }
215
216 Player * Environment::getPlayer(u16 peer_id)
217 {
218         for(core::list<Player*>::Iterator i = m_players.begin();
219                         i != m_players.end(); i++)
220         {
221                 Player *player = *i;
222                 if(player->peer_id == peer_id)
223                         return player;
224         }
225         return NULL;
226 }
227
228 core::list<Player*> Environment::getPlayers()
229 {
230         return m_players;
231 }
232
233 void Environment::printPlayers(std::ostream &o)
234 {
235         o<<"Players in environment:"<<std::endl;
236         for(core::list<Player*>::Iterator i = m_players.begin();
237                         i != m_players.end(); i++)
238         {
239                 Player *player = *i;
240                 o<<"Player peer_id="<<player->peer_id<<std::endl;
241         }
242 }
243
244 void Environment::updateMeshes(v3s16 blockpos)
245 {
246         m_map->updateMeshes(blockpos, m_daylight_ratio);
247 }
248
249 void Environment::expireMeshes()
250 {
251         m_map->expireMeshes();
252 }
253
254 void Environment::setDaylightRatio(u32 r)
255 {
256         m_daylight_ratio = r;
257 }
258
259 u32 Environment::getDaylightRatio()
260 {
261         return m_daylight_ratio;
262 }
263