Working version before block send priorization update
[oweals/minetest.git] / src / mapblockobject.h
1 /*
2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
3 */
4
5 #ifndef MAPBLOCKOBJECT_HEADER
6 #define MAPBLOCKOBJECT_HEADER
7
8 #include "common_irrlicht.h"
9 #include <math.h>
10 #include <string>
11 #include "serialization.h"
12 #include "mapnode.h"
13 #include "constants.h"
14
15 enum
16 {
17         MAPBLOCKOBJECT_TYPE_TEST=0,
18         MAPBLOCKOBJECT_TYPE_TEST2=1,
19         MAPBLOCKOBJECT_TYPE_SIGN=2,
20         MAPBLOCKOBJECT_TYPE_RAT=3,
21 };
22
23 class MapBlock;
24
25 class MapBlockObject
26 {
27 public:
28         MapBlockObject(MapBlock *block, s16 id, v3f pos):
29                 m_collision_box(NULL),
30                 m_selection_box(NULL),
31                 m_block(block),
32                 m_id(id),
33                 m_pos(pos)
34         {
35         }
36         virtual ~MapBlockObject()
37         {
38         }
39
40         s16 getId()
41         {
42                 return m_id;
43         }
44         MapBlock* getBlock()
45         {
46                 return m_block;
47         }
48         
49         // Writes id, pos and typeId
50         void serializeBase(std::ostream &os, u8 version)
51         {
52                 u8 buf[6];
53
54                 // id
55                 writeS16(buf, m_id);
56                 os.write((char*)buf, 2);
57                 
58                 // position
59                 // stored as x1000/BS v3s16
60                 v3s16 pos_i(m_pos.X*1000/BS, m_pos.Y*1000/BS, m_pos.Z*1000/BS);
61                 writeV3S16(buf, pos_i);
62                 os.write((char*)buf, 6);
63
64                 // typeId
65                 writeU16(buf, getTypeId());
66                 os.write((char*)buf, 2);
67         }
68         
69         // Get floating point position on map
70         v3f getAbsolutePos();
71
72         void setBlockChanged();
73
74         // Shootline is relative to block
75         bool isSelected(core::line3d<f32> shootline)
76         {
77                 if(m_selection_box == NULL)
78                         return false;
79
80                 core::aabbox3d<f32> offsetted_box(
81                                 m_selection_box->MinEdge + m_pos,
82                                 m_selection_box->MaxEdge + m_pos
83                 );
84
85                 return offsetted_box.intersectsWithLine(shootline);
86         }
87
88         core::aabbox3d<f32> getSelectionBoxOnMap()
89         {
90                 v3f absolute_pos = getAbsolutePos();
91
92                 core::aabbox3d<f32> box(
93                                 m_selection_box->MinEdge + absolute_pos,
94                                 m_selection_box->MaxEdge + absolute_pos
95                 );
96
97                 return box;
98         }
99         
100         /*
101                 Implementation interface
102         */
103
104         virtual u16 getTypeId() const = 0;
105         // Shall call serializeBase and then write the parameters
106         virtual void serialize(std::ostream &os, u8 version) = 0;
107         // Shall read parameters from stream
108         virtual void update(std::istream &is, u8 version) = 0;
109
110         virtual std::string getInventoryString() { return "None"; }
111         
112         // Reimplementation shall call this.
113         virtual void updatePos(v3f pos)
114         {
115                 m_pos = pos;
116         }
117         
118         // Shall move the object around, modify it and possibly delete it.
119         // Typical dtimes are 0.2 and 10000.
120         // A return value of true requests deletion of the object by the caller.
121         // NOTE: Only server calls this.
122         virtual bool serverStep(float dtime) { return false; };
123         // This should do slight animations only or so
124         virtual void clientStep(float dtime) {};
125
126         // NOTE: These functions should do nothing if the asked state is
127         //       same as the current state
128         // Shall add and remove relevant scene nodes for rendering the
129         // object in the game world
130         virtual void addToScene(scene::ISceneManager *smgr) {};
131         // Shall remove stuff from the scene
132         // Should return silently if there is nothing to remove
133         // NOTE: This has to be called before calling destructor
134         virtual void removeFromScene() {};
135
136         virtual std::string infoText() { return ""; }
137         
138         // Shall be left NULL if doesn't collide
139         // Position is relative to m_pos in block
140         core::aabbox3d<f32> * m_collision_box;
141         
142         // Shall be left NULL if can't be selected
143         core::aabbox3d<f32> * m_selection_box;
144
145 protected:
146         MapBlock *m_block;
147         // This differentiates the instance of the object
148         // Not same as typeId.
149         s16 m_id;
150         // Position of the object inside the block
151         // Units is node coordinates * BS
152         v3f m_pos;
153
154         friend class MapBlockObjectList;
155 };
156
157 class TestObject : public MapBlockObject
158 {
159 public:
160         // The constructor of every MapBlockObject should be like this
161         TestObject(MapBlock *block, s16 id, v3f pos):
162                 MapBlockObject(block, id, pos),
163                 m_node(NULL)
164         {
165         }
166         virtual ~TestObject()
167         {
168         }
169         
170         /*
171                 Implementation interface
172         */
173         virtual u16 getTypeId() const
174         {
175                 return MAPBLOCKOBJECT_TYPE_TEST;
176         }
177         virtual void serialize(std::ostream &os, u8 version)
178         {
179                 serializeBase(os, version);
180
181                 // Write subpos_c * 100
182                 u8 buf[2];
183                 writeU16(buf, m_subpos_c * 100);
184                 os.write((char*)buf, 2);
185         }
186         virtual void update(std::istream &is, u8 version)
187         {
188                 // Read subpos_c * 100
189                 u8 buf[2];
190                 is.read((char*)buf, 2);
191                 m_subpos_c = (f32)readU16(buf) / 100;
192                 
193                 updateNodePos();
194         }
195         virtual bool serverStep(float dtime)
196         {
197                 m_subpos_c += dtime * 3.0;
198
199                 updateNodePos();
200
201                 return false;
202         }
203         virtual void addToScene(scene::ISceneManager *smgr)
204         {
205                 if(m_node != NULL)
206                         return;
207                 
208                 //dstream<<"Adding to scene"<<std::endl;
209
210                 video::IVideoDriver* driver = smgr->getVideoDriver();
211                 
212                 scene::SMesh *mesh = new scene::SMesh();
213                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
214                 video::SColor c(255,255,255,255);
215                 video::S3DVertex vertices[4] =
216                 {
217                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
218                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
219                         video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
220                         video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
221                 };
222                 u16 indices[] = {0,1,2,2,3,0};
223                 buf->append(vertices, 4, indices, 6);
224                 // Set material
225                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
226                 buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
227                 buf->getMaterial().setTexture
228                                 (0, driver->getTexture("../data/player.png"));
229                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
230                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
231                 // Add to mesh
232                 mesh->addMeshBuffer(buf);
233                 buf->drop();
234                 m_node = smgr->addMeshSceneNode(mesh, NULL);
235                 mesh->drop();
236                 m_node->setPosition(getAbsolutePos());
237         }
238         virtual void removeFromScene()
239         {
240                 //dstream<<"Removing from scene"<<std::endl;
241                 if(m_node != NULL)
242                 {
243                         m_node->remove();
244                         m_node = NULL;
245                 }
246         }
247
248         /*
249                 Special methods
250         */
251         
252         void updateNodePos()
253         {
254                 m_subpos = BS*2.0 * v3f(sin(m_subpos_c), sin(m_subpos_c+1.0), sin(-m_subpos_c));
255                 
256                 if(m_node != NULL)
257                 {
258                         m_node->setPosition(getAbsolutePos() + m_subpos);
259                 }
260         }
261         
262 protected:
263         scene::IMeshSceneNode *m_node;
264         std::string m_text;
265
266         v3f m_subpos;
267         f32 m_subpos_c;
268 };
269
270 class MovingObject : public MapBlockObject
271 {
272 public:
273         // The constructor of every MapBlockObject should be like this
274         MovingObject(MapBlock *block, s16 id, v3f pos):
275                 MapBlockObject(block, id, pos),
276                 m_speed(0,0,0)
277         {
278                 m_touching_ground = false;
279         }
280         virtual ~MovingObject()
281         {
282         }
283         
284         /*
285                 Implementation interface
286         */
287         
288         virtual u16 getTypeId() const = 0;
289
290         virtual void serialize(std::ostream &os, u8 version)
291         {
292                 serializeBase(os, version);
293
294                 u8 buf[6];
295
296                 // Write speed
297                 // stored as x100/BS v3s16
298                 v3s16 speed_i(m_speed.X*100/BS, m_speed.Y*100/BS, m_speed.Z*100/BS);
299                 writeV3S16(buf, speed_i);
300                 os.write((char*)buf, 6);
301         }
302         virtual void update(std::istream &is, u8 version)
303         {
304                 u8 buf[6];
305                 
306                 // Read speed
307                 // stored as x100/BS v3s16
308                 is.read((char*)buf, 6);
309                 v3s16 speed_i = readV3S16(buf);
310                 v3f speed((f32)speed_i.X/100*BS,
311                                 (f32)speed_i.Y/100*BS,
312                                 (f32)speed_i.Z/100*BS);
313
314                 m_speed = speed;
315         }
316
317         virtual bool serverStep(float dtime) { return false; };
318         virtual void clientStep(float dtime) {};
319         
320         virtual void addToScene(scene::ISceneManager *smgr) = 0;
321         virtual void removeFromScene() = 0;
322
323         /*
324                 Special methods
325         */
326         
327         // Moves with collision detection
328         void move(float dtime, v3f acceleration);
329         
330 protected:
331         v3f m_speed;
332         bool m_touching_ground;
333 };
334
335 class Test2Object : public MovingObject
336 {
337 public:
338         // The constructor of every MapBlockObject should be like this
339         Test2Object(MapBlock *block, s16 id, v3f pos):
340                 MovingObject(block, id, pos),
341                 m_node(NULL)
342         {
343                 m_collision_box = new core::aabbox3d<f32>
344                                 (-BS*0.3,0,-BS*0.3, BS*0.3,BS*1.7,BS*0.3);
345         }
346         virtual ~Test2Object()
347         {
348                 delete m_collision_box;
349         }
350         
351         /*
352                 Implementation interface
353         */
354         virtual u16 getTypeId() const
355         {
356                 return MAPBLOCKOBJECT_TYPE_TEST2;
357         }
358         virtual void serialize(std::ostream &os, u8 version)
359         {
360                 MovingObject::serialize(os, version);
361         }
362         virtual void update(std::istream &is, u8 version)
363         {
364                 MovingObject::update(is, version);
365                 
366                 updateNodePos();
367         }
368
369         virtual bool serverStep(float dtime)
370         {
371                 m_speed.X = 2*BS;
372                 m_speed.Z = 0;
373
374                 if(m_touching_ground)
375                 {
376                         static float count = 0;
377                         count -= dtime;
378                         if(count < 0.0)
379                         {
380                                 count += 1.0;
381                                 m_speed.Y = 6.5*BS;
382                         }
383                 }
384
385                 move(dtime, v3f(0, -9.81*BS, 0));
386
387                 updateNodePos();
388
389                 return false;
390         }
391         
392         virtual void clientStep(float dtime)
393         {
394                 m_pos += m_speed * dtime;
395
396                 updateNodePos();
397         }
398         
399         virtual void addToScene(scene::ISceneManager *smgr)
400         {
401                 if(m_node != NULL)
402                         return;
403                 
404                 //dstream<<"Adding to scene"<<std::endl;
405
406                 video::IVideoDriver* driver = smgr->getVideoDriver();
407                 
408                 scene::SMesh *mesh = new scene::SMesh();
409                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
410                 video::SColor c(255,255,255,255);
411                 video::S3DVertex vertices[4] =
412                 {
413                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
414                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
415                         video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0),
416                         video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0),
417                 };
418                 u16 indices[] = {0,1,2,2,3,0};
419                 buf->append(vertices, 4, indices, 6);
420                 // Set material
421                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
422                 buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
423                 buf->getMaterial().setTexture
424                                 (0, driver->getTexture("../data/player.png"));
425                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
426                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
427                 // Add to mesh
428                 mesh->addMeshBuffer(buf);
429                 buf->drop();
430                 m_node = smgr->addMeshSceneNode(mesh, NULL);
431                 mesh->drop();
432                 m_node->setPosition(getAbsolutePos());
433         }
434         virtual void removeFromScene()
435         {
436                 //dstream<<"Removing from scene"<<std::endl;
437                 if(m_node != NULL)
438                 {
439                         m_node->remove();
440                         m_node = NULL;
441                 }
442         }
443
444         /*
445                 Special methods
446         */
447         
448         void updateNodePos()
449         {
450                 //m_subpos = BS*2.0 * v3f(sin(m_subpos_c), sin(m_subpos_c+1.0), sin(-m_subpos_c));
451                 
452                 if(m_node != NULL)
453                 {
454                         //m_node->setPosition(getAbsolutePos() + m_subpos);
455                         m_node->setPosition(getAbsolutePos());
456                 }
457         }
458         
459 protected:
460         scene::IMeshSceneNode *m_node;
461 };
462
463 class RatObject : public MovingObject
464 {
465 public:
466         RatObject(MapBlock *block, s16 id, v3f pos):
467                 MovingObject(block, id, pos),
468                 m_node(NULL)
469         {
470                 m_collision_box = new core::aabbox3d<f32>
471                                 (-BS*0.3,0,-BS*0.3, BS*0.3,BS*0.5,BS*0.3);
472                 m_selection_box = new core::aabbox3d<f32>
473                                 (-BS*0.3,0,-BS*0.3, BS*0.3,BS*0.5,BS*0.3);
474
475                 m_counter1 = 0;
476                 m_counter2 = 0;
477         }
478         virtual ~RatObject()
479         {
480                 delete m_collision_box;
481                 delete m_selection_box;
482         }
483         
484         /*
485                 Implementation interface
486         */
487         virtual u16 getTypeId() const
488         {
489                 return MAPBLOCKOBJECT_TYPE_RAT;
490         }
491         virtual void serialize(std::ostream &os, u8 version)
492         {
493                 MovingObject::serialize(os, version);
494                 u8 buf[2];
495
496                 // Write yaw * 10
497                 writeS16(buf, m_yaw * 10);
498                 os.write((char*)buf, 2);
499
500         }
501         virtual void update(std::istream &is, u8 version)
502         {
503                 MovingObject::update(is, version);
504                 u8 buf[2];
505                 
506                 // Read yaw * 10
507                 is.read((char*)buf, 2);
508                 s16 yaw_i = readS16(buf);
509                 m_yaw = (f32)yaw_i / 10;
510
511                 updateNodePos();
512         }
513
514         virtual bool serverStep(float dtime)
515         {
516                 v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
517
518                 f32 speed = 2*BS;
519
520                 m_speed.X = speed * dir.X;
521                 m_speed.Z = speed * dir.Z;
522
523                 if(m_touching_ground && (m_oldpos - m_pos).getLength() < dtime*speed/2)
524                 {
525                         m_counter1 -= dtime;
526                         if(m_counter1 < 0.0)
527                         {
528                                 m_counter1 += 1.0;
529                                 m_speed.Y = 5.0*BS;
530                         }
531                 }
532
533                 {
534                         m_counter2 -= dtime;
535                         if(m_counter2 < 0.0)
536                         {
537                                 m_counter2 += (float)(rand()%100)/100*3.0;
538                                 m_yaw += ((float)(rand()%200)-100)/100*180;
539                                 m_yaw = wrapDegrees(m_yaw);
540                         }
541                 }
542
543                 m_oldpos = m_pos;
544
545                 //m_yaw += dtime*90;
546
547                 move(dtime, v3f(0, -9.81*BS, 0));
548
549                 updateNodePos();
550
551                 return false;
552         }
553         
554         virtual void clientStep(float dtime)
555         {
556                 m_pos += m_speed * dtime;
557
558                 updateNodePos();
559         }
560         
561         virtual void addToScene(scene::ISceneManager *smgr)
562         {
563                 if(m_node != NULL)
564                         return;
565                 
566                 video::IVideoDriver* driver = smgr->getVideoDriver();
567                 
568                 scene::SMesh *mesh = new scene::SMesh();
569                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
570                 video::SColor c(255,255,255,255);
571                 video::S3DVertex vertices[4] =
572                 {
573                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
574                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
575                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
576                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
577                 };
578                 u16 indices[] = {0,1,2,2,3,0};
579                 buf->append(vertices, 4, indices, 6);
580                 // Set material
581                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
582                 buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
583                 buf->getMaterial().setTexture
584                                 (0, driver->getTexture("../data/rat.png"));
585                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
586                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
587                 // Add to mesh
588                 mesh->addMeshBuffer(buf);
589                 buf->drop();
590                 m_node = smgr->addMeshSceneNode(mesh, NULL);
591                 mesh->drop();
592                 m_node->setPosition(getAbsolutePos());
593         }
594         virtual void removeFromScene()
595         {
596                 if(m_node != NULL)
597                 {
598                         m_node->remove();
599                         m_node = NULL;
600                 }
601         }
602
603         virtual std::string getInventoryString()
604         {
605                 // There must be a space after the name
606                 // Or does there?
607                 return std::string("Rat ");
608         }
609
610         /*
611                 Special methods
612         */
613         
614         void updateNodePos()
615         {
616                 if(m_node != NULL)
617                 {
618                         m_node->setPosition(getAbsolutePos());
619                         m_node->setRotation(v3f(0, -m_yaw+180, 0));
620                 }
621         }
622         
623 protected:
624         scene::IMeshSceneNode *m_node;
625         float m_yaw;
626
627         float m_counter1;
628         float m_counter2;
629         v3f m_oldpos;
630 };
631
632 class SignObject : public MapBlockObject
633 {
634 public:
635         // The constructor of every MapBlockObject should be like this
636         SignObject(MapBlock *block, s16 id, v3f pos):
637                 MapBlockObject(block, id, pos),
638                 m_node(NULL)
639         {
640                 m_selection_box = new core::aabbox3d<f32>
641                                 (-BS*0.4,-BS*0.5,-BS*0.4, BS*0.4,BS*0.5,BS*0.4);
642         }
643         virtual ~SignObject()
644         {
645                 delete m_selection_box;
646         }
647         
648         /*
649                 Implementation interface
650         */
651         virtual u16 getTypeId() const
652         {
653                 return MAPBLOCKOBJECT_TYPE_SIGN;
654         }
655         virtual void serialize(std::ostream &os, u8 version)
656         {
657                 serializeBase(os, version);
658                 u8 buf[2];
659
660                 // Write yaw * 10
661                 writeS16(buf, m_yaw * 10);
662                 os.write((char*)buf, 2);
663
664                 // Write text length
665                 writeU16(buf, m_text.size());
666                 os.write((char*)buf, 2);
667                 
668                 // Write text
669                 os.write(m_text.c_str(), m_text.size());
670         }
671         virtual void update(std::istream &is, u8 version)
672         {
673                 u8 buf[2];
674
675                 // Read yaw * 10
676                 is.read((char*)buf, 2);
677                 s16 yaw_i = readS16(buf);
678                 m_yaw = (f32)yaw_i / 10;
679
680                 // Read text length
681                 is.read((char*)buf, 2);
682                 u16 size = readU16(buf);
683
684                 // Read text
685                 m_text.clear();
686                 for(u16 i=0; i<size; i++)
687                 {
688                         is.read((char*)buf, 1);
689                         m_text += buf[0];
690                 }
691
692                 updateSceneNode();
693         }
694         virtual bool serverStep(float dtime)
695         {
696                 return false;
697         }
698         virtual void addToScene(scene::ISceneManager *smgr)
699         {
700                 if(m_node != NULL)
701                         return;
702                 
703                 video::IVideoDriver* driver = smgr->getVideoDriver();
704                 
705                 scene::SMesh *mesh = new scene::SMesh();
706                 { // Front
707                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
708                 video::SColor c(255,255,255,255);
709                 video::S3DVertex vertices[4] =
710                 {
711                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 0,1),
712                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 1,1),
713                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 1,0),
714                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 0,0),
715                 };
716                 u16 indices[] = {0,1,2,2,3,0};
717                 buf->append(vertices, 4, indices, 6);
718                 // Set material
719                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
720                 //buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
721                 buf->getMaterial().setTexture
722                                 (0, driver->getTexture("../data/sign.png"));
723                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
724                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
725                 // Add to mesh
726                 mesh->addMeshBuffer(buf);
727                 buf->drop();
728                 }
729                 { // Back
730                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
731                 video::SColor c(255,255,255,255);
732                 video::S3DVertex vertices[4] =
733                 {
734                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
735                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
736                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
737                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
738                 };
739                 u16 indices[] = {0,1,2,2,3,0};
740                 buf->append(vertices, 4, indices, 6);
741                 // Set material
742                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
743                 //buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
744                 buf->getMaterial().setTexture
745                                 (0, driver->getTexture("../data/sign_back.png"));
746                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
747                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
748                 // Add to mesh
749                 mesh->addMeshBuffer(buf);
750                 buf->drop();
751                 }
752                 m_node = smgr->addMeshSceneNode(mesh, NULL);
753                 mesh->drop();
754
755                 updateSceneNode();
756         }
757         virtual void removeFromScene()
758         {
759                 if(m_node != NULL)
760                 {
761                         m_node->remove();
762                         m_node = NULL;
763                 }
764         }
765
766         virtual std::string infoText()
767         {
768                 return std::string("\"") + m_text + "\"";
769         }
770
771         virtual std::string getInventoryString()
772         {
773                 return std::string("Sign ")+m_text;
774         }
775
776         /*
777                 Special methods
778         */
779
780         void updateSceneNode()
781         {
782                 if(m_node != NULL)
783                 {
784                         m_node->setPosition(getAbsolutePos());
785                         m_node->setRotation(v3f(0, m_yaw, 0));
786                 }
787         }
788
789         void setText(std::string text)
790         {
791                 if(text.size() > SIGN_TEXT_MAX_LENGTH)
792                         text = text.substr(0, SIGN_TEXT_MAX_LENGTH);
793                 m_text = text;
794
795                 setBlockChanged();
796         }
797
798         void setYaw(f32 yaw)
799         {
800                 m_yaw = yaw;
801
802                 setBlockChanged();
803         }
804         
805 protected:
806         scene::IMeshSceneNode *m_node;
807         std::string m_text;
808         f32 m_yaw;
809 };
810
811 struct DistanceSortedObject
812 {
813         DistanceSortedObject(MapBlockObject *a_obj, f32 a_d)
814         {
815                 obj = a_obj;
816                 d = a_d;
817         }
818         
819         MapBlockObject *obj;
820         f32 d;
821
822         bool operator < (DistanceSortedObject &other)
823         {
824                 return d < other.d;
825         }
826 };
827
828 class MapBlockObjectList
829 {
830 public:
831         MapBlockObjectList(MapBlock *block);
832         ~MapBlockObjectList();
833         // Writes the count, id, the type id and the parameters of all objects
834         void serialize(std::ostream &os, u8 version);
835         // Reads ids, type_ids and parameters.
836         // Creates, updates and deletes objects.
837         // If smgr!=NULL, new objects are added to the scene
838         void update(std::istream &is, u8 version, scene::ISceneManager *smgr);
839         // Finds a new unique id
840         s16 getFreeId() throw(ContainerFullException);
841         /*
842                 Adds an object.
843                 Set id to -1 to have this set it to a suitable one.
844                 The block pointer member is set to this block.
845         */
846         void add(MapBlockObject *object)
847                         throw(ContainerFullException, AlreadyExistsException);
848
849         // Deletes and removes all objects
850         void clear();
851
852         /*
853                 Removes an object.
854                 Ignores inexistent objects
855         */
856         void remove(s16 id);
857         /*
858                 References an object.
859                 The object will not be valid after step() or of course if
860                 it is removed.
861                 Grabbing the lock is recommended while processing.
862         */
863         MapBlockObject * get(s16 id);
864
865         // You'll want to grab this in a SharedPtr
866         JMutexAutoLock * getLock()
867         {
868                 return new JMutexAutoLock(m_mutex);
869         }
870
871         // Steps all objects and if server==true, removes those that
872         // want to be removed
873         void step(float dtime, bool server);
874
875         // Wraps an object that wants to move onto this block from an another
876         // Returns true if wrapping was impossible
877         bool wrapObject(MapBlockObject *object);
878         
879         // origin is relative to block
880         void getObjects(v3f origin, f32 max_d,
881                         core::array<DistanceSortedObject> &dest);
882         
883         // Number of objects
884         s32 getCount()
885         {
886                 return m_objects.size();
887         }
888
889 private:
890         JMutex m_mutex;
891         // Key is id
892         core::map<s16, MapBlockObject*> m_objects;
893         MapBlock *m_block;
894 };
895
896
897 #endif
898