]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblockobject.cpp
779fe3fa71d0257c208c20d00082f880039e4259
[dragonfireclient.git] / src / mapblockobject.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 "mapblockobject.h"
21 #include "mapblock.h"
22 // Only for ::getNodeBox, TODO: Get rid of this
23 #include "map.h"
24
25 /*
26         MapBlockObject
27 */
28
29 // This is here because it uses the MapBlock
30 v3f MapBlockObject::getAbsolutePos()
31 {
32         if(m_block == NULL)
33                 return m_pos;
34         
35         // getPosRelative gets nodepos relative to map origin
36         v3f blockpos = intToFloat(m_block->getPosRelative());
37         return blockpos + m_pos;
38 }
39
40 void MapBlockObject::setBlockChanged()
41 {
42         if(m_block)
43                 m_block->setChangedFlag();
44 }
45
46 /*
47         MovingObject
48 */
49
50 v3f MovingObject::getAbsoluteShowPos()
51 {
52         if(m_block == NULL)
53                 return m_pos;
54         
55         // getPosRelative gets nodepos relative to map origin
56         v3f blockpos = intToFloat(m_block->getPosRelative());
57         return blockpos + m_showpos;
58 }
59
60 void MovingObject::move(float dtime, v3f acceleration)
61 {
62         DSTACK("%s: typeid=%i, pos=(%f,%f,%f), speed=(%f,%f,%f)"
63                         ", dtime=%f, acc=(%f,%f,%f)",
64                         __FUNCTION_NAME,
65                         getTypeId(),
66                         m_pos.X, m_pos.Y, m_pos.Z,
67                         m_speed.X, m_speed.Y, m_speed.Z,
68                         dtime,
69                         acceleration.X, acceleration.Y, acceleration.Z
70                         );
71         
72         v3s16 oldpos_i = floatToInt(m_pos);
73         
74         if(m_block->isValidPosition(oldpos_i) == false)
75         {
76                 // Should have wrapped, cancelling further movement.
77                 return;
78         }
79
80         // No collisions if there is no collision box
81         if(m_collision_box == NULL)
82         {
83                 m_speed += dtime * acceleration;
84                 m_pos += m_speed * dtime;
85                 return;
86         }
87         
88         // Set insane speed to zero
89         // Otherwise there will be divides by zero and other silly stuff
90         if(m_speed.getLength() > 1000.0*BS)
91                 m_speed = v3f(0,0,0);
92                 
93         // Limit speed to a reasonable value
94         float speed_limit = 20.0*BS;
95         if(m_speed.getLength() > speed_limit)
96                 m_speed = m_speed * (speed_limit / m_speed.getLength());
97
98         v3f position = m_pos;
99         v3f oldpos = position;
100
101         /*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
102                         <<oldpos_i.Z<<")"<<std::endl;*/
103
104         // Maximum time increment (for collision detection etc)
105         // Allow 0.1 blocks per increment
106         // time = distance / speed
107         // NOTE: In the loop below collisions are detected at 0.15*BS radius
108         float speedlength = m_speed.getLength();
109         f32 dtime_max_increment;
110         if(fabs(speedlength) > 0.001)
111                 dtime_max_increment = 0.05*BS / speedlength;
112         else
113                 dtime_max_increment = 0.5;
114         
115         m_touching_ground = false;
116                 
117         u32 loopcount = 0;
118         do
119         {
120                 loopcount++;
121
122                 f32 dtime_part;
123                 if(dtime > dtime_max_increment)
124                         dtime_part = dtime_max_increment;
125                 else
126                         dtime_part = dtime;
127                 dtime -= dtime_part;
128
129                 // Begin of dtime limited code
130                 
131                 m_speed += acceleration * dtime_part;
132                 position += m_speed * dtime_part;
133
134                 /*
135                         Collision detection
136                 */
137                 
138                 v3s16 pos_i = floatToInt(position);
139                 
140                 // The loop length is limited to the object moving a distance
141                 f32 d = (float)BS * 0.15;
142
143                 core::aabbox3d<f32> objectbox(
144                                 m_collision_box->MinEdge + position,
145                                 m_collision_box->MaxEdge + position
146                 );
147                 
148                 core::aabbox3d<f32> objectbox_old(
149                                 m_collision_box->MinEdge + oldpos,
150                                 m_collision_box->MaxEdge + oldpos
151                 );
152                 
153                 //TODO: Get these ranges from somewhere
154                 for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
155                 for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
156                 for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
157                 {
158                         try{
159                                 if(content_walkable(m_block->getNodeParent(v3s16(x,y,z)).d)
160                                                 == false)
161                                         continue;
162                         }
163                         catch(InvalidPositionException &e)
164                         {
165                                 // Doing nothing here will block the object from
166                                 // walking over map borders
167                         }
168
169                         core::aabbox3d<f32> nodebox = Map::getNodeBox(
170                                         v3s16(x,y,z));
171                         
172                         // See if the object is touching ground
173                         if(
174                                         fabs(nodebox.MaxEdge.Y-objectbox.MinEdge.Y) < d
175                                         && nodebox.MaxEdge.X-d > objectbox.MinEdge.X
176                                         && nodebox.MinEdge.X+d < objectbox.MaxEdge.X
177                                         && nodebox.MaxEdge.Z-d > objectbox.MinEdge.Z
178                                         && nodebox.MinEdge.Z+d < objectbox.MaxEdge.Z
179                         ){
180                                 m_touching_ground = true;
181                         }
182                         
183                         if(objectbox.intersectsWithBox(nodebox))
184                         {
185                                         
186                 v3f dirs[3] = {
187                         v3f(0,0,1), // back
188                         v3f(0,1,0), // top
189                         v3f(1,0,0), // right
190                 };
191                 for(u16 i=0; i<3; i++)
192                 {
193                         f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
194                         f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
195                         f32 playermax = objectbox.MaxEdge.dotProduct(dirs[i]);
196                         f32 playermin = objectbox.MinEdge.dotProduct(dirs[i]);
197                         f32 playermax_old = objectbox_old.MaxEdge.dotProduct(dirs[i]);
198                         f32 playermin_old = objectbox_old.MinEdge.dotProduct(dirs[i]);
199
200                         bool main_edge_collides = 
201                                 ((nodemax > playermin && nodemax <= playermin_old + d
202                                         && m_speed.dotProduct(dirs[i]) < 0)
203                                 ||
204                                 (nodemin < playermax && nodemin >= playermax_old - d
205                                         && m_speed.dotProduct(dirs[i]) > 0));
206
207                         bool other_edges_collide = true;
208                         for(u16 j=0; j<3; j++)
209                         {
210                                 if(j == i)
211                                         continue;
212                                 f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
213                                 f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
214                                 f32 playermax = objectbox.MaxEdge.dotProduct(dirs[j]);
215                                 f32 playermin = objectbox.MinEdge.dotProduct(dirs[j]);
216                                 if(!(nodemax - d > playermin && nodemin + d < playermax))
217                                 {
218                                         other_edges_collide = false;
219                                         break;
220                                 }
221                         }
222                         
223                         if(main_edge_collides && other_edges_collide)
224                         {
225                                 m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
226                                 position -= position.dotProduct(dirs[i]) * dirs[i];
227                                 position += oldpos.dotProduct(dirs[i]) * dirs[i];
228                         }
229                 
230                 }
231                 
232                         } // if(objectbox.intersectsWithBox(nodebox))
233                 } // for y
234
235         } // End of dtime limited loop
236         while(dtime > 0.001);
237
238         m_pos = position;
239 }
240
241 void MovingObject::simpleMove(float dtime)
242 {
243         m_pos_animation_time_counter += dtime;
244         m_pos_animation_counter += dtime;
245         v3f movevector = m_pos - m_oldpos;
246         f32 moveratio;
247         if(m_pos_animation_time < 0.001)
248                 moveratio = 1.0;
249         else
250                 moveratio = m_pos_animation_counter / m_pos_animation_time;
251         if(moveratio > 1.5)
252                 moveratio = 1.5;
253         m_showpos = m_oldpos + movevector * moveratio;
254 }
255
256 #ifndef SERVER
257 /*
258         RatObject
259 */
260 void RatObject::addToScene(scene::ISceneManager *smgr)
261 {
262         if(m_node != NULL)
263                 return;
264         
265         video::IVideoDriver* driver = smgr->getVideoDriver();
266         
267         scene::SMesh *mesh = new scene::SMesh();
268         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
269         video::SColor c(255,255,255,255);
270         video::S3DVertex vertices[4] =
271         {
272                 video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
273                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
274                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
275                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
276         };
277         u16 indices[] = {0,1,2,2,3,0};
278         buf->append(vertices, 4, indices, 6);
279         // Set material
280         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
281         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
282         buf->getMaterial().setTexture
283                         (0, driver->getTexture("../data/rat.png"));
284         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
285         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
286         // Add to mesh
287         mesh->addMeshBuffer(buf);
288         buf->drop();
289         m_node = smgr->addMeshSceneNode(mesh, NULL);
290         mesh->drop();
291         updateNodePos();
292 }
293 #endif
294
295 /*
296         MapBlockObjectList
297 */
298
299 MapBlockObjectList::MapBlockObjectList(MapBlock *block):
300         m_block(block)
301 {
302         m_mutex.Init();
303 }
304
305 MapBlockObjectList::~MapBlockObjectList()
306 {
307         clear();
308 }
309
310 /*
311         The serialization format:
312         [0] u16 number of entries
313         [2] entries (id, typeId, parameters)
314 */
315
316 void MapBlockObjectList::serialize(std::ostream &os, u8 version)
317 {
318         JMutexAutoLock lock(m_mutex);
319
320         u8 buf[2];
321         writeU16(buf, m_objects.size());
322         os.write((char*)buf, 2);
323
324         for(core::map<s16, MapBlockObject*>::Iterator
325                         i = m_objects.getIterator();
326                         i.atEnd() == false; i++)
327         {
328                 i.getNode()->getValue()->serialize(os, version);
329         }
330 }
331
332 void MapBlockObjectList::update(std::istream &is, u8 version,
333                 scene::ISceneManager *smgr, u32 daynight_ratio)
334 {
335         JMutexAutoLock lock(m_mutex);
336
337         /*
338                 Collect all existing ids to a set.
339
340                 As things are updated, they are removed from this.
341
342                 All remaining ones are deleted.
343         */
344         core::map<s16, bool> ids_to_delete;
345         for(core::map<s16, MapBlockObject*>::Iterator
346                         i = m_objects.getIterator();
347                         i.atEnd() == false; i++)
348         {
349                 ids_to_delete.insert(i.getNode()->getKey(), true);
350         }
351         
352         u8 buf[6];
353         
354         is.read((char*)buf, 2);
355         u16 count = readU16(buf);
356
357         for(u16 i=0; i<count; i++)
358         {
359                 // Read id
360                 is.read((char*)buf, 2);
361                 s16 id = readS16(buf);
362                 
363                 // Read position
364                 // stored as x1000/BS v3s16
365                 is.read((char*)buf, 6);
366                 v3s16 pos_i = readV3S16(buf);
367                 v3f pos((f32)pos_i.X/1000*BS,
368                                 (f32)pos_i.Y/1000*BS,
369                                 (f32)pos_i.Z/1000*BS);
370
371                 // Read typeId
372                 is.read((char*)buf, 2);
373                 u16 type_id = readU16(buf);
374                 
375                 bool create_new = false;
376
377                 // Find an object with the id
378                 core::map<s16, MapBlockObject*>::Node *n;
379                 n = m_objects.find(id);
380                 // If no entry is found for id
381                 if(n == NULL)
382                 {
383                         // Insert dummy pointer node
384                         m_objects.insert(id, NULL);
385                         // Get node
386                         n = m_objects.find(id);
387                         // A new object will be created at this node
388                         create_new = true;
389                 }
390                 // If type_id differs
391                 else if(n->getValue()->getTypeId() != type_id)
392                 {
393                         // Delete old object
394                         delete n->getValue();
395                         // A new object will be created at this node
396                         create_new = true;
397                 }
398
399                 MapBlockObject *obj = NULL;
400
401                 if(create_new)
402                 {
403                         /*dstream<<"MapBlockObjectList adding new object"
404                                         " id="<<id
405                                         <<std::endl;*/
406
407                         if(type_id == MAPBLOCKOBJECT_TYPE_SIGN)
408                         {
409                                 obj = new SignObject(m_block, id, pos);
410                         }
411                         else if(type_id == MAPBLOCKOBJECT_TYPE_RAT)
412                         {
413                                 obj = new RatObject(m_block, id, pos);
414                         }
415                         else
416                         {
417                                 // This is fatal because we cannot know the length
418                                 // of the object's data
419                                 throw SerializationError
420                                 ("MapBlockObjectList::update(): Unknown MapBlockObject type");
421                         }
422
423                         if(smgr != NULL)
424                                 //obj->addToScene(smgr, daynight_ratio);
425                                 obj->addToScene(smgr);
426
427                         n->setValue(obj);
428                 }
429                 else
430                 {
431                         obj = n->getValue();
432                         obj->updatePos(pos);
433                         /*if(daynight_ratio != m_last_update_daynight_ratio)
434                         {
435                                 obj->removeFromScene();
436                                 obj->addToScene(smgr, daynight_ratio);
437                         }*/
438                 }
439
440                 // Now there is an object in obj.
441                 // Update it.
442                 
443                 obj->update(is, version);
444                 
445                 /*
446                         Update light on client
447                 */
448                 if(smgr != NULL)
449                 {
450                         u8 light = LIGHT_MAX;
451                         try{
452                                 v3s16 relpos_i = floatToInt(obj->m_pos);
453                                 MapNode n = m_block->getNodeParent(relpos_i);
454                                 light = n.getLightBlend(daynight_ratio);
455                         }
456                         catch(InvalidPositionException &e) {}
457                         obj->updateLight(light);
458                 }
459                 
460                 // Remove from deletion list
461                 if(ids_to_delete.find(id) != NULL)
462                         ids_to_delete.remove(id);
463         }
464
465         // Delete all objects whose ids_to_delete remain in ids_to_delete
466         for(core::map<s16, bool>::Iterator
467                         i = ids_to_delete.getIterator();
468                         i.atEnd() == false; i++)
469         {
470                 s16 id = i.getNode()->getKey();
471
472                 /*dstream<<"MapBlockObjectList deleting object"
473                                 " id="<<id
474                                 <<std::endl;*/
475
476                 MapBlockObject *obj = m_objects[id];
477                 obj->removeFromScene();
478                 delete obj;
479                 m_objects.remove(id);
480         }
481
482         m_last_update_daynight_ratio = daynight_ratio;
483 }
484
485 s16 MapBlockObjectList::getFreeId() throw(ContainerFullException)
486 {
487         s16 id = 0;
488         for(;;)
489         {
490                 if(m_objects.find(id) == NULL)
491                         return id;
492                 if(id == 32767)
493                         throw ContainerFullException
494                                         ("MapBlockObjectList doesn't fit more objects");
495                 id++;
496         }
497 }
498
499 void MapBlockObjectList::add(MapBlockObject *object)
500                 throw(ContainerFullException, AlreadyExistsException)
501 {
502         if(object == NULL)
503         {
504                 dstream<<"MapBlockObjectList::add(): NULL object"<<std::endl;
505                 return;
506         }
507
508         JMutexAutoLock lock(m_mutex);
509
510         // Create unique id if id==-1
511         if(object->m_id == -1)
512         {
513                 object->m_id = getFreeId();
514         }
515
516         if(m_objects.find(object->m_id) != NULL)
517         {
518                 dstream<<"MapBlockObjectList::add(): "
519                                 "object with same id already exists"<<std::endl;
520                 throw AlreadyExistsException
521                                 ("MapBlockObjectList already has given id");
522         }
523         
524         object->m_block = m_block;
525         
526         /*v3f p = object->m_pos;
527         dstream<<"MapBlockObjectList::add(): "
528                         <<"m_block->getPos()=("
529                         <<m_block->getPos().X<<","
530                         <<m_block->getPos().Y<<","
531                         <<m_block->getPos().Z<<")"
532                         <<" inserting object with id="<<object->m_id
533                         <<" pos="
534                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
535                         <<std::endl;*/
536         
537         m_objects.insert(object->m_id, object);
538 }
539
540 void MapBlockObjectList::clear()
541 {
542         JMutexAutoLock lock(m_mutex);
543
544         for(core::map<s16, MapBlockObject*>::Iterator
545                         i = m_objects.getIterator();
546                         i.atEnd() == false; i++)
547         {
548                 MapBlockObject *obj = i.getNode()->getValue();
549                 //FIXME: This really shouldn't be NULL at any time,
550                 //       but this condition was added because it was.
551                 if(obj != NULL)
552                 {
553                         obj->removeFromScene();
554                         delete obj;
555                 }
556         }
557
558         m_objects.clear();
559 }
560
561 void MapBlockObjectList::remove(s16 id)
562 {
563         JMutexAutoLock lock(m_mutex);
564
565         core::map<s16, MapBlockObject*>::Node *n;
566         n = m_objects.find(id);
567         if(n == NULL)
568                 return;
569         
570         n->getValue()->removeFromScene();
571         delete n->getValue();
572         m_objects.remove(id);
573 }
574
575 MapBlockObject * MapBlockObjectList::get(s16 id)
576 {
577         core::map<s16, MapBlockObject*>::Node *n;
578         n = m_objects.find(id);
579         if(n == NULL)
580                 return NULL;
581         else
582                 return n->getValue();
583 }
584
585 void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
586 {
587         DSTACK(__FUNCTION_NAME);
588         
589         JMutexAutoLock lock(m_mutex);
590         
591         core::map<s16, bool> ids_to_delete;
592
593         {
594                 DSTACK("%s: stepping objects", __FUNCTION_NAME);
595
596                 for(core::map<s16, MapBlockObject*>::Iterator
597                                 i = m_objects.getIterator();
598                                 i.atEnd() == false; i++)
599                 {
600                         MapBlockObject *obj = i.getNode()->getValue();
601                         
602                         DSTACK("%s: stepping object type %i", __FUNCTION_NAME,
603                                         obj->getTypeId());
604
605                         if(server)
606                         {
607                                 // Update light
608                                 u8 light = LIGHT_MAX;
609                                 try{
610                                         v3s16 relpos_i = floatToInt(obj->m_pos);
611                                         MapNode n = m_block->getNodeParent(relpos_i);
612                                         light = n.getLightBlend(daynight_ratio);
613                                 }
614                                 catch(InvalidPositionException &e) {}
615                                 obj->updateLight(light);
616                                 
617                                 bool to_delete = obj->serverStep(dtime, daynight_ratio);
618
619                                 if(to_delete)
620                                         ids_to_delete.insert(obj->m_id, true);
621                         }
622                         else
623                         {
624                                 obj->clientStep(dtime);
625                         }
626                 }
627         }
628
629         {
630                 DSTACK("%s: deleting objects", __FUNCTION_NAME);
631
632                 // Delete objects in delete queue
633                 for(core::map<s16, bool>::Iterator
634                                 i = ids_to_delete.getIterator();
635                                 i.atEnd() == false; i++)
636                 {
637                         s16 id = i.getNode()->getKey();
638
639                         MapBlockObject *obj = m_objects[id];
640                         obj->removeFromScene();
641                         delete obj;
642                         m_objects.remove(id);
643                 }
644         }
645         
646         /*
647                 Wrap objects on server
648         */
649
650         if(server == false)
651                 return;
652         
653         {
654                 DSTACK("%s: object wrap loop", __FUNCTION_NAME);
655
656                 for(core::map<s16, MapBlockObject*>::Iterator
657                                 i = m_objects.getIterator();
658                                 i.atEnd() == false; i++)
659                 {
660                         MapBlockObject *obj = i.getNode()->getValue();
661
662                         v3s16 pos_i = floatToInt(obj->m_pos);
663
664                         if(m_block->isValidPosition(pos_i))
665                         {
666                                 // No wrap
667                                 continue;
668                         }
669
670                         bool impossible = wrapObject(obj);
671
672                         if(impossible)
673                         {
674                                 // No wrap
675                                 continue;
676                         }
677
678                         // Restart find
679                         i = m_objects.getIterator();
680                 }
681         }
682 }
683
684 bool MapBlockObjectList::wrapObject(MapBlockObject *object)
685 {
686         DSTACK(__FUNCTION_NAME);
687         
688         // No lock here; this is called so that the lock is already locked.
689         //JMutexAutoLock lock(m_mutex);
690
691         assert(object->m_block == m_block);
692         assert(m_objects.find(object->m_id) != NULL);
693         assert(m_objects[object->m_id] == object);
694
695         NodeContainer *parentcontainer = m_block->getParent();
696         // This will only work if the parent is the map
697         if(parentcontainer->nodeContainerId() != NODECONTAINER_ID_MAP)
698         {
699                 dstream<<"WARNING: Wrapping object not possible: "
700                                 "MapBlock's parent is not map"<<std::endl;
701                 return true;
702         }
703         // OK, we have the map!
704         Map *map = (Map*)parentcontainer;
705         
706         // Calculate blockpos on map
707         v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
708         v3f pos_f_on_oldblock = object->m_pos;
709         v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock);
710         v3s16 pos_i_on_map = pos_i_on_oldblock + oldblock_pos_i_on_map;
711         v3s16 pos_blocks_on_map = getNodeBlockPos(pos_i_on_map);
712
713         // Get new block
714         MapBlock *newblock;
715         try{
716                 newblock = map->getBlockNoCreate(pos_blocks_on_map);
717         }
718         catch(InvalidPositionException &e)
719         {
720                 // Couldn't find block -> not wrapping
721                 /*dstream<<"WARNING: Wrapping object not possible: "
722                                 <<"could not find new block"
723                                 <<"("<<pos_blocks_on_map.X
724                                 <<","<<pos_blocks_on_map.Y
725                                 <<","<<pos_blocks_on_map.Z
726                                 <<")"<<std::endl;*/
727                 /*dstream<<"pos_f_on_oldblock=("
728                                 <<pos_f_on_oldblock.X<<","
729                                 <<pos_f_on_oldblock.Y<<","
730                                 <<pos_f_on_oldblock.Z<<")"
731                                 <<std::endl;*/
732                 return true;
733         }
734
735         if(newblock == m_block)
736         {
737                 dstream<<"WARNING: Wrapping object not possible: "
738                                 "newblock == oldblock"<<std::endl;
739                 return true;
740         }
741         
742         // Calculate position on new block
743         v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map);
744         v3s16 newblock_pos_i_on_map = newblock->getPosRelative();
745         v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map);
746         v3f pos_f_on_newblock = pos_f_on_oldblock
747                         - newblock_pos_f_on_map + oldblock_pos_f_on_map;
748
749         // Remove object from this block
750         m_objects.remove(object->m_id);
751         
752         // Add object to new block
753         object->m_pos = pos_f_on_newblock;
754         object->m_id = -1;
755         object->m_block = NULL;
756         newblock->addObject(object);
757
758         //dstream<<"NOTE: Wrapped object"<<std::endl;
759
760         return false;
761 }
762
763 void MapBlockObjectList::getObjects(v3f origin, f32 max_d,
764                 core::array<DistanceSortedObject> &dest)
765 {
766         for(core::map<s16, MapBlockObject*>::Iterator
767                         i = m_objects.getIterator();
768                         i.atEnd() == false; i++)
769         {
770                 MapBlockObject *obj = i.getNode()->getValue();
771
772                 f32 d = (obj->getRelativeShowPos() - origin).getLength();
773
774                 if(d > max_d)
775                         continue;
776
777                 DistanceSortedObject dso(obj, d);
778
779                 dest.push_back(dso);
780         }
781 }
782
783 //END