]> git.lizzy.rs Git - minetest.git/blob - src/environment.cpp
added sneaking/crouching and changelog
[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 "filesys.h"
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         /*
71                 Maximum position increment
72         */
73         //f32 position_max_increment = 0.05*BS;
74         f32 position_max_increment = 0.1*BS;
75
76         // Maximum time increment (for collision detection etc)
77         // time = distance / speed
78         f32 dtime_max_increment = position_max_increment / maximum_player_speed;
79         // Maximum time increment is 10ms or lower
80         if(dtime_max_increment > 0.01)
81                 dtime_max_increment = 0.01;
82         
83         //TimeTaker playerupdate("playerupdate", g_device);
84         
85         /*
86                 Stuff that has a maximum time increment
87         */
88         // Don't allow overly huge dtime
89         if(dtime > 0.5)
90                 dtime = 0.5;
91
92         u32 loopcount = 0;
93         do
94         {
95                 loopcount++;
96
97                 f32 dtime_part;
98                 if(dtime > dtime_max_increment)
99                         dtime_part = dtime_max_increment;
100                 else
101                         dtime_part = dtime;
102                 dtime -= dtime_part;
103                 
104                 /*
105                         Handle players
106                 */
107                 for(core::list<Player*>::Iterator i = m_players.begin();
108                                 i != m_players.end(); i++)
109                 {
110                         Player *player = *i;
111
112                         v3f playerpos = player->getPosition();
113                         
114                         // Apply physics to local player
115                         bool free_move = g_settings.getBool("free_move");
116                         if(player->isLocal() && free_move == false)
117                         {
118                                 // Apply gravity to local player
119                                 v3f speed = player->getSpeed();
120                                 if(player->swimming_up == false)
121                                         speed.Y -= 9.81 * BS * dtime_part * 2;
122
123                                 /*
124                                         Apply water resistance
125                                 */
126                                 if(player->in_water_stable || player->in_water)
127                                 {
128                                         f32 max_down = 2.0*BS;
129                                         if(speed.Y < -max_down) speed.Y = -max_down;
130
131                                         f32 max = 2.5*BS;
132                                         if(speed.getLength() > max)
133                                         {
134                                                 speed = speed / speed.getLength() * max;
135                                         }
136                                 }
137
138                                 player->setSpeed(speed);
139                         }
140
141                         /*
142                                 Move the player.
143                                 For local player, this also calculates collision detection.
144                         */
145                         player->move(dtime_part, *m_map, position_max_increment);
146                         
147                         /*
148                                 Update lighting on remote players on client
149                         */
150                         u8 light = LIGHT_MAX;
151                         try{
152                                 // Get node at feet
153                                 v3s16 p = floatToInt(playerpos + v3f(0,BS/4,0));
154                                 MapNode n = m_map->getNode(p);
155                                 light = n.getLightBlend(m_daynight_ratio);
156                         }
157                         catch(InvalidPositionException &e) {}
158                         player->updateLight(light);
159
160                         /*
161                                 Add footsteps to grass
162                         */
163                         if(g_settings.getBool("footprints"))
164                         {
165                                 // Get node that is at BS/4 under player
166                                 v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0));
167                                 try{
168                                         MapNode n = m_map->getNode(bottompos);
169                                         if(n.d == CONTENT_GRASS)
170                                         {
171                                                 n.d = CONTENT_GRASS_FOOTSTEPS;
172                                                 m_map->setNode(bottompos, n);
173 #ifndef SERVER
174                                                 // Update mesh on client
175                                                 if(m_map->mapType() == MAPTYPE_CLIENT)
176                                                 {
177                                                         v3s16 p_blocks = getNodeBlockPos(bottompos);
178                                                         MapBlock *b = m_map->getBlockNoCreate(p_blocks);
179                                                         b->updateMesh(m_daynight_ratio);
180                                                 }
181 #endif
182                                         }
183                                 }
184                                 catch(InvalidPositionException &e)
185                                 {
186                                 }
187                         }
188                 }
189         }
190         while(dtime > 0.001);
191         
192         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
193 }
194
195 Map & Environment::getMap()
196 {
197         return *m_map;
198 }
199
200 void Environment::addPlayer(Player *player)
201 {
202         DSTACK(__FUNCTION_NAME);
203         /*
204                 Check that only one local player exists and peer_ids are unique.
205                 Also check that names are unique.
206                 Exception: there can be multiple players with peer_id=0
207         */
208 #ifndef SERVER
209         /*
210                 It is a failure if player is local and there already is a local
211                 player
212         */
213         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
214 #endif
215         // If peer id is non-zero, it has to be unique.
216         if(player->peer_id != 0)
217                 assert(getPlayer(player->peer_id) == NULL);
218         // Name has to be unique.
219         assert(getPlayer(player->getName()) == NULL);
220         // Add.
221         m_players.push_back(player);
222 }
223
224 void Environment::removePlayer(u16 peer_id)
225 {
226         DSTACK(__FUNCTION_NAME);
227 re_search:
228         for(core::list<Player*>::Iterator i = m_players.begin();
229                         i != m_players.end(); i++)
230         {
231                 Player *player = *i;
232                 if(player->peer_id != peer_id)
233                         continue;
234                 
235                 delete player;
236                 m_players.erase(i);
237                 // See if there is an another one
238                 // (shouldn't be, but just to be sure)
239                 goto re_search;
240         }
241 }
242
243 #ifndef SERVER
244 LocalPlayer * Environment::getLocalPlayer()
245 {
246         for(core::list<Player*>::Iterator i = m_players.begin();
247                         i != m_players.end(); i++)
248         {
249                 Player *player = *i;
250                 if(player->isLocal())
251                         return (LocalPlayer*)player;
252         }
253         return NULL;
254 }
255 #endif
256
257 Player * Environment::getPlayer(u16 peer_id)
258 {
259         for(core::list<Player*>::Iterator i = m_players.begin();
260                         i != m_players.end(); i++)
261         {
262                 Player *player = *i;
263                 if(player->peer_id == peer_id)
264                         return player;
265         }
266         return NULL;
267 }
268
269 Player * Environment::getPlayer(const char *name)
270 {
271         for(core::list<Player*>::Iterator i = m_players.begin();
272                         i != m_players.end(); i++)
273         {
274                 Player *player = *i;
275                 if(strcmp(player->getName(), name) == 0)
276                         return player;
277         }
278         return NULL;
279 }
280
281 core::list<Player*> Environment::getPlayers()
282 {
283         return m_players;
284 }
285
286 core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
287 {
288         core::list<Player*> newlist;
289         for(core::list<Player*>::Iterator
290                         i = m_players.begin();
291                         i != m_players.end(); i++)
292         {
293                 Player *player = *i;
294                 
295                 if(ignore_disconnected)
296                 {
297                         // Ignore disconnected players
298                         if(player->peer_id == 0)
299                                 continue;
300                 }
301
302                 newlist.push_back(player);
303         }
304         return newlist;
305 }
306
307 void Environment::printPlayers(std::ostream &o)
308 {
309         o<<"Players in environment:"<<std::endl;
310         for(core::list<Player*>::Iterator i = m_players.begin();
311                         i != m_players.end(); i++)
312         {
313                 Player *player = *i;
314                 o<<"Player peer_id="<<player->peer_id<<std::endl;
315         }
316 }
317
318 void Environment::serializePlayers(const std::string &savedir)
319 {
320         std::string players_path = savedir + "/players";
321         fs::CreateDir(players_path);
322
323         core::map<Player*, bool> saved_players;
324
325         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
326         for(u32 i=0; i<player_files.size(); i++)
327         {
328                 if(player_files[i].dir)
329                         continue;
330                 
331                 // Full path to this file
332                 std::string path = players_path + "/" + player_files[i].name;
333
334                 //dstream<<"Checking player file "<<path<<std::endl;
335
336                 // Load player to see what is its name
337                 ServerRemotePlayer testplayer;
338                 {
339                         // Open file and deserialize
340                         std::ifstream is(path.c_str(), std::ios_base::binary);
341                         if(is.good() == false)
342                         {
343                                 dstream<<"Failed to read "<<path<<std::endl;
344                                 continue;
345                         }
346                         testplayer.deSerialize(is);
347                 }
348
349                 //dstream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
350                 
351                 // Search for the player
352                 std::string playername = testplayer.getName();
353                 Player *player = getPlayer(playername.c_str());
354                 if(player == NULL)
355                 {
356                         dstream<<"Didn't find matching player, ignoring file "<<path<<std::endl;
357                         continue;
358                 }
359
360                 //dstream<<"Found matching player, overwriting."<<std::endl;
361
362                 // OK, found. Save player there.
363                 {
364                         // Open file and serialize
365                         std::ofstream os(path.c_str(), std::ios_base::binary);
366                         if(os.good() == false)
367                         {
368                                 dstream<<"Failed to overwrite "<<path<<std::endl;
369                                 continue;
370                         }
371                         player->serialize(os);
372                         saved_players.insert(player, true);
373                 }
374         }
375
376         for(core::list<Player*>::Iterator i = m_players.begin();
377                         i != m_players.end(); i++)
378         {
379                 Player *player = *i;
380                 if(saved_players.find(player) != NULL)
381                 {
382                         /*dstream<<"Player "<<player->getName()
383                                         <<" was already saved."<<std::endl;*/
384                         continue;
385                 }
386                 std::string playername = player->getName();
387                 // Don't save unnamed player
388                 if(playername == "")
389                 {
390                         //dstream<<"Not saving unnamed player."<<std::endl;
391                         continue;
392                 }
393                 /*
394                         Find a sane filename
395                 */
396                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
397                         playername = "player";
398                 std::string path = players_path + "/" + playername;
399                 bool found = false;
400                 for(u32 i=0; i<1000; i++)
401                 {
402                         if(fs::PathExists(path) == false)
403                         {
404                                 found = true;
405                                 break;
406                         }
407                         path = players_path + "/" + playername + itos(i);
408                 }
409                 if(found == false)
410                 {
411                         dstream<<"WARNING: Didn't find free file for player"<<std::endl;
412                         continue;
413                 }
414
415                 {
416                         /*dstream<<"Saving player "<<player->getName()<<" to "
417                                         <<path<<std::endl;*/
418                         // Open file and serialize
419                         std::ofstream os(path.c_str(), std::ios_base::binary);
420                         if(os.good() == false)
421                         {
422                                 dstream<<"WARNING: Failed to overwrite "<<path<<std::endl;
423                                 continue;
424                         }
425                         player->serialize(os);
426                         saved_players.insert(player, true);
427                 }
428         }
429
430         //dstream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
431 }
432
433 void Environment::deSerializePlayers(const std::string &savedir)
434 {
435         std::string players_path = savedir + "/players";
436
437         core::map<Player*, bool> saved_players;
438
439         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
440         for(u32 i=0; i<player_files.size(); i++)
441         {
442                 if(player_files[i].dir)
443                         continue;
444                 
445                 // Full path to this file
446                 std::string path = players_path + "/" + player_files[i].name;
447
448                 dstream<<"Checking player file "<<path<<std::endl;
449
450                 // Load player to see what is its name
451                 ServerRemotePlayer testplayer;
452                 {
453                         // Open file and deserialize
454                         std::ifstream is(path.c_str(), std::ios_base::binary);
455                         if(is.good() == false)
456                         {
457                                 dstream<<"Failed to read "<<path<<std::endl;
458                                 continue;
459                         }
460                         testplayer.deSerialize(is);
461                 }
462
463                 dstream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
464                 
465                 // Search for the player
466                 std::string playername = testplayer.getName();
467                 Player *player = getPlayer(playername.c_str());
468                 bool newplayer = false;
469                 if(player == NULL)
470                 {
471                         dstream<<"Is a new player"<<std::endl;
472                         player = new ServerRemotePlayer();
473                         newplayer = true;
474                 }
475
476                 // Load player
477                 {
478                         dstream<<"Reading player "<<testplayer.getName()<<" from "
479                                         <<path<<std::endl;
480                         // Open file and deserialize
481                         std::ifstream is(path.c_str(), std::ios_base::binary);
482                         if(is.good() == false)
483                         {
484                                 dstream<<"Failed to read "<<path<<std::endl;
485                                 continue;
486                         }
487                         player->deSerialize(is);
488                 }
489
490                 if(newplayer)
491                         addPlayer(player);
492         }
493 }
494
495 #ifndef SERVER
496 void Environment::updateMeshes(v3s16 blockpos)
497 {
498         m_map->updateMeshes(blockpos, m_daynight_ratio);
499 }
500
501 void Environment::expireMeshes(bool only_daynight_diffed)
502 {
503         m_map->expireMeshes(only_daynight_diffed);
504 }
505 #endif
506
507 void Environment::setDayNightRatio(u32 r)
508 {
509         m_daynight_ratio = r;
510 }
511
512 u32 Environment::getDayNightRatio()
513 {
514         return m_daynight_ratio;
515 }
516