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