]> git.lizzy.rs Git - minetest.git/blob - src/clientobject.cpp
bb4497e94ad23c4ffe39e5755fa8d9bc21fe28b3
[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
26 ClientActiveObject::ClientActiveObject(u16 id):
27         ActiveObject(id)
28 {
29 }
30
31 ClientActiveObject::~ClientActiveObject()
32 {
33         removeFromScene();
34 }
35
36 ClientActiveObject* ClientActiveObject::create(u8 type)
37 {
38         if(type == ACTIVEOBJECT_TYPE_INVALID)
39         {
40                 dstream<<"ClientActiveObject::create(): passed "
41                                 <<"ACTIVEOBJECT_TYPE_INVALID"<<std::endl;
42                 return NULL;
43         }
44         else if(type == ACTIVEOBJECT_TYPE_TEST)
45         {
46                 dstream<<"ClientActiveObject::create(): passed "
47                                 <<"ACTIVEOBJECT_TYPE_TEST"<<std::endl;
48                 return new TestCAO(0);
49         }
50         else if(type == ACTIVEOBJECT_TYPE_LUA)
51         {
52                 dstream<<"ClientActiveObject::create(): passed "
53                                 <<"ACTIVEOBJECT_TYPE_LUA"<<std::endl;
54                 return new LuaCAO(0);
55         }
56         else
57         {
58                 dstream<<"ClientActiveObject::create(): passed "
59                                 <<"unknown type="<<type<<std::endl;
60                 return NULL;
61         }
62 }
63
64 /*
65         TestCAO
66 */
67
68 TestCAO::TestCAO(u16 id):
69         ClientActiveObject(id),
70         m_node(NULL),
71         m_position(v3f(0,10*BS,0))
72 {
73 }
74
75 TestCAO::~TestCAO()
76 {
77 }
78
79 void TestCAO::addToScene(scene::ISceneManager *smgr)
80 {
81         if(m_node != NULL)
82                 return;
83         
84         video::IVideoDriver* driver = smgr->getVideoDriver();
85         
86         scene::SMesh *mesh = new scene::SMesh();
87         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
88         video::SColor c(255,255,255,255);
89         video::S3DVertex vertices[4] =
90         {
91                 video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
92                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
93                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
94                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
95         };
96         u16 indices[] = {0,1,2,2,3,0};
97         buf->append(vertices, 4, indices, 6);
98         // Set material
99         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
100         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
101         buf->getMaterial().setTexture
102                         (0, driver->getTexture(porting::getDataPath("rat.png").c_str()));
103         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
104         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
105         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
106         // Add to mesh
107         mesh->addMeshBuffer(buf);
108         buf->drop();
109         m_node = smgr->addMeshSceneNode(mesh, NULL);
110         mesh->drop();
111         updateNodePos();
112 }
113
114 void TestCAO::removeFromScene()
115 {
116         if(m_node == NULL)
117                 return;
118
119         m_node->remove();
120         m_node = NULL;
121 }
122
123 void TestCAO::updateLight(u8 light_at_pos)
124 {
125 }
126
127 v3s16 TestCAO::getLightPosition()
128 {
129         return floatToInt(m_position, BS);
130 }
131
132 void TestCAO::updateNodePos()
133 {
134         if(m_node == NULL)
135                 return;
136
137         m_node->setPosition(m_position);
138         //m_node->setRotation(v3f(0, 45, 0));
139 }
140
141 void TestCAO::step(float dtime)
142 {
143         if(m_node)
144         {
145                 v3f rot = m_node->getRotation();
146                 //dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
147                 rot.Y += dtime * 180;
148                 m_node->setRotation(rot);
149         }
150 }
151
152 void TestCAO::processMessage(const std::string &data)
153 {
154         dstream<<"TestCAO: Got data: "<<data<<std::endl;
155         std::istringstream is(data, std::ios::binary);
156         u16 cmd;
157         is>>cmd;
158         if(cmd == 0)
159         {
160                 v3f newpos;
161                 is>>newpos.X;
162                 is>>newpos.Y;
163                 is>>newpos.Z;
164                 m_position = newpos;
165                 updateNodePos();
166         }
167 }
168
169 /*
170         LuaCAO
171 */
172
173 extern "C"{
174 #include "lstring.h"
175 }
176
177 /*
178         Functions for calling from script:
179
180         object_set_position(self, x, y, z)
181         object_set_rotation(self, x, y, z)
182         object_add_to_mesh(self, image, corners, backface_culling)
183         object_clear_mesh(self)
184
185         Callbacks in script:
186
187         step(self, dtime)
188         process_message(self, data)
189         initialize(self, data)
190         TODO:
191         string status_text(self)
192 */
193
194 /*
195         object_set_position(self, x, y, z)
196 */
197 static int lf_object_set_position(lua_State *L)
198 {
199         // 4: z
200         lua_Number z = lua_tonumber(L, -1);
201         lua_pop(L, 1);
202         // 3: y
203         lua_Number y = lua_tonumber(L, -1);
204         lua_pop(L, 1);
205         // 2: x
206         lua_Number x = lua_tonumber(L, -1);
207         lua_pop(L, 1);
208         // 1: self
209         LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
210         lua_pop(L, 1);
211         
212         assert(self);
213         
214         self->setPosition(v3f(x*BS,y*BS,z*BS));
215         
216         return 0; // Number of return values
217 }
218
219 /*
220         object_set_rotation(self, x, y, z)
221 */
222 static int lf_object_set_rotation(lua_State *L)
223 {
224         // 4: z
225         lua_Number z = lua_tonumber(L, -1);
226         lua_pop(L, 1);
227         // 3: y
228         lua_Number y = lua_tonumber(L, -1);
229         lua_pop(L, 1);
230         // 2: x
231         lua_Number x = lua_tonumber(L, -1);
232         lua_pop(L, 1);
233         // 1: self
234         LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
235         lua_pop(L, 1);
236         
237         assert(self);
238         
239         self->setRotation(v3f(x,y,z));
240         
241         return 0; // Number of return values
242 }
243
244 /*
245         object_add_to_mesh(self, image, corners, backface_culling)
246         corners is an array like this:
247         {{x,y,z},{x,y,z},{x,y,z},{x,y,z}}
248 */
249 static int lf_object_add_to_mesh(lua_State *L)
250 {
251         // 4: backface_culling
252         bool backface_culling = lua_toboolean(L, -1);
253         lua_pop(L, 1);
254         // 3: corners
255         if(lua_istable(L, -1) == false)
256         {
257                 dstream<<"ERROR: object_add_to_mesh(): parameter 3 not a table"
258                                 <<std::endl;
259                 return 0;
260         }
261         v3f corners[4];
262         // Loop table
263         for(int i=0; i<4; i++)
264         {
265                 // Get child table
266                 lua_pushinteger(L, i+1);
267                 lua_gettable(L, -2);
268                 if(lua_istable(L, -1) == false)
269                 {
270                         dstream<<"ERROR: object_add_to_mesh(): parameter 3 not a"
271                                         " table of tables"<<std::endl;
272                         return 0;
273                 }
274
275                 // Get x, y and z from the child table
276                 
277                 lua_pushinteger(L, 1);
278                 lua_gettable(L, -2);
279                 corners[i].X = lua_tonumber(L, -1) * BS;
280                 lua_pop(L, 1);
281
282                 lua_pushinteger(L, 2);
283                 lua_gettable(L, -2);
284                 corners[i].Y = lua_tonumber(L, -1) * BS;
285                 lua_pop(L, 1);
286
287                 lua_pushinteger(L, 3);
288                 lua_gettable(L, -2);
289                 corners[i].Z = lua_tonumber(L, -1) * BS;
290                 lua_pop(L, 1);
291
292                 // Pop child table
293                 lua_pop(L, 1);
294         }
295         lua_pop(L, 1);
296         // 2: image
297         const char *image = lua_tostring(L, -1);
298         lua_pop(L, 1);
299         // 1: self
300         LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
301         lua_pop(L, 1);
302
303         assert(self);
304         
305         self->addToMesh(image, corners, backface_culling);
306         
307         return 0; // Number of return values
308 }
309
310 /*
311         object_clear_mesh(self)
312 */
313 static int lf_object_clear_mesh(lua_State *L)
314 {
315         // 1: self
316         LuaCAO *self = (LuaCAO*)lua_touserdata(L, -1);
317         lua_pop(L, 1);
318         
319         assert(self);
320
321         self->clearMesh();
322
323         return 0;
324 }
325
326 LuaCAO::LuaCAO(u16 id):
327         ClientActiveObject(id),
328         L(NULL),
329         m_smgr(NULL),
330         m_node(NULL),
331         m_mesh(NULL),
332         m_position(v3f(0,10*BS,0))
333 {
334         dstream<<"LuaCAO::LuaCAO(): id="<<id<<std::endl;
335         L = lua_open();
336         assert(L);
337         
338         // Load libraries
339         luaopen_base(L);
340         luaopen_table(L);
341         luaopen_string(L);
342         luaopen_math(L);
343
344         // Disable some stuff
345         const char *to_disable[] = {
346                 "arg",
347                 "debug",
348                 "dofile",
349                 "io",
350                 "loadfile",
351                 "os",
352                 "package",
353                 "require",
354                 NULL
355         };
356         const char **td = to_disable;
357         do{
358                 lua_pushnil(L);
359                 lua_setglobal(L, *td);
360         }while(*(++td));
361         
362         // Add globals
363         //lua_pushlightuserdata(L, this);
364         //lua_setglobal(L, "self");
365         
366         // Register functions
367         lua_register(L, "object_set_position", lf_object_set_position);
368         lua_register(L, "object_set_rotation", lf_object_set_rotation);
369         lua_register(L, "object_add_to_mesh", lf_object_add_to_mesh);
370         lua_register(L, "object_clear_mesh", lf_object_clear_mesh);
371 }
372
373 LuaCAO::~LuaCAO()
374 {
375         lua_close(L);
376 }
377
378 void LuaCAO::step(float dtime)
379 {
380         /*
381                 Call step(self, dtime) from lua
382         */
383         
384         const char *funcname = "step";
385         lua_getglobal(L, funcname);
386         if(!lua_isfunction(L,-1))
387         {
388                 lua_pop(L,1);
389                 dstream<<"WARNING: LuaCAO: Function not found: "
390                                 <<funcname<<std::endl;
391                 return;
392         }
393         
394         // Parameters:
395         // 1: self
396         lua_pushlightuserdata(L, this);
397         // 2: dtime
398         lua_pushnumber(L, dtime);
399         
400         // Call (2 parameters, 0 result)
401         if(lua_pcall(L, 2, 0, 0))
402         {
403                 dstream<<"WARNING: LuaCAO: Error running function "
404                                 <<funcname<<": "
405                                 <<lua_tostring(L,-1)<<std::endl;
406                 return;
407         }
408 }
409
410 void LuaCAO::processMessage(const std::string &data)
411 {
412         /*
413                 Call process_message(self, data) from lua
414         */
415         
416         const char *funcname = "process_message";
417         lua_getglobal(L, funcname);
418         if(!lua_isfunction(L,-1))
419         {
420                 lua_pop(L,1);
421                 dstream<<"WARNING: LuaCAO: Function not found: "
422                                 <<funcname<<std::endl;
423                 return;
424         }
425         
426         // Parameters:
427         // 1: self
428         lua_pushlightuserdata(L, this);
429         // 2: data
430         lua_pushlstring(L, data.c_str(), data.size());
431         
432         // Call (2 parameters, 0 results)
433         if(lua_pcall(L, 2, 1, 0))
434         {
435                 dstream<<"WARNING: LuaCAO: Error running function "
436                                 <<funcname<<": "
437                                 <<lua_tostring(L,-1)<<std::endl;
438                 return;
439         }
440 }
441
442 void LuaCAO::initialize(const std::string &data)
443 {
444         dstream<<"LuaCAO::initialize(): id="<<getId()<<std::endl;
445
446         std::istringstream is(data, std::ios::binary);
447         std::string script = deSerializeLongString(is);
448         std::string other = deSerializeLongString(is);
449
450         /*dstream<<"=== script (size="<<script.size()<<")"<<std::endl
451                         <<script<<std::endl
452                         <<"==="<<std::endl;*/
453         dstream<<"LuaCAO::initialize(): script size="<<script.size()<<std::endl;
454         
455         /*dstream<<"other.size()="<<other.size()<<std::endl;
456         dstream<<"other=\""<<other<<"\""<<std::endl;*/
457         
458         // Load the script to lua
459         loadScript(script);
460
461         /*
462                 Call initialize(self, data) in the script
463         */
464         
465         const char *funcname = "initialize";
466         lua_getglobal(L, funcname);
467         if(!lua_isfunction(L,-1))
468         {
469                 lua_pop(L,1);
470                 dstream<<"WARNING: LuaCAO: Function not found: "
471                                 <<funcname<<std::endl;
472                 return;
473         }
474         
475         // Parameters:
476         // 1: self
477         lua_pushlightuserdata(L, this);
478         // 2: data (other)
479         lua_pushlstring(L, other.c_str(), other.size());
480         
481         // Call (2 parameters, 0 result)
482         if(lua_pcall(L, 2, 0, 0))
483         {
484                 dstream<<"WARNING: LuaCAO: Error running function "
485                                 <<funcname<<": "
486                                 <<lua_tostring(L,-1)<<std::endl;
487                 return;
488         }
489
490 }
491
492 void LuaCAO::loadScript(const std::string script)
493 {
494         int ret;
495         ret = luaL_loadstring(L, script.c_str());
496         if(ret)
497         {
498                 const char *message = lua_tostring(L, -1);
499                 lua_pop(L, 1);
500                 dstream<<"LuaCAO::loadScript(): lua_loadstring failed: "
501                                 <<message<<std::endl;
502                 assert(0);
503                 return;
504         }
505         ret = lua_pcall(L, 0, 0, 0);
506         if(ret)
507         {
508                 const char *message = lua_tostring(L, -1);
509                 lua_pop(L, 1);
510                 dstream<<"LuaCAO::loadScript(): lua_pcall failed: "
511                                 <<message<<std::endl;
512                 assert(0);
513                 return;
514         }
515 }
516
517 void LuaCAO::addToScene(scene::ISceneManager *smgr)
518 {
519         if(m_smgr != NULL)
520         {
521                 dstream<<"WARNING: LuaCAO::addToScene() called more than once"
522                                 <<std::endl;
523                 return;
524         }
525
526         if(m_node != NULL)
527         {
528                 dstream<<"WARNING: LuaCAO::addToScene(): m_node != NULL"
529                                 <<std::endl;
530                 return;
531         }
532         
533         m_smgr = smgr;
534         
535         if(m_mesh == NULL)
536         {
537                 m_mesh = new scene::SMesh();
538                 m_node = smgr->addMeshSceneNode(m_mesh, NULL);
539                 
540                 /*v3f corners[4] = {
541                         v3f(-BS/2,-BS/4,0),
542                         v3f(BS/2,-BS/4,0),
543                         v3f(BS/2,BS/4,0),
544                         v3f(-BS/2,BS/4,0),
545                 };
546                 addToMesh("rat.png", corners, false);*/
547         }
548         else
549         {
550                 dstream<<"WARNING: LuaCAO::addToScene(): m_mesh != NULL"
551                                 <<std::endl;
552                 return;
553         }
554         
555         updateNodePos();
556 }
557
558 void LuaCAO::addToMesh(const char *image, v3f *corners, bool backface_culling)
559 {
560         dstream<<"INFO: addToMesh called"<<std::endl;
561
562         video::IVideoDriver* driver = m_smgr->getVideoDriver();
563         
564         assert(m_mesh);
565                 
566         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
567         video::SColor c(255,255,255,255);
568         video::S3DVertex vertices[4] =
569         {
570                 video::S3DVertex(corners[0], v3f(0,0,0), c, v2f(0,1)),
571                 video::S3DVertex(corners[1], v3f(0,0,0), c, v2f(1,1)),
572                 video::S3DVertex(corners[2], v3f(0,0,0), c, v2f(1,0)),
573                 video::S3DVertex(corners[3], v3f(0,0,0), c, v2f(0,0)),
574                 /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
575                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
576                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
577                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
578         };
579         u16 indices[] = {0,1,2,2,3,0};
580         buf->append(vertices, 4, indices, 6);
581         // Set material
582         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
583         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, backface_culling);
584         buf->getMaterial().setTexture
585                         (0, driver->getTexture(porting::getDataPath(image).c_str()));
586         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
587         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
588         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
589         // Add to mesh
590         m_mesh->addMeshBuffer(buf);
591         buf->drop();
592         // Reset mesh
593         if(m_node)
594                 m_node->setMesh(m_mesh);
595 }
596
597 void LuaCAO::clearMesh()
598 {
599         if(m_node)
600         {
601                 m_node->setMesh(NULL);
602         }
603         
604         if(m_mesh)
605         {
606                 m_mesh->drop();
607                 m_mesh = NULL;
608         }
609 }
610
611 void LuaCAO::removeFromScene()
612 {
613         if(m_node == NULL)
614                 return;
615         
616         if(m_node)
617         {
618                 m_node->remove();
619                 m_node = NULL;
620         }
621         if(m_mesh)
622         {
623                 m_mesh->drop();
624                 m_mesh = NULL;
625         }
626
627         m_smgr = NULL;
628 }
629
630 void LuaCAO::updateLight(u8 light_at_pos)
631 {
632 }
633
634 v3s16 LuaCAO::getLightPosition()
635 {
636         return floatToInt(m_position, BS);
637 }
638
639 void LuaCAO::updateNodePos()
640 {
641         if(m_node == NULL)
642                 return;
643
644         m_node->setPosition(m_position);
645         m_node->setRotation(-m_rotation);
646 }
647
648 void LuaCAO::setPosition(v3f pos)
649 {
650         m_position = pos;
651         updateNodePos();
652 }
653
654 v3f LuaCAO::getPosition()
655 {
656         return m_position;
657 }
658
659 void LuaCAO::setRotation(v3f rot)
660 {
661         m_rotation = rot;
662         updateNodePos();
663 }
664
665 v3f LuaCAO::getRotation()
666 {
667         return m_rotation;
668 }
669
670