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