3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "mapblockobject.h"
22 // Only for ::getNodeBox, TODO: Get rid of this
29 // This is here because it uses the MapBlock
30 v3f MapBlockObject::getAbsolutePos()
35 // getPosRelative gets nodepos relative to map origin
36 v3f blockpos = intToFloat(m_block->getPosRelative());
37 return blockpos + m_pos;
40 void MapBlockObject::setBlockChanged()
43 m_block->setChangedFlag();
50 v3f MovingObject::getAbsoluteShowPos()
55 // getPosRelative gets nodepos relative to map origin
56 v3f blockpos = intToFloat(m_block->getPosRelative());
57 return blockpos + m_showpos;
60 void MovingObject::move(float dtime, v3f acceleration)
62 DSTACK("%s: typeid=%i, pos=(%f,%f,%f), speed=(%f,%f,%f)"
63 ", dtime=%f, acc=(%f,%f,%f)",
66 m_pos.X, m_pos.Y, m_pos.Z,
67 m_speed.X, m_speed.Y, m_speed.Z,
69 acceleration.X, acceleration.Y, acceleration.Z
72 v3s16 oldpos_i = floatToInt(m_pos);
74 if(m_block->isValidPosition(oldpos_i) == false)
76 // Should have wrapped, cancelling further movement.
80 // No collisions if there is no collision box
81 if(m_collision_box == NULL)
83 m_speed += dtime * acceleration;
84 m_pos += m_speed * dtime;
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)
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());
99 v3f oldpos = position;
101 /*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
102 <<oldpos_i.Z<<")"<<std::endl;*/
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;
113 dtime_max_increment = 0.5;
115 m_touching_ground = false;
123 if(dtime > dtime_max_increment)
124 dtime_part = dtime_max_increment;
129 // Begin of dtime limited code
131 m_speed += acceleration * dtime_part;
132 position += m_speed * dtime_part;
138 v3s16 pos_i = floatToInt(position);
140 // The loop length is limited to the object moving a distance
141 f32 d = (float)BS * 0.15;
143 core::aabbox3d<f32> objectbox(
144 m_collision_box->MinEdge + position,
145 m_collision_box->MaxEdge + position
148 core::aabbox3d<f32> objectbox_old(
149 m_collision_box->MinEdge + oldpos,
150 m_collision_box->MaxEdge + oldpos
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++)
159 if(content_walkable(m_block->getNodeParent(v3s16(x,y,z)).d)
163 catch(InvalidPositionException &e)
165 // Doing nothing here will block the object from
166 // walking over map borders
169 core::aabbox3d<f32> nodebox = Map::getNodeBox(
172 // See if the object is touching ground
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
180 m_touching_ground = true;
183 if(objectbox.intersectsWithBox(nodebox))
191 for(u16 i=0; i<3; i++)
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]);
200 bool main_edge_collides =
201 ((nodemax > playermin && nodemax <= playermin_old + d
202 && m_speed.dotProduct(dirs[i]) < 0)
204 (nodemin < playermax && nodemin >= playermax_old - d
205 && m_speed.dotProduct(dirs[i]) > 0));
207 bool other_edges_collide = true;
208 for(u16 j=0; j<3; j++)
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))
218 other_edges_collide = false;
223 if(main_edge_collides && other_edges_collide)
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];
232 } // if(objectbox.intersectsWithBox(nodebox))
235 } // End of dtime limited loop
236 while(dtime > 0.001);
241 void MovingObject::simpleMove(float dtime)
243 m_pos_animation_time_counter += dtime;
244 m_pos_animation_counter += dtime;
245 v3f movevector = m_pos - m_oldpos;
247 if(m_pos_animation_time < 0.001)
250 moveratio = m_pos_animation_counter / m_pos_animation_time;
253 m_showpos = m_oldpos + movevector * moveratio;
260 void RatObject::addToScene(scene::ISceneManager *smgr)
265 video::IVideoDriver* driver = smgr->getVideoDriver();
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] =
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),
277 u16 indices[] = {0,1,2,2,3,0};
278 buf->append(vertices, 4, indices, 6);
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().setFlag(video::EMF_FOG_ENABLE, true);
286 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
288 mesh->addMeshBuffer(buf);
290 m_node = smgr->addMeshSceneNode(mesh, NULL);
300 void PlayerObject::addToScene(scene::ISceneManager *smgr)
305 video::IVideoDriver* driver = smgr->getVideoDriver();
307 // Attach a simple mesh to the player for showing an image
308 scene::SMesh *mesh = new scene::SMesh();
310 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
311 video::SColor c(255,255,255,255);
312 video::S3DVertex vertices[4] =
314 video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
315 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
316 video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
317 video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
319 u16 indices[] = {0,1,2,2,3,0};
320 buf->append(vertices, 4, indices, 6);
322 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
323 //buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
324 buf->getMaterial().setTexture(0, driver->getTexture("../data/player.png"));
325 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
326 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
327 //buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
328 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
330 mesh->addMeshBuffer(buf);
334 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
335 video::SColor c(255,255,255,255);
336 video::S3DVertex vertices[4] =
338 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
339 video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
340 video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
341 video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
343 u16 indices[] = {0,1,2,2,3,0};
344 buf->append(vertices, 4, indices, 6);
346 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
347 //buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
348 buf->getMaterial().setTexture(0, driver->getTexture("../data/player_back.png"));
349 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
350 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
351 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
353 mesh->addMeshBuffer(buf);
357 m_node = smgr->addMeshSceneNode(mesh, NULL);
367 MapBlockObjectList::MapBlockObjectList(MapBlock *block):
373 MapBlockObjectList::~MapBlockObjectList()
379 The serialization format:
380 [0] u16 number of entries
381 [2] entries (id, typeId, parameters)
384 void MapBlockObjectList::serialize(std::ostream &os, u8 version)
386 JMutexAutoLock lock(m_mutex);
389 writeU16(buf, m_objects.size());
390 os.write((char*)buf, 2);
392 for(core::map<s16, MapBlockObject*>::Iterator
393 i = m_objects.getIterator();
394 i.atEnd() == false; i++)
396 i.getNode()->getValue()->serialize(os, version);
400 void MapBlockObjectList::update(std::istream &is, u8 version,
401 scene::ISceneManager *smgr, u32 daynight_ratio)
403 JMutexAutoLock lock(m_mutex);
406 Collect all existing ids to a set.
408 As things are updated, they are removed from this.
410 All remaining ones are deleted.
412 core::map<s16, bool> ids_to_delete;
413 for(core::map<s16, MapBlockObject*>::Iterator
414 i = m_objects.getIterator();
415 i.atEnd() == false; i++)
417 ids_to_delete.insert(i.getNode()->getKey(), true);
422 is.read((char*)buf, 2);
423 u16 count = readU16(buf);
425 for(u16 i=0; i<count; i++)
428 is.read((char*)buf, 2);
429 s16 id = readS16(buf);
432 // stored as x1000/BS v3s16
433 is.read((char*)buf, 6);
434 v3s16 pos_i = readV3S16(buf);
435 v3f pos((f32)pos_i.X/1000*BS,
436 (f32)pos_i.Y/1000*BS,
437 (f32)pos_i.Z/1000*BS);
440 is.read((char*)buf, 2);
441 u16 type_id = readU16(buf);
443 bool create_new = false;
445 // Find an object with the id
446 core::map<s16, MapBlockObject*>::Node *n;
447 n = m_objects.find(id);
448 // If no entry is found for id
451 // Insert dummy pointer node
452 m_objects.insert(id, NULL);
454 n = m_objects.find(id);
455 // A new object will be created at this node
458 // If type_id differs
459 else if(n->getValue()->getTypeId() != type_id)
462 delete n->getValue();
463 // A new object will be created at this node
467 MapBlockObject *obj = NULL;
471 /*dstream<<"MapBlockObjectList adding new object"
475 if(type_id == MAPBLOCKOBJECT_TYPE_SIGN)
477 obj = new SignObject(m_block, id, pos);
479 else if(type_id == MAPBLOCKOBJECT_TYPE_RAT)
481 obj = new RatObject(m_block, id, pos);
485 // This is fatal because we cannot know the length
486 // of the object's data
487 throw SerializationError
488 ("MapBlockObjectList::update(): Unknown MapBlockObject type");
492 //obj->addToScene(smgr, daynight_ratio);
493 obj->addToScene(smgr);
501 /*if(daynight_ratio != m_last_update_daynight_ratio)
503 obj->removeFromScene();
504 obj->addToScene(smgr, daynight_ratio);
508 // Now there is an object in obj.
511 obj->update(is, version);
514 Update light on client
518 u8 light = LIGHT_MAX;
520 v3s16 relpos_i = floatToInt(obj->m_pos);
521 MapNode n = m_block->getNodeParent(relpos_i);
522 light = n.getLightBlend(daynight_ratio);
524 catch(InvalidPositionException &e) {}
525 obj->updateLight(light);
528 // Remove from deletion list
529 if(ids_to_delete.find(id) != NULL)
530 ids_to_delete.remove(id);
533 // Delete all objects whose ids_to_delete remain in ids_to_delete
534 for(core::map<s16, bool>::Iterator
535 i = ids_to_delete.getIterator();
536 i.atEnd() == false; i++)
538 s16 id = i.getNode()->getKey();
540 /*dstream<<"MapBlockObjectList deleting object"
544 MapBlockObject *obj = m_objects[id];
545 obj->removeFromScene();
547 m_objects.remove(id);
550 m_last_update_daynight_ratio = daynight_ratio;
553 s16 MapBlockObjectList::getFreeId() throw(ContainerFullException)
558 if(m_objects.find(id) == NULL)
561 throw ContainerFullException
562 ("MapBlockObjectList doesn't fit more objects");
567 void MapBlockObjectList::add(MapBlockObject *object)
568 throw(ContainerFullException, AlreadyExistsException)
572 dstream<<"MapBlockObjectList::add(): NULL object"<<std::endl;
576 JMutexAutoLock lock(m_mutex);
578 // Create unique id if id==-1
579 if(object->m_id == -1)
581 object->m_id = getFreeId();
584 if(m_objects.find(object->m_id) != NULL)
586 dstream<<"MapBlockObjectList::add(): "
587 "object with same id already exists"<<std::endl;
588 throw AlreadyExistsException
589 ("MapBlockObjectList already has given id");
592 object->m_block = m_block;
594 /*v3f p = object->m_pos;
595 dstream<<"MapBlockObjectList::add(): "
596 <<"m_block->getPos()=("
597 <<m_block->getPos().X<<","
598 <<m_block->getPos().Y<<","
599 <<m_block->getPos().Z<<")"
600 <<" inserting object with id="<<object->m_id
602 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
605 m_objects.insert(object->m_id, object);
608 void MapBlockObjectList::clear()
610 JMutexAutoLock lock(m_mutex);
612 for(core::map<s16, MapBlockObject*>::Iterator
613 i = m_objects.getIterator();
614 i.atEnd() == false; i++)
616 MapBlockObject *obj = i.getNode()->getValue();
617 //FIXME: This really shouldn't be NULL at any time,
618 // but this condition was added because it was.
621 obj->removeFromScene();
629 void MapBlockObjectList::remove(s16 id)
631 JMutexAutoLock lock(m_mutex);
633 core::map<s16, MapBlockObject*>::Node *n;
634 n = m_objects.find(id);
638 n->getValue()->removeFromScene();
639 delete n->getValue();
640 m_objects.remove(id);
643 MapBlockObject * MapBlockObjectList::get(s16 id)
645 core::map<s16, MapBlockObject*>::Node *n;
646 n = m_objects.find(id);
650 return n->getValue();
653 void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
655 DSTACK(__FUNCTION_NAME);
657 JMutexAutoLock lock(m_mutex);
659 core::map<s16, bool> ids_to_delete;
662 DSTACK("%s: stepping objects", __FUNCTION_NAME);
664 for(core::map<s16, MapBlockObject*>::Iterator
665 i = m_objects.getIterator();
666 i.atEnd() == false; i++)
668 MapBlockObject *obj = i.getNode()->getValue();
670 DSTACK("%s: stepping object type %i", __FUNCTION_NAME,
676 u8 light = LIGHT_MAX;
678 v3s16 relpos_i = floatToInt(obj->m_pos);
679 MapNode n = m_block->getNodeParent(relpos_i);
680 light = n.getLightBlend(daynight_ratio);
682 catch(InvalidPositionException &e) {}
683 obj->updateLight(light);
685 bool to_delete = obj->serverStep(dtime, daynight_ratio);
688 ids_to_delete.insert(obj->m_id, true);
692 obj->clientStep(dtime);
698 DSTACK("%s: deleting objects", __FUNCTION_NAME);
700 // Delete objects in delete queue
701 for(core::map<s16, bool>::Iterator
702 i = ids_to_delete.getIterator();
703 i.atEnd() == false; i++)
705 s16 id = i.getNode()->getKey();
707 MapBlockObject *obj = m_objects[id];
708 obj->removeFromScene();
710 m_objects.remove(id);
715 Wrap objects on server
722 DSTACK("%s: object wrap loop", __FUNCTION_NAME);
724 for(core::map<s16, MapBlockObject*>::Iterator
725 i = m_objects.getIterator();
726 i.atEnd() == false; i++)
728 MapBlockObject *obj = i.getNode()->getValue();
730 v3s16 pos_i = floatToInt(obj->m_pos);
732 if(m_block->isValidPosition(pos_i))
738 bool impossible = wrapObject(obj);
747 i = m_objects.getIterator();
752 bool MapBlockObjectList::wrapObject(MapBlockObject *object)
754 DSTACK(__FUNCTION_NAME);
756 // No lock here; this is called so that the lock is already locked.
757 //JMutexAutoLock lock(m_mutex);
759 assert(object->m_block == m_block);
760 assert(m_objects.find(object->m_id) != NULL);
761 assert(m_objects[object->m_id] == object);
763 NodeContainer *parentcontainer = m_block->getParent();
764 // This will only work if the parent is the map
765 if(parentcontainer->nodeContainerId() != NODECONTAINER_ID_MAP)
767 dstream<<"WARNING: Wrapping object not possible: "
768 "MapBlock's parent is not map"<<std::endl;
771 // OK, we have the map!
772 Map *map = (Map*)parentcontainer;
774 // Calculate blockpos on map
775 v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
776 v3f pos_f_on_oldblock = object->m_pos;
777 v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock);
778 v3s16 pos_i_on_map = pos_i_on_oldblock + oldblock_pos_i_on_map;
779 v3s16 pos_blocks_on_map = getNodeBlockPos(pos_i_on_map);
784 newblock = map->getBlockNoCreate(pos_blocks_on_map);
786 catch(InvalidPositionException &e)
788 // Couldn't find block -> not wrapping
789 /*dstream<<"WARNING: Wrapping object not possible: "
790 <<"could not find new block"
791 <<"("<<pos_blocks_on_map.X
792 <<","<<pos_blocks_on_map.Y
793 <<","<<pos_blocks_on_map.Z
795 /*dstream<<"pos_f_on_oldblock=("
796 <<pos_f_on_oldblock.X<<","
797 <<pos_f_on_oldblock.Y<<","
798 <<pos_f_on_oldblock.Z<<")"
803 if(newblock == m_block)
805 dstream<<"WARNING: Wrapping object not possible: "
806 "newblock == oldblock"<<std::endl;
810 // Calculate position on new block
811 v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map);
812 v3s16 newblock_pos_i_on_map = newblock->getPosRelative();
813 v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map);
814 v3f pos_f_on_newblock = pos_f_on_oldblock
815 - newblock_pos_f_on_map + oldblock_pos_f_on_map;
817 // Remove object from this block
818 m_objects.remove(object->m_id);
820 // Add object to new block
821 object->m_pos = pos_f_on_newblock;
823 object->m_block = NULL;
824 newblock->addObject(object);
826 //dstream<<"NOTE: Wrapped object"<<std::endl;
831 void MapBlockObjectList::getObjects(v3f origin, f32 max_d,
832 core::array<DistanceSortedObject> &dest)
834 for(core::map<s16, MapBlockObject*>::Iterator
835 i = m_objects.getIterator();
836 i.atEnd() == false; i++)
838 MapBlockObject *obj = i.getNode()->getValue();
840 f32 d = (obj->getRelativeShowPos() - origin).getLength();
845 DistanceSortedObject dso(obj, d);