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