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