2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
5 #include "mapblockobject.h"
7 // Only for ::getNodeBox, TODO: Get rid of this
14 // This is here because it uses the MapBlock
15 v3f MapBlockObject::getAbsolutePos()
20 // getPosRelative gets nodepos relative to map origin
21 v3f blockpos = intToFloat(m_block->getPosRelative());
22 return blockpos + m_pos;
25 void MapBlockObject::setBlockChanged()
28 m_block->setChangedFlag();
34 void MovingObject::move(float dtime, v3f acceleration)
36 //m_pos += dtime * 3.0;
38 v3s16 oldpos_i = floatToInt(m_pos);
40 if(m_block->isValidPosition(oldpos_i) == false)
42 // Should have wrapped, cancelling further movement.
46 // No collisions if there is no collision box
47 if(m_collision_box == NULL)
49 m_speed += dtime * acceleration;
50 m_pos += m_speed * dtime;
55 v3f oldpos = position;
57 /*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
58 <<oldpos_i.Z<<")"<<std::endl;*/
60 // Maximum time increment (for collision detection etc)
61 // Allow 0.1 blocks per increment
62 // time = distance / speed
63 // NOTE: In the loop below collisions are detected at 0.15*BS radius
64 float speedlength = m_speed.getLength();
65 f32 dtime_max_increment;
66 if(fabs(speedlength) > 0.001)
67 dtime_max_increment = 0.1*BS / speedlength;
69 dtime_max_increment = 0.5;
71 m_touching_ground = false;
79 if(dtime > dtime_max_increment)
80 dtime_part = dtime_max_increment;
85 // Begin of dtime limited code
87 m_speed += acceleration * dtime_part;
88 position += m_speed * dtime_part;
94 v3s16 pos_i = floatToInt(position);
96 // The loop length is limited to the object moving a distance
97 f32 d = (float)BS * 0.15;
99 core::aabbox3d<f32> objectbox(
100 m_collision_box->MinEdge + position,
101 m_collision_box->MaxEdge + position
104 core::aabbox3d<f32> objectbox_old(
105 m_collision_box->MinEdge + oldpos,
106 m_collision_box->MaxEdge + oldpos
109 //TODO: Get these ranges from somewhere
110 for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
111 for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
112 for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
115 if(m_block->getNodeParent(v3s16(x,y,z)).d == MATERIAL_AIR){
119 catch(InvalidPositionException &e)
121 // Doing nothing here will block the player from
122 // walking over map borders
125 core::aabbox3d<f32> nodebox = Map::getNodeBox(
128 // See if the player is touching ground
130 fabs(nodebox.MaxEdge.Y-objectbox.MinEdge.Y) < d
131 && nodebox.MaxEdge.X-d > objectbox.MinEdge.X
132 && nodebox.MinEdge.X+d < objectbox.MaxEdge.X
133 && nodebox.MaxEdge.Z-d > objectbox.MinEdge.Z
134 && nodebox.MinEdge.Z+d < objectbox.MaxEdge.Z
136 m_touching_ground = true;
139 if(objectbox.intersectsWithBox(nodebox))
147 for(u16 i=0; i<3; i++)
149 f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
150 f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
151 f32 playermax = objectbox.MaxEdge.dotProduct(dirs[i]);
152 f32 playermin = objectbox.MinEdge.dotProduct(dirs[i]);
153 f32 playermax_old = objectbox_old.MaxEdge.dotProduct(dirs[i]);
154 f32 playermin_old = objectbox_old.MinEdge.dotProduct(dirs[i]);
156 bool main_edge_collides =
157 ((nodemax > playermin && nodemax <= playermin_old + d
158 && m_speed.dotProduct(dirs[i]) < 0)
160 (nodemin < playermax && nodemin >= playermax_old - d
161 && m_speed.dotProduct(dirs[i]) > 0));
163 bool other_edges_collide = true;
164 for(u16 j=0; j<3; j++)
168 f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
169 f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
170 f32 playermax = objectbox.MaxEdge.dotProduct(dirs[j]);
171 f32 playermin = objectbox.MinEdge.dotProduct(dirs[j]);
172 if(!(nodemax - d > playermin && nodemin + d < playermax))
174 other_edges_collide = false;
179 if(main_edge_collides && other_edges_collide)
181 m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
182 position -= position.dotProduct(dirs[i]) * dirs[i];
183 position += oldpos.dotProduct(dirs[i]) * dirs[i];
188 } // if(objectbox.intersectsWithBox(nodebox))
191 } // End of dtime limited loop
192 while(dtime > 0.001);
201 MapBlockObjectList::MapBlockObjectList(MapBlock *block):
207 MapBlockObjectList::~MapBlockObjectList()
213 The serialization format:
214 [0] u16 number of entries
215 [2] entries (id, typeId, parameters)
218 void MapBlockObjectList::serialize(std::ostream &os, u8 version)
220 JMutexAutoLock lock(m_mutex);
223 writeU16(buf, m_objects.size());
224 os.write((char*)buf, 2);
226 for(core::map<s16, MapBlockObject*>::Iterator
227 i = m_objects.getIterator();
228 i.atEnd() == false; i++)
230 i.getNode()->getValue()->serialize(os, version);
234 void MapBlockObjectList::update(std::istream &is, u8 version,
235 scene::ISceneManager *smgr)
237 JMutexAutoLock lock(m_mutex);
240 Collect all existing ids to a set.
242 As things are updated, they are removed from this.
244 All remaining ones are deleted.
246 core::map<s16, bool> ids_to_delete;
247 for(core::map<s16, MapBlockObject*>::Iterator
248 i = m_objects.getIterator();
249 i.atEnd() == false; i++)
251 ids_to_delete.insert(i.getNode()->getKey(), true);
256 is.read((char*)buf, 2);
257 u16 count = readU16(buf);
259 for(u16 i=0; i<count; i++)
262 is.read((char*)buf, 2);
263 s16 id = readS16(buf);
266 // stored as x1000/BS v3s16
267 is.read((char*)buf, 6);
268 v3s16 pos_i = readV3S16(buf);
269 v3f pos((f32)pos_i.X/1000*BS,
270 (f32)pos_i.Y/1000*BS,
271 (f32)pos_i.Z/1000*BS);
274 is.read((char*)buf, 2);
275 u16 type_id = readU16(buf);
277 bool create_new = false;
279 // Find an object with the id
280 core::map<s16, MapBlockObject*>::Node *n;
281 n = m_objects.find(id);
282 // If no entry is found for id
285 // Insert dummy pointer node
286 m_objects.insert(id, NULL);
288 n = m_objects.find(id);
289 // A new object will be created at this node
292 // If type_id differs
293 else if(n->getValue()->getTypeId() != type_id)
296 delete n->getValue();
297 // A new object will be created at this node
301 MapBlockObject *obj = NULL;
305 /*dstream<<"MapBlockObjectList adding new object"
309 if(type_id == MAPBLOCKOBJECT_TYPE_TEST)
311 // The constructors of objects shouldn't need
312 // any more parameters than this.
313 obj = new TestObject(m_block, id, pos);
315 else if(type_id == MAPBLOCKOBJECT_TYPE_TEST2)
317 obj = new Test2Object(m_block, id, pos);
319 else if(type_id == MAPBLOCKOBJECT_TYPE_SIGN)
321 obj = new SignObject(m_block, id, pos);
323 else if(type_id == MAPBLOCKOBJECT_TYPE_RAT)
325 obj = new RatObject(m_block, id, pos);
329 throw SerializationError
330 ("MapBlockObjectList::update(): Unknown MapBlockObject type");
334 obj->addToScene(smgr);
344 // Now there is an object in obj.
347 obj->update(is, version);
349 // Remove from deletion list
350 if(ids_to_delete.find(id) != NULL)
351 ids_to_delete.remove(id);
354 // Delete all objects whose ids_to_delete remain in ids_to_delete
355 for(core::map<s16, bool>::Iterator
356 i = ids_to_delete.getIterator();
357 i.atEnd() == false; i++)
359 s16 id = i.getNode()->getKey();
361 /*dstream<<"MapBlockObjectList deleting object"
365 MapBlockObject *obj = m_objects[id];
366 obj->removeFromScene();
368 m_objects.remove(id);
372 s16 MapBlockObjectList::getFreeId() throw(ContainerFullException)
377 if(m_objects.find(id) == NULL)
380 throw ContainerFullException
381 ("MapBlockObjectList doesn't fit more objects");
386 void MapBlockObjectList::add(MapBlockObject *object)
387 throw(ContainerFullException, AlreadyExistsException)
391 dstream<<"MapBlockObjectList::add(): NULL object"<<std::endl;
395 JMutexAutoLock lock(m_mutex);
397 // Create unique id if id==-1
398 if(object->m_id == -1)
400 object->m_id = getFreeId();
403 if(m_objects.find(object->m_id) != NULL)
405 dstream<<"MapBlockObjectList::add(): "
406 "object with same id already exists"<<std::endl;
407 throw AlreadyExistsException
408 ("MapBlockObjectList already has given id");
411 object->m_block = m_block;
413 /*v3f p = object->m_pos;
414 dstream<<"MapBlockObjectList::add(): "
415 <<"m_block->getPos()=("
416 <<m_block->getPos().X<<","
417 <<m_block->getPos().Y<<","
418 <<m_block->getPos().Z<<")"
419 <<" inserting object with id="<<object->m_id
421 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
424 m_objects.insert(object->m_id, object);
427 void MapBlockObjectList::clear()
429 JMutexAutoLock lock(m_mutex);
431 for(core::map<s16, MapBlockObject*>::Iterator
432 i = m_objects.getIterator();
433 i.atEnd() == false; i++)
435 MapBlockObject *obj = i.getNode()->getValue();
436 //FIXME: This really shouldn't be NULL at any time,
437 // but this condition was added because it was.
440 obj->removeFromScene();
448 void MapBlockObjectList::remove(s16 id)
450 JMutexAutoLock lock(m_mutex);
452 core::map<s16, MapBlockObject*>::Node *n;
453 n = m_objects.find(id);
457 n->getValue()->removeFromScene();
458 delete n->getValue();
459 m_objects.remove(id);
462 MapBlockObject * MapBlockObjectList::get(s16 id)
464 core::map<s16, MapBlockObject*>::Node *n;
465 n = m_objects.find(id);
469 return n->getValue();
472 void MapBlockObjectList::step(float dtime, bool server)
474 JMutexAutoLock lock(m_mutex);
476 core::map<s16, bool> ids_to_delete;
478 for(core::map<s16, MapBlockObject*>::Iterator
479 i = m_objects.getIterator();
480 i.atEnd() == false; i++)
482 MapBlockObject *obj = i.getNode()->getValue();
486 bool to_delete = obj->serverStep(dtime);
489 ids_to_delete.insert(obj->m_id, true);
493 obj->clientStep(dtime);
497 // Delete objects in delete queue
498 for(core::map<s16, bool>::Iterator
499 i = ids_to_delete.getIterator();
500 i.atEnd() == false; i++)
502 s16 id = i.getNode()->getKey();
504 MapBlockObject *obj = m_objects[id];
505 obj->removeFromScene();
507 m_objects.remove(id);
511 Wrap objects on server
517 for(core::map<s16, MapBlockObject*>::Iterator
518 i = m_objects.getIterator();
519 i.atEnd() == false; i++)
521 MapBlockObject *obj = i.getNode()->getValue();
523 v3s16 pos_i = floatToInt(obj->m_pos);
525 if(m_block->isValidPosition(pos_i))
531 bool impossible = wrapObject(obj);
540 i = m_objects.getIterator();
544 bool MapBlockObjectList::wrapObject(MapBlockObject *object)
546 // No lock here; this is called so that the lock is already locked.
547 //JMutexAutoLock lock(m_mutex);
549 assert(object->m_block == m_block);
550 assert(m_objects.find(object->m_id) != NULL);
551 assert(m_objects[object->m_id] == object);
553 NodeContainer *parentcontainer = m_block->getParent();
554 // This will only work if the parent is the map
555 if(parentcontainer->nodeContainerId() != NODECONTAINER_ID_MAP)
557 dstream<<"WARNING: Wrapping object not possible: "
558 "MapBlock's parent is not map"<<std::endl;
561 // OK, we have the map!
562 Map *map = (Map*)parentcontainer;
564 // Calculate blockpos on map
565 v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
566 v3f pos_f_on_oldblock = object->m_pos;
567 v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock);
568 v3s16 pos_i_on_map = pos_i_on_oldblock + oldblock_pos_i_on_map;
569 v3s16 pos_blocks_on_map = getNodeBlockPos(pos_i_on_map);
574 newblock = map->getBlockNoCreate(pos_blocks_on_map);
576 catch(InvalidPositionException &e)
578 // Couldn't find block -> not wrapping
579 /*dstream<<"WARNING: Wrapping object not possible: "
580 <<"could not find new block"
581 <<"("<<pos_blocks_on_map.X
582 <<","<<pos_blocks_on_map.Y
583 <<","<<pos_blocks_on_map.Z
585 /*dstream<<"pos_f_on_oldblock=("
586 <<pos_f_on_oldblock.X<<","
587 <<pos_f_on_oldblock.Y<<","
588 <<pos_f_on_oldblock.Z<<")"
593 if(newblock == m_block)
595 dstream<<"WARNING: Wrapping object not possible: "
596 "newblock == oldblock"<<std::endl;
600 // Calculate position on new block
601 v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map);
602 v3s16 newblock_pos_i_on_map = newblock->getPosRelative();
603 v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map);
604 v3f pos_f_on_newblock = pos_f_on_oldblock
605 - newblock_pos_f_on_map + oldblock_pos_f_on_map;
607 // Remove object from this block
608 m_objects.remove(object->m_id);
610 // Add object to new block
611 object->m_pos = pos_f_on_newblock;
613 object->m_block = NULL;
614 newblock->addObject(object);
616 //dstream<<"NOTE: Wrapped object"<<std::endl;
621 void MapBlockObjectList::getObjects(v3f origin, f32 max_d,
622 core::array<DistanceSortedObject> &dest)
624 for(core::map<s16, MapBlockObject*>::Iterator
625 i = m_objects.getIterator();
626 i.atEnd() == false; i++)
628 MapBlockObject *obj = i.getNode()->getValue();
630 f32 d = (obj->m_pos - origin).getLength();
635 DistanceSortedObject dso(obj, d);