1d9dd215bd31a8a25517e37fa8c48389e220d6bf
[oweals/minetest.git] / src / clientobject.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 #include "clientobject.h"
21 #include "debug.h"
22 #include "porting.h"
23 #include "constants.h"
24 #include "utility.h"
25 #include "environment.h"
26
27 /*
28         ClientActiveObject
29 */
30
31 core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
32
33 ClientActiveObject::ClientActiveObject(u16 id):
34         ActiveObject(id)
35 {
36 }
37
38 ClientActiveObject::~ClientActiveObject()
39 {
40         removeFromScene();
41 }
42
43 ClientActiveObject* ClientActiveObject::create(u8 type)
44 {
45         // Find factory function
46         core::map<u16, Factory>::Node *n;
47         n = m_types.find(type);
48         if(n == NULL)
49         {
50                 // If factory is not found, just return.
51                 dstream<<"WARNING: ClientActiveObject: No factory for type="
52                                 <<type<<std::endl;
53                 return NULL;
54         }
55
56         Factory f = n->getValue();
57         ClientActiveObject *object = (*f)();
58         return object;
59 }
60
61 void ClientActiveObject::registerType(u16 type, Factory f)
62 {
63         core::map<u16, Factory>::Node *n;
64         n = m_types.find(type);
65         if(n)
66                 return;
67         m_types.insert(type, f);
68 }
69
70 /*
71         TestCAO
72 */
73
74 // Prototype
75 TestCAO proto_TestCAO;
76
77 TestCAO::TestCAO():
78         ClientActiveObject(0),
79         m_node(NULL),
80         m_position(v3f(0,10*BS,0))
81 {
82         ClientActiveObject::registerType(getType(), create);
83 }
84
85 TestCAO::~TestCAO()
86 {
87 }
88
89 ClientActiveObject* TestCAO::create()
90 {
91         return new TestCAO();
92 }
93
94 void TestCAO::addToScene(scene::ISceneManager *smgr)
95 {
96         if(m_node != NULL)
97                 return;
98         
99         video::IVideoDriver* driver = smgr->getVideoDriver();
100         
101         scene::SMesh *mesh = new scene::SMesh();
102         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
103         video::SColor c(255,255,255,255);
104         video::S3DVertex vertices[4] =
105         {
106                 video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
107                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
108                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
109                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
110         };
111         u16 indices[] = {0,1,2,2,3,0};
112         buf->append(vertices, 4, indices, 6);
113         // Set material
114         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
115         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
116         buf->getMaterial().setTexture
117                         (0, driver->getTexture(porting::getDataPath("rat.png").c_str()));
118         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
119         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
120         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
121         // Add to mesh
122         mesh->addMeshBuffer(buf);
123         buf->drop();
124         m_node = smgr->addMeshSceneNode(mesh, NULL);
125         mesh->drop();
126         updateNodePos();
127 }
128
129 void TestCAO::removeFromScene()
130 {
131         if(m_node == NULL)
132                 return;
133
134         m_node->remove();
135         m_node = NULL;
136 }
137
138 void TestCAO::updateLight(u8 light_at_pos)
139 {
140 }
141
142 v3s16 TestCAO::getLightPosition()
143 {
144         return floatToInt(m_position, BS);
145 }
146
147 void TestCAO::updateNodePos()
148 {
149         if(m_node == NULL)
150                 return;
151
152         m_node->setPosition(m_position);
153         //m_node->setRotation(v3f(0, 45, 0));
154 }
155
156 void TestCAO::step(float dtime, ClientEnvironment *env)
157 {
158         if(m_node)
159         {
160                 v3f rot = m_node->getRotation();
161                 //dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
162                 rot.Y += dtime * 180;
163                 m_node->setRotation(rot);
164         }
165 }
166
167 void TestCAO::processMessage(const std::string &data)
168 {
169         dstream<<"TestCAO: Got data: "<<data<<std::endl;
170         std::istringstream is(data, std::ios::binary);
171         u16 cmd;
172         is>>cmd;
173         if(cmd == 0)
174         {
175                 v3f newpos;
176                 is>>newpos.X;
177                 is>>newpos.Y;
178                 is>>newpos.Z;
179                 m_position = newpos;
180                 updateNodePos();
181         }
182 }
183
184 /*
185         ItemCAO
186 */
187
188 #include "inventory.h"
189
190 // Prototype
191 ItemCAO proto_ItemCAO;
192
193 ItemCAO::ItemCAO():
194         ClientActiveObject(0),
195         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
196         m_node(NULL),
197         m_position(v3f(0,10*BS,0))
198 {
199         ClientActiveObject::registerType(getType(), create);
200 }
201
202 ItemCAO::~ItemCAO()
203 {
204 }
205
206 ClientActiveObject* ItemCAO::create()
207 {
208         return new ItemCAO();
209 }
210
211 void ItemCAO::addToScene(scene::ISceneManager *smgr)
212 {
213         if(m_node != NULL)
214                 return;
215         
216         video::IVideoDriver* driver = smgr->getVideoDriver();
217         
218         scene::SMesh *mesh = new scene::SMesh();
219         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
220         video::SColor c(255,255,255,255);
221         video::S3DVertex vertices[4] =
222         {
223                 /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
224                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
225                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
226                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
227                 video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
228                 video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
229                 video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
230                 video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
231         };
232         u16 indices[] = {0,1,2,2,3,0};
233         buf->append(vertices, 4, indices, 6);
234         // Set material
235         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
236         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
237         //buf->getMaterial().setTexture(0, NULL);
238         // Initialize with the stick texture
239         buf->getMaterial().setTexture
240                         (0, driver->getTexture(porting::getDataPath("stick.png").c_str()));
241         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
242         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
243         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
244         // Add to mesh
245         mesh->addMeshBuffer(buf);
246         buf->drop();
247         m_node = smgr->addMeshSceneNode(mesh, NULL);
248         mesh->drop();
249         // Set it to use the materials of the meshbuffers directly.
250         // This is needed for changing the texture in the future
251         m_node->setReadOnlyMaterials(true);
252         updateNodePos();
253 }
254
255 void ItemCAO::removeFromScene()
256 {
257         if(m_node == NULL)
258                 return;
259
260         m_node->remove();
261         m_node = NULL;
262 }
263
264 void ItemCAO::updateLight(u8 light_at_pos)
265 {
266         if(m_node == NULL)
267                 return;
268
269         u8 li = decode_light(light_at_pos);
270         video::SColor color(255,li,li,li);
271
272         scene::IMesh *mesh = m_node->getMesh();
273         if(mesh == NULL)
274                 return;
275         
276         u16 mc = mesh->getMeshBufferCount();
277         for(u16 j=0; j<mc; j++)
278         {
279                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
280                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
281                 u16 vc = buf->getVertexCount();
282                 for(u16 i=0; i<vc; i++)
283                 {
284                         vertices[i].Color = color;
285                 }
286         }
287 }
288
289 v3s16 ItemCAO::getLightPosition()
290 {
291         return floatToInt(m_position, BS);
292 }
293
294 void ItemCAO::updateNodePos()
295 {
296         if(m_node == NULL)
297                 return;
298
299         m_node->setPosition(m_position);
300 }
301
302 void ItemCAO::step(float dtime, ClientEnvironment *env)
303 {
304         if(m_node)
305         {
306                 /*v3f rot = m_node->getRotation();
307                 rot.Y += dtime * 120;
308                 m_node->setRotation(rot);*/
309                 LocalPlayer *player = env->getLocalPlayer();
310                 assert(player);
311                 v3f rot = m_node->getRotation();
312                 rot.Y = 180.0 - (player->getYaw());
313                 m_node->setRotation(rot);
314         }
315 }
316
317 void ItemCAO::processMessage(const std::string &data)
318 {
319         dstream<<"ItemCAO: Got message"<<std::endl;
320         std::istringstream is(data, std::ios::binary);
321         // command
322         u8 cmd = readU8(is);
323         if(cmd == 0)
324         {
325                 // pos
326                 m_position = readV3F1000(is);
327                 updateNodePos();
328         }
329 }
330
331 void ItemCAO::initialize(const std::string &data)
332 {
333         dstream<<"ItemCAO: Got init data"<<std::endl;
334         
335         {
336                 std::istringstream is(data, std::ios::binary);
337                 // version
338                 u8 version = readU8(is);
339                 // check version
340                 if(version != 0)
341                         return;
342                 // pos
343                 m_position = readV3F1000(is);
344                 // inventorystring
345                 m_inventorystring = deSerializeString(is);
346         }
347         
348         updateNodePos();
349
350         /*
351                 Update image of node
352         */
353
354         if(m_node == NULL)
355                 return;
356
357         scene::IMesh *mesh = m_node->getMesh();
358
359         if(mesh == NULL)
360                 return;
361         
362         scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
363
364         if(buf == NULL)
365                 return;
366
367         // Create an inventory item to see what is its image
368         std::istringstream is(m_inventorystring, std::ios_base::binary);
369         video::ITexture *texture = NULL;
370         try{
371                 InventoryItem *item = NULL;
372                 item = InventoryItem::deSerialize(is);
373                 dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
374                                 <<m_inventorystring<<"\" -> item="<<item
375                                 <<std::endl;
376                 if(item)
377                 {
378                         texture = item->getImage();
379                         delete item;
380                 }
381         }
382         catch(SerializationError &e)
383         {
384                 dstream<<"WARNING: "<<__FUNCTION_NAME
385                                 <<": error deSerializing inventorystring \""
386                                 <<m_inventorystring<<"\""<<std::endl;
387         }
388         
389         // Set meshbuffer texture
390         buf->getMaterial().setTexture(0, texture);
391         
392 }
393
394 /*
395         RatCAO
396 */
397
398 #include "inventory.h"
399
400 // Prototype
401 RatCAO proto_RatCAO;
402
403 RatCAO::RatCAO():
404         ClientActiveObject(0),
405         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
406         m_node(NULL),
407         m_position(v3f(0,10*BS,0))
408 {
409         ClientActiveObject::registerType(getType(), create);
410 }
411
412 RatCAO::~RatCAO()
413 {
414 }
415
416 ClientActiveObject* RatCAO::create()
417 {
418         return new RatCAO();
419 }
420
421 void RatCAO::addToScene(scene::ISceneManager *smgr)
422 {
423         if(m_node != NULL)
424                 return;
425         
426         video::IVideoDriver* driver = smgr->getVideoDriver();
427         
428         scene::SMesh *mesh = new scene::SMesh();
429         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
430         video::SColor c(255,255,255,255);
431         video::S3DVertex vertices[4] =
432         {
433                 video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1),
434                 video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
435                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
436                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
437         };
438         u16 indices[] = {0,1,2,2,3,0};
439         buf->append(vertices, 4, indices, 6);
440         // Set material
441         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
442         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
443         //buf->getMaterial().setTexture(0, NULL);
444         buf->getMaterial().setTexture
445                         (0, driver->getTexture(porting::getDataPath("rat.png").c_str()));
446         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
447         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
448         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
449         // Add to mesh
450         mesh->addMeshBuffer(buf);
451         buf->drop();
452         m_node = smgr->addMeshSceneNode(mesh, NULL);
453         mesh->drop();
454         // Set it to use the materials of the meshbuffers directly.
455         // This is needed for changing the texture in the future
456         m_node->setReadOnlyMaterials(true);
457         updateNodePos();
458 }
459
460 void RatCAO::removeFromScene()
461 {
462         if(m_node == NULL)
463                 return;
464
465         m_node->remove();
466         m_node = NULL;
467 }
468
469 void RatCAO::updateLight(u8 light_at_pos)
470 {
471         if(m_node == NULL)
472                 return;
473
474         u8 li = decode_light(light_at_pos);
475         video::SColor color(255,li,li,li);
476
477         scene::IMesh *mesh = m_node->getMesh();
478         if(mesh == NULL)
479                 return;
480         
481         u16 mc = mesh->getMeshBufferCount();
482         for(u16 j=0; j<mc; j++)
483         {
484                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
485                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
486                 u16 vc = buf->getVertexCount();
487                 for(u16 i=0; i<vc; i++)
488                 {
489                         vertices[i].Color = color;
490                 }
491         }
492 }
493
494 v3s16 RatCAO::getLightPosition()
495 {
496         return floatToInt(m_position, BS);
497 }
498
499 void RatCAO::updateNodePos()
500 {
501         if(m_node == NULL)
502                 return;
503
504         //m_node->setPosition(m_position);
505         m_node->setPosition(pos_translator.vect_show);
506
507         v3f rot = m_node->getRotation();
508         rot.Y = 180.0 - m_yaw;
509         m_node->setRotation(rot);
510 }
511
512 void RatCAO::step(float dtime, ClientEnvironment *env)
513 {
514         pos_translator.translate(dtime);
515         updateNodePos();
516 }
517
518 void RatCAO::processMessage(const std::string &data)
519 {
520         //dstream<<"RatCAO: Got message"<<std::endl;
521         std::istringstream is(data, std::ios::binary);
522         // command
523         u8 cmd = readU8(is);
524         if(cmd == 0)
525         {
526                 // pos
527                 m_position = readV3F1000(is);
528                 pos_translator.update(m_position);
529                 // yaw
530                 m_yaw = readF1000(is);
531                 updateNodePos();
532         }
533 }
534
535 void RatCAO::initialize(const std::string &data)
536 {
537         //dstream<<"RatCAO: Got init data"<<std::endl;
538         
539         {
540                 std::istringstream is(data, std::ios::binary);
541                 // version
542                 u8 version = readU8(is);
543                 // check version
544                 if(version != 0)
545                         return;
546                 // pos
547                 m_position = readV3F1000(is);
548                 pos_translator.init(m_position);
549         }
550         
551         updateNodePos();
552 }
553
554