]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblockobject.h
8518d6b11fb2c23330151316b5c7a66212bc6021
[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 MovingObject : public MapBlockObject
224 {
225 public:
226         // The constructor of every MapBlockObject should be like this
227         MovingObject(MapBlock *block, s16 id, v3f pos):
228                 MapBlockObject(block, id, pos),
229                 m_speed(0,0,0)
230         {
231                 m_touching_ground = false;
232         }
233         virtual ~MovingObject()
234         {
235         }
236         
237         /*
238                 Implementation interface
239         */
240         
241         virtual u16 getTypeId() const = 0;
242
243         virtual void serialize(std::ostream &os, u8 version)
244         {
245                 serializeBase(os, version);
246
247                 u8 buf[6];
248
249                 // Write speed
250                 // stored as x100/BS v3s16
251                 v3s16 speed_i(m_speed.X*100/BS, m_speed.Y*100/BS, m_speed.Z*100/BS);
252                 writeV3S16(buf, speed_i);
253                 os.write((char*)buf, 6);
254         }
255         virtual void update(std::istream &is, u8 version)
256         {
257                 u8 buf[6];
258                 
259                 // Read speed
260                 // stored as x100/BS v3s16
261                 is.read((char*)buf, 6);
262                 v3s16 speed_i = readV3S16(buf);
263                 v3f speed((f32)speed_i.X/100*BS,
264                                 (f32)speed_i.Y/100*BS,
265                                 (f32)speed_i.Z/100*BS);
266
267                 m_speed = speed;
268         }
269
270         virtual bool serverStep(float dtime) { return false; };
271         virtual void clientStep(float dtime) {};
272         
273         virtual void addToScene(scene::ISceneManager *smgr) = 0;
274         virtual void removeFromScene() = 0;
275
276         /*
277                 Special methods
278         */
279         
280         // Moves with collision detection
281         void move(float dtime, v3f acceleration);
282         
283 protected:
284         v3f m_speed;
285         bool m_touching_ground;
286 };
287
288 class RatObject : public MovingObject
289 {
290 public:
291         RatObject(MapBlock *block, s16 id, v3f pos):
292                 MovingObject(block, id, pos),
293                 m_node(NULL)
294         {
295                 m_collision_box = new core::aabbox3d<f32>
296                                 (-BS*0.3,0,-BS*0.3, BS*0.3,BS*0.5,BS*0.3);
297                 m_selection_box = new core::aabbox3d<f32>
298                                 (-BS*0.3,0,-BS*0.3, BS*0.3,BS*0.5,BS*0.3);
299
300                 m_counter1 = 0;
301                 m_counter2 = 0;
302         }
303         virtual ~RatObject()
304         {
305                 delete m_collision_box;
306                 delete m_selection_box;
307         }
308         
309         /*
310                 Implementation interface
311         */
312         virtual u16 getTypeId() const
313         {
314                 return MAPBLOCKOBJECT_TYPE_RAT;
315         }
316         virtual void serialize(std::ostream &os, u8 version)
317         {
318                 MovingObject::serialize(os, version);
319                 u8 buf[2];
320
321                 // Write yaw * 10
322                 writeS16(buf, m_yaw * 10);
323                 os.write((char*)buf, 2);
324
325         }
326         virtual void update(std::istream &is, u8 version)
327         {
328                 MovingObject::update(is, version);
329                 u8 buf[2];
330                 
331                 // Read yaw * 10
332                 is.read((char*)buf, 2);
333                 s16 yaw_i = readS16(buf);
334                 m_yaw = (f32)yaw_i / 10;
335
336                 updateNodePos();
337         }
338
339         virtual bool serverStep(float dtime)
340         {
341                 v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
342
343                 f32 speed = 2*BS;
344
345                 m_speed.X = speed * dir.X;
346                 m_speed.Z = speed * dir.Z;
347
348                 if(m_touching_ground && (m_oldpos - m_pos).getLength() < dtime*speed/2)
349                 {
350                         m_counter1 -= dtime;
351                         if(m_counter1 < 0.0)
352                         {
353                                 m_counter1 += 1.0;
354                                 m_speed.Y = 5.0*BS;
355                         }
356                 }
357
358                 {
359                         m_counter2 -= dtime;
360                         if(m_counter2 < 0.0)
361                         {
362                                 m_counter2 += (float)(rand()%100)/100*3.0;
363                                 m_yaw += ((float)(rand()%200)-100)/100*180;
364                                 m_yaw = wrapDegrees(m_yaw);
365                         }
366                 }
367
368                 m_oldpos = m_pos;
369
370                 //m_yaw += dtime*90;
371
372                 move(dtime, v3f(0, -9.81*BS, 0));
373
374                 updateNodePos();
375
376                 return false;
377         }
378         
379         virtual void clientStep(float dtime)
380         {
381                 m_pos += m_speed * dtime;
382
383                 updateNodePos();
384         }
385         
386         virtual void addToScene(scene::ISceneManager *smgr)
387         {
388                 if(m_node != NULL)
389                         return;
390                 
391                 video::IVideoDriver* driver = smgr->getVideoDriver();
392                 
393                 scene::SMesh *mesh = new scene::SMesh();
394                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
395                 video::SColor c(255,255,255,255);
396                 video::S3DVertex vertices[4] =
397                 {
398                         video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
399                         video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
400                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
401                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
402                 };
403                 u16 indices[] = {0,1,2,2,3,0};
404                 buf->append(vertices, 4, indices, 6);
405                 // Set material
406                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
407                 buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
408                 buf->getMaterial().setTexture
409                                 (0, driver->getTexture("../data/rat.png"));
410                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
411                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
412                 // Add to mesh
413                 mesh->addMeshBuffer(buf);
414                 buf->drop();
415                 m_node = smgr->addMeshSceneNode(mesh, NULL);
416                 mesh->drop();
417                 m_node->setPosition(getAbsolutePos());
418         }
419         virtual void removeFromScene()
420         {
421                 if(m_node != NULL)
422                 {
423                         m_node->remove();
424                         m_node = NULL;
425                 }
426         }
427
428         virtual std::string getInventoryString()
429         {
430                 // There must be a space after the name
431                 // Or does there?
432                 return std::string("Rat ");
433         }
434
435         /*
436                 Special methods
437         */
438         
439         void updateNodePos()
440         {
441                 if(m_node != NULL)
442                 {
443                         m_node->setPosition(getAbsolutePos());
444                         m_node->setRotation(v3f(0, -m_yaw+180, 0));
445                 }
446         }
447         
448 protected:
449         scene::IMeshSceneNode *m_node;
450         float m_yaw;
451
452         float m_counter1;
453         float m_counter2;
454         v3f m_oldpos;
455 };
456
457 class SignObject : public MapBlockObject
458 {
459 public:
460         // The constructor of every MapBlockObject should be like this
461         SignObject(MapBlock *block, s16 id, v3f pos):
462                 MapBlockObject(block, id, pos),
463                 m_node(NULL)
464         {
465                 m_selection_box = new core::aabbox3d<f32>
466                                 (-BS*0.4,-BS*0.5,-BS*0.4, BS*0.4,BS*0.5,BS*0.4);
467         }
468         virtual ~SignObject()
469         {
470                 delete m_selection_box;
471         }
472         
473         /*
474                 Implementation interface
475         */
476         virtual u16 getTypeId() const
477         {
478                 return MAPBLOCKOBJECT_TYPE_SIGN;
479         }
480         virtual void serialize(std::ostream &os, u8 version)
481         {
482                 serializeBase(os, version);
483                 u8 buf[2];
484
485                 // Write yaw * 10
486                 writeS16(buf, m_yaw * 10);
487                 os.write((char*)buf, 2);
488
489                 // Write text length
490                 writeU16(buf, m_text.size());
491                 os.write((char*)buf, 2);
492                 
493                 // Write text
494                 os.write(m_text.c_str(), m_text.size());
495         }
496         virtual void update(std::istream &is, u8 version)
497         {
498                 u8 buf[2];
499
500                 // Read yaw * 10
501                 is.read((char*)buf, 2);
502                 s16 yaw_i = readS16(buf);
503                 m_yaw = (f32)yaw_i / 10;
504
505                 // Read text length
506                 is.read((char*)buf, 2);
507                 u16 size = readU16(buf);
508
509                 // Read text
510                 m_text.clear();
511                 for(u16 i=0; i<size; i++)
512                 {
513                         is.read((char*)buf, 1);
514                         m_text += buf[0];
515                 }
516
517                 updateSceneNode();
518         }
519         virtual bool serverStep(float dtime)
520         {
521                 return false;
522         }
523         virtual void addToScene(scene::ISceneManager *smgr)
524         {
525                 if(m_node != NULL)
526                         return;
527                 
528                 video::IVideoDriver* driver = smgr->getVideoDriver();
529                 
530                 scene::SMesh *mesh = new scene::SMesh();
531                 { // Front
532                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
533                 video::SColor c(255,255,255,255);
534                 video::S3DVertex vertices[4] =
535                 {
536                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 0,1),
537                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 1,1),
538                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 1,0),
539                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 0,0),
540                 };
541                 u16 indices[] = {0,1,2,2,3,0};
542                 buf->append(vertices, 4, indices, 6);
543                 // Set material
544                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
545                 //buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
546                 buf->getMaterial().setTexture
547                                 (0, driver->getTexture("../data/sign.png"));
548                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
549                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
550                 // Add to mesh
551                 mesh->addMeshBuffer(buf);
552                 buf->drop();
553                 }
554                 { // Back
555                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
556                 video::SColor c(255,255,255,255);
557                 video::S3DVertex vertices[4] =
558                 {
559                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
560                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
561                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
562                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
563                 };
564                 u16 indices[] = {0,1,2,2,3,0};
565                 buf->append(vertices, 4, indices, 6);
566                 // Set material
567                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
568                 //buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
569                 buf->getMaterial().setTexture
570                                 (0, driver->getTexture("../data/sign_back.png"));
571                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
572                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
573                 // Add to mesh
574                 mesh->addMeshBuffer(buf);
575                 buf->drop();
576                 }
577                 m_node = smgr->addMeshSceneNode(mesh, NULL);
578                 mesh->drop();
579
580                 updateSceneNode();
581         }
582         virtual void removeFromScene()
583         {
584                 if(m_node != NULL)
585                 {
586                         m_node->remove();
587                         m_node = NULL;
588                 }
589         }
590
591         virtual std::string infoText()
592         {
593                 return std::string("\"") + m_text + "\"";
594         }
595
596         virtual std::string getInventoryString()
597         {
598                 return std::string("Sign ")+m_text;
599         }
600
601         /*
602                 Special methods
603         */
604
605         void updateSceneNode()
606         {
607                 if(m_node != NULL)
608                 {
609                         m_node->setPosition(getAbsolutePos());
610                         m_node->setRotation(v3f(0, m_yaw, 0));
611                 }
612         }
613
614         void setText(std::string text)
615         {
616                 if(text.size() > SIGN_TEXT_MAX_LENGTH)
617                         text = text.substr(0, SIGN_TEXT_MAX_LENGTH);
618                 m_text = text;
619
620                 setBlockChanged();
621         }
622
623         void setYaw(f32 yaw)
624         {
625                 m_yaw = yaw;
626
627                 setBlockChanged();
628         }
629         
630 protected:
631         scene::IMeshSceneNode *m_node;
632         std::string m_text;
633         f32 m_yaw;
634 };
635
636 struct DistanceSortedObject
637 {
638         DistanceSortedObject(MapBlockObject *a_obj, f32 a_d)
639         {
640                 obj = a_obj;
641                 d = a_d;
642         }
643         
644         MapBlockObject *obj;
645         f32 d;
646
647         bool operator < (DistanceSortedObject &other)
648         {
649                 return d < other.d;
650         }
651 };
652
653 class MapBlockObjectList
654 {
655 public:
656         MapBlockObjectList(MapBlock *block);
657         ~MapBlockObjectList();
658         // Writes the count, id, the type id and the parameters of all objects
659         void serialize(std::ostream &os, u8 version);
660         // Reads ids, type_ids and parameters.
661         // Creates, updates and deletes objects.
662         // If smgr!=NULL, new objects are added to the scene
663         void update(std::istream &is, u8 version, scene::ISceneManager *smgr);
664         // Finds a new unique id
665         s16 getFreeId() throw(ContainerFullException);
666         /*
667                 Adds an object.
668                 Set id to -1 to have this set it to a suitable one.
669                 The block pointer member is set to this block.
670         */
671         void add(MapBlockObject *object)
672                         throw(ContainerFullException, AlreadyExistsException);
673
674         // Deletes and removes all objects
675         void clear();
676
677         /*
678                 Removes an object.
679                 Ignores inexistent objects
680         */
681         void remove(s16 id);
682         /*
683                 References an object.
684                 The object will not be valid after step() or of course if
685                 it is removed.
686                 Grabbing the lock is recommended while processing.
687         */
688         MapBlockObject * get(s16 id);
689
690         // You'll want to grab this in a SharedPtr
691         JMutexAutoLock * getLock()
692         {
693                 return new JMutexAutoLock(m_mutex);
694         }
695
696         // Steps all objects and if server==true, removes those that
697         // want to be removed
698         void step(float dtime, bool server);
699
700         // Wraps an object that wants to move onto this block from an another
701         // Returns true if wrapping was impossible
702         bool wrapObject(MapBlockObject *object);
703         
704         // origin is relative to block
705         void getObjects(v3f origin, f32 max_d,
706                         core::array<DistanceSortedObject> &dest);
707         
708         // Number of objects
709         s32 getCount()
710         {
711                 return m_objects.size();
712         }
713
714 private:
715         JMutex m_mutex;
716         // Key is id
717         core::map<s16, MapBlockObject*> m_objects;
718         MapBlock *m_block;
719 };
720
721
722 #endif
723