]> git.lizzy.rs Git - dragonfireclient.git/blob - src/serverobject.cpp
mainly work on object scripting api
[dragonfireclient.git] / src / serverobject.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 "serverobject.h"
21 #include <fstream>
22 #include "environment.h"
23
24 ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos):
25         ActiveObject(id),
26         m_known_by_count(0),
27         m_removed(false),
28         m_env(env),
29         m_base_position(pos)
30 {
31 }
32
33 ServerActiveObject::~ServerActiveObject()
34 {
35 }
36
37 /*
38         TestSAO
39 */
40
41 TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
42         ServerActiveObject(env, id, pos),
43         m_timer1(0),
44         m_age(0)
45 {
46 }
47
48 void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
49 {
50         m_age += dtime;
51         if(m_age > 10)
52         {
53                 m_removed = true;
54                 return;
55         }
56
57         m_base_position.Y += dtime * BS * 2;
58         if(m_base_position.Y > 8*BS)
59                 m_base_position.Y = 2*BS;
60
61         m_timer1 -= dtime;
62         if(m_timer1 < 0.0)
63         {
64                 m_timer1 += 0.125;
65                 //dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
66
67                 std::string data;
68
69                 data += itos(0); // 0 = position
70                 data += " ";
71                 data += itos(m_base_position.X);
72                 data += " ";
73                 data += itos(m_base_position.Y);
74                 data += " ";
75                 data += itos(m_base_position.Z);
76
77                 ActiveObjectMessage aom(getId(), false, data);
78                 messages.push_back(aom);
79         }
80 }
81
82 /*
83         LuaSAO
84 */
85
86 extern "C"{
87 #include "lstring.h"
88 }
89
90 /*
91         Callbacks in script:
92         
93         on_step(self, dtime)
94         on_get_client_init_data(self)
95         on_get_server_init_data(self)
96         on_initialize(self, data)
97 */
98
99 /*
100         object_set_base_position(self, {X=,Y=,Z=})
101 */
102 static int lf_object_set_base_position(lua_State *L)
103 {
104         // 2: position
105         assert(lua_istable(L, -1));
106         lua_pushstring(L, "X");
107         lua_gettable(L, -2);
108         lua_Number x = lua_tonumber(L, -1);
109         lua_pop(L, 1);
110         lua_pushstring(L, "Y");
111         lua_gettable(L, -2);
112         lua_Number y = lua_tonumber(L, -1);
113         lua_pop(L, 1);
114         lua_pushstring(L, "Z");
115         lua_gettable(L, -2);
116         lua_Number z = lua_tonumber(L, -1);
117         lua_pop(L, 1);
118         lua_pop(L, 1);
119         // 1: self
120         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
121         lua_pop(L, 1);
122         
123         assert(self);
124         
125         self->setBasePosition(v3f(x*BS,y*BS,z*BS));
126         
127         return 0; // Number of return values
128 }
129
130 /*
131         {X=,Y=,Z=} object_get_base_position(self)
132 */
133 static int lf_object_get_base_position(lua_State *L)
134 {
135         // 1: self
136         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
137         lua_pop(L, 1);
138         
139         assert(self);
140         
141         v3f pos = self->getBasePosition();
142
143         lua_newtable(L);
144
145         lua_pushstring(L, "X");
146         lua_pushnumber(L, pos.X/BS);
147         lua_settable(L, -3);
148
149         lua_pushstring(L, "Y");
150         lua_pushnumber(L, pos.Y/BS);
151         lua_settable(L, -3);
152
153         lua_pushstring(L, "Z");
154         lua_pushnumber(L, pos.Z/BS);
155         lua_settable(L, -3);
156
157         return 1; // Number of return values
158 }
159
160 /*
161         object_add_message(self, string data)
162         lf = luafunc
163 */
164 static int lf_object_add_message(lua_State *L)
165 {
166         // 2: data
167         size_t datalen = 0;
168         const char *data_c = lua_tolstring(L, -1, &datalen);
169         lua_pop(L, 1);
170         // 1: self
171         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
172         lua_pop(L, 1);
173         
174         assert(self);
175         assert(data_c);
176         
177         std::string data(data_c, datalen);
178         //dstream<<"object_add_message: data="<<data<<std::endl;
179         
180         // Create message and add to queue
181         ActiveObjectMessage aom(self->getId());
182         aom.reliable = true;
183         aom.datastring = data;
184         self->m_message_queue.push_back(aom);
185
186         return 0; // Number of return values
187 }
188
189 /*
190         object_get_node(self, {X=,Y=,Z=})
191 */
192 static int lf_object_get_node(lua_State *L)
193 {
194         // 2: position
195         assert(lua_istable(L, -1));
196         lua_pushstring(L, "X");
197         lua_gettable(L, -2);
198         lua_Number x = lua_tonumber(L, -1);
199         lua_pop(L, 1);
200         lua_pushstring(L, "Y");
201         lua_gettable(L, -2);
202         lua_Number y = lua_tonumber(L, -1);
203         lua_pop(L, 1);
204         lua_pushstring(L, "Z");
205         lua_gettable(L, -2);
206         lua_Number z = lua_tonumber(L, -1);
207         lua_pop(L, 1);
208         lua_pop(L, 1);
209         // 1: self
210         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
211         lua_pop(L, 1);
212         
213         assert(self);
214
215         v3s16 pos = floatToInt(v3f(x,y,z), 1.0);
216
217         /*dstream<<"Checking node from pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z
218                         <<")"<<std::endl;*/
219         
220         // Get the node
221         MapNode n(CONTENT_IGNORE);
222         n = self->getEnv()->getMap().getNodeNoEx(pos);
223
224         // Create a table with some data about the node
225         lua_newtable(L);
226         lua_pushstring(L, "content");
227         lua_pushinteger(L, n.d);
228         lua_settable(L, -3);
229         lua_pushstring(L, "param1");
230         lua_pushinteger(L, n.param);
231         lua_settable(L, -3);
232         lua_pushstring(L, "param2");
233         lua_pushinteger(L, n.param2);
234         lua_settable(L, -3);
235         
236         // Return the table
237         return 1;
238 }
239
240 #if 0
241 /*
242         get_node_features(node)
243         node = {content=,param1=,param2=}
244 */
245 static int lf_get_node_features(lua_State *L)
246 {
247         MapNode n;
248         
249         // 1: node
250         assert(lua_istable(L, -1));
251         lua_pushstring(L, "content");
252         lua_gettable(L, -2);
253         n.d = lua_tointeger(L, -1);
254         lua_pop(L, 1);
255         lua_pushstring(L, "param1");
256         lua_gettable(L, -2);
257         n.param = lua_tointeger(L, -1);
258         lua_pop(L, 1);
259         lua_pushstring(L, "param2");
260         lua_gettable(L, -2);
261         n.param2 = lua_tointeger(L, -1);
262         lua_pop(L, 1);
263         lua_pop(L, 1);
264
265         ContentFeatures &f = content_features(n.d);
266
267 }
268 #endif
269
270 /*
271         get_content_features(content)
272 */
273 static int lf_get_content_features(lua_State *L)
274 {
275         MapNode n;
276         
277         // 1: content
278         n.d = lua_tointeger(L, -1);
279         lua_pop(L, 1);
280         
281         // Get and return information
282         ContentFeatures &f = content_features(n.d);
283         
284         lua_newtable(L);
285         lua_pushstring(L, "walkable");
286         lua_pushboolean(L, f.walkable);
287         lua_settable(L, -3);
288         lua_pushstring(L, "diggable");
289         lua_pushboolean(L, f.diggable);
290         lua_settable(L, -3);
291         lua_pushstring(L, "buildable_to");
292         lua_pushboolean(L, f.buildable_to);
293         lua_settable(L, -3);
294         
295         return 1;
296 }
297
298 /*
299         bool object_dig_node(self, {X=,Y=,Z=})
300         Return true on success
301 */
302 static int lf_object_dig_node(lua_State *L)
303 {
304         // 2: position
305         assert(lua_istable(L, -1));
306         lua_pushstring(L, "X");
307         lua_gettable(L, -2);
308         lua_Number x = lua_tonumber(L, -1);
309         lua_pop(L, 1);
310         lua_pushstring(L, "Y");
311         lua_gettable(L, -2);
312         lua_Number y = lua_tonumber(L, -1);
313         lua_pop(L, 1);
314         lua_pushstring(L, "Z");
315         lua_gettable(L, -2);
316         lua_Number z = lua_tonumber(L, -1);
317         lua_pop(L, 1);
318         lua_pop(L, 1);
319         // 1: self
320         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
321         lua_pop(L, 1);
322         
323         assert(self);
324
325         v3s16 pos = floatToInt(v3f(x,y,z), 1.0);
326         
327         /*
328                 Do stuff.
329                 This gets sent to the server by the map through the edit
330                 event system.
331         */
332         bool succeeded = self->getEnv()->getMap().removeNodeWithEvent(pos);
333         
334         lua_pushboolean(L, succeeded);
335         return 1;
336 }
337
338 /*
339         bool object_place_node(self, {X=,Y=,Z=}, node)
340         node={content=,param1=,param2=}
341         param1 and param2 are optional
342         Return true on success
343 */
344 static int lf_object_place_node(lua_State *L)
345 {
346         // 3: node
347         MapNode n(CONTENT_STONE);
348         assert(lua_istable(L, -1));
349         {
350                 lua_pushstring(L, "content");
351                 lua_gettable(L, -2);
352                 if(lua_isnumber(L, -1))
353                         n.d = lua_tonumber(L, -1);
354                 lua_pop(L, 1);
355                 lua_pushstring(L, "param1");
356                 lua_gettable(L, -2);
357                 if(lua_isnumber(L, -1))
358                         n.param = lua_tonumber(L, -1);
359                 lua_pop(L, 1);
360                 lua_pushstring(L, "param2");
361                 lua_gettable(L, -2);
362                 if(lua_isnumber(L, -1))
363                         n.param2 = lua_tonumber(L, -1);
364                 lua_pop(L, 1);
365         }
366         lua_pop(L, 1);
367         // 2: position
368         assert(lua_istable(L, -1));
369         lua_pushstring(L, "X");
370         lua_gettable(L, -2);
371         lua_Number x = lua_tonumber(L, -1);
372         lua_pop(L, 1);
373         lua_pushstring(L, "Y");
374         lua_gettable(L, -2);
375         lua_Number y = lua_tonumber(L, -1);
376         lua_pop(L, 1);
377         lua_pushstring(L, "Z");
378         lua_gettable(L, -2);
379         lua_Number z = lua_tonumber(L, -1);
380         lua_pop(L, 1);
381         lua_pop(L, 1);
382         // 1: self
383         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
384         lua_pop(L, 1);
385         
386         assert(self);
387
388         v3s16 pos = floatToInt(v3f(x,y,z), 1.0);
389         
390         /*
391                 Do stuff.
392                 This gets sent to the server by the map through the edit
393                 event system.
394         */
395         bool succeeded = self->getEnv()->getMap().addNodeWithEvent(pos, n);
396
397         lua_pushboolean(L, succeeded);
398         return 1;
399 }
400
401 /*
402         object_remove(x,y,z)
403 */
404 static int lf_object_remove(lua_State *L)
405 {
406         // 1: self
407         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
408         lua_pop(L, 1);
409         
410         assert(self);
411
412         self->m_removed = true;
413
414         return 0;
415 }
416
417 /*
418         {X=,Y=,Z=} object_get_nearest_player_position(self)
419 */
420 /*static int lf_object_get_nearest_player_position(lua_State *L)
421 {
422         // 1: self
423         LuaSAO *self = (LuaSAO*)lua_touserdata(L, -1);
424         lua_pop(L, 1);
425         
426         assert(self);
427         
428         ServerEnvironment *env = self->getEnv();
429         env->
430         v3f pos = ;
431
432         lua_newtable(L);
433
434         lua_pushstring(L, "X");
435         lua_pushnumber(L, pos.X/BS);
436         lua_settable(L, -3);
437
438         lua_pushstring(L, "Y");
439         lua_pushnumber(L, pos.Y/BS);
440         lua_settable(L, -3);
441
442         lua_pushstring(L, "Z");
443         lua_pushnumber(L, pos.Z/BS);
444         lua_settable(L, -3);
445
446         return 1; // Number of return values
447 }*/
448
449 LuaSAO::LuaSAO(ServerEnvironment *env, u16 id, v3f pos):
450         ServerActiveObject(env, id, pos),
451         L(NULL)
452 {
453         dstream<<"LuaSAO::LuaSAO(): id="<<id<<std::endl;
454         L = lua_open();
455         assert(L);
456         
457         // Load libraries
458         luaopen_base(L);
459         luaopen_table(L);
460         luaopen_string(L);
461         luaopen_math(L);
462         
463         // Add globals
464         //lua_pushlightuserdata(L, this);
465         //lua_setglobal(L, "self");
466         
467         // Register functions
468         lua_register(L, "object_set_base_position", lf_object_set_base_position);
469         lua_register(L, "object_get_base_position", lf_object_get_base_position);
470         lua_register(L, "object_add_message", lf_object_add_message);
471         lua_register(L, "object_get_node", lf_object_get_node);
472         lua_register(L, "get_content_features", lf_get_content_features);
473         lua_register(L, "object_dig_node", lf_object_dig_node);
474         lua_register(L, "object_place_node", lf_object_place_node);
475         lua_register(L, "object_remove", lf_object_remove);
476 }
477
478 LuaSAO::~LuaSAO()
479 {
480         lua_close(L);
481 }
482
483 std::string LuaSAO::getClientInitializationData()
484 {
485         /*
486                 Read client-side script from file
487         */
488         
489         std::string relative_path;
490         relative_path += "luaobjects/";
491         relative_path += m_script_name;
492         relative_path += "/client.lua";
493         std::string full_path = porting::getDataPath(relative_path.c_str());
494         std::string script;
495         std::ifstream file(full_path.c_str(), std::ios::binary | std::ios::ate);
496         int size = file.tellg();
497         SharedBuffer<char> buf(size);
498         file.seekg(0, std::ios::beg);
499         file.read(&buf[0], size);
500         file.close();
501         
502         /*
503                 Create data string
504         */
505         std::string data;
506
507         // Append script
508         std::string script_string(&buf[0], buf.getSize());
509         data += serializeLongString(script_string);
510
511         /*
512                 Get data from server-side script for inclusion
513         */
514         std::string other_data;
515         
516         do{
517
518                 const char *funcname = "on_get_client_init_data";
519                 lua_getglobal(L, funcname);
520                 if(!lua_isfunction(L,-1))
521                 {
522                         lua_pop(L,1);
523                         dstream<<"WARNING: LuaSAO: Function not found: "
524                                         <<funcname<<std::endl;
525                         break;
526                 }
527                 
528                 // Parameters:
529                 // 1: self
530                 lua_pushlightuserdata(L, this);
531                 
532                 // Call (1 parameters, 1 result)
533                 if(lua_pcall(L, 1, 1, 0))
534                 {
535                         dstream<<"WARNING: LuaSAO: Error running function "
536                                         <<funcname<<": "
537                                         <<lua_tostring(L,-1)<<std::endl;
538                         break;
539                 }
540
541                 // Retrieve result
542                 if(!lua_isstring(L,-1))
543                 {
544                         dstream<<"WARNING: LuaSAO: Function "<<funcname
545                                         <<" didn't return a string"<<std::endl;
546                         break;
547                 }
548                 
549                 size_t cs_len = 0;
550                 const char *cs = lua_tolstring(L, -1, &cs_len);
551                 lua_pop(L,1);
552
553                 other_data = std::string(cs, cs_len);
554
555         }while(0);
556         
557         data += serializeLongString(other_data);
558
559         return data;
560 }
561
562 std::string LuaSAO::getServerInitializationData()
563 {
564         std::string data;
565         
566         // Script name
567         data.append(serializeString(m_script_name));
568
569         /*
570                 Get data from server-side script for inclusion
571         */
572         std::string other_data;
573         
574         do{
575
576                 const char *funcname = "on_get_server_init_data";
577                 lua_getglobal(L, funcname);
578                 if(!lua_isfunction(L,-1))
579                 {
580                         lua_pop(L,1);
581                         dstream<<"WARNING: LuaSAO: Function not found: "
582                                         <<funcname<<std::endl;
583                         break;
584                 }
585                 
586                 // Parameters:
587                 // 1: self
588                 lua_pushlightuserdata(L, this);
589                 
590                 // Call (1 parameters, 1 result)
591                 if(lua_pcall(L, 1, 1, 0))
592                 {
593                         dstream<<"WARNING: LuaSAO: Error running function "
594                                         <<funcname<<": "
595                                         <<lua_tostring(L,-1)<<std::endl;
596                         break;
597                 }
598
599                 // Retrieve result
600                 if(!lua_isstring(L,-1))
601                 {
602                         dstream<<"WARNING: LuaSAO: Function "<<funcname
603                                         <<" didn't return a string"<<std::endl;
604                         break;
605                 }
606                 
607                 size_t cs_len = 0;
608                 const char *cs = lua_tolstring(L, -1, &cs_len);
609                 lua_pop(L,1);
610
611                 other_data = std::string(cs, cs_len);
612
613         }while(0);
614         
615         data += serializeLongString(other_data);
616
617         return data;
618 }
619
620 void LuaSAO::initializeFromNothing(const std::string &script_name)
621 {
622         loadScripts(script_name);
623
624         /*
625                 Call on_initialize(self, data) in the script
626         */
627         
628         const char *funcname = "on_initialize";
629         lua_getglobal(L, funcname);
630         if(!lua_isfunction(L,-1))
631         {
632                 lua_pop(L,1);
633                 dstream<<"WARNING: LuaSAO: Function not found: "
634                                 <<funcname<<std::endl;
635                 return;
636         }
637         
638         // Parameters:
639         // 1: self
640         lua_pushlightuserdata(L, this);
641         // 2: data (other)
642         lua_pushstring(L, "");
643         
644         // Call (2 parameters, 0 result)
645         if(lua_pcall(L, 2, 0, 0))
646         {
647                 dstream<<"WARNING: LuaSAO: Error running function "
648                                 <<funcname<<": "
649                                 <<lua_tostring(L,-1)<<std::endl;
650                 return;
651         }
652 }
653
654 void LuaSAO::initializeFromSave(const std::string &data)
655 {
656         std::istringstream is(data, std::ios::binary);
657         std::string script_name = deSerializeString(is);
658         std::string other = deSerializeLongString(is);
659
660         loadScripts(script_name);
661
662         /*
663                 Call on_initialize(self, data) in the script
664         */
665         
666         const char *funcname = "on_initialize";
667         lua_getglobal(L, funcname);
668         if(!lua_isfunction(L,-1))
669         {
670                 lua_pop(L,1);
671                 dstream<<"WARNING: LuaSAO: Function not found: "
672                                 <<funcname<<std::endl;
673                 return;
674         }
675         
676         // Parameters:
677         // 1: self
678         lua_pushlightuserdata(L, this);
679         // 2: data (other)
680         lua_pushlstring(L, other.c_str(), other.size());
681         
682         // Call (2 parameters, 0 result)
683         if(lua_pcall(L, 2, 0, 0))
684         {
685                 dstream<<"WARNING: LuaSAO: Error running function "
686                                 <<funcname<<": "
687                                 <<lua_tostring(L,-1)<<std::endl;
688                 return;
689         }
690 }
691
692 void LuaSAO::loadScripts(const std::string &script_name)
693 {
694         m_script_name = script_name;
695         
696         std::string relative_path;
697         relative_path += "luaobjects/";
698         relative_path += script_name;
699         std::string server_file = relative_path + "/server.lua";
700         std::string server_path = porting::getDataPath(server_file.c_str());
701
702         // Load the file
703         int ret;
704         ret = luaL_loadfile(L, server_path.c_str());
705         if(ret)
706         {
707                 const char *message = lua_tostring(L, -1);
708                 lua_pop(L, 1);
709                 dstream<<"LuaSAO::loadScript(): lua_loadfile failed: "
710                                 <<message<<std::endl;
711                 assert(0);
712                 return;
713         }
714         ret = lua_pcall(L, 0, 0, 0);
715         if(ret)
716         {
717                 const char *message = lua_tostring(L, -1);
718                 lua_pop(L, 1);
719                 dstream<<"LuaSAO::loadScript(): lua_pcall failed: "
720                                 <<message<<std::endl;
721                 assert(0);
722                 return;
723         }
724 }
725
726 void LuaSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
727 {
728         const char *funcname = "on_step";
729         lua_getglobal(L, funcname);
730         if(!lua_isfunction(L,-1))
731         {
732                 lua_pop(L,1);
733                 dstream<<"WARNING: LuaSAO::step(): Function not found: "
734                                 <<funcname<<std::endl;
735                 return;
736         }
737         
738         // Parameters:
739         // 1: self
740         lua_pushlightuserdata(L, this);
741         // 2: dtime
742         lua_pushnumber(L, dtime);
743         
744         // Call (2 parameters, 0 result)
745         if(lua_pcall(L, 2, 0, 0))
746         {
747                 dstream<<"WARNING: LuaSAO::step(): Error running function "
748                                 <<funcname<<": "
749                                 <<lua_tostring(L,-1)<<std::endl;
750                 return;
751         }
752
753         // Move messages
754         while(m_message_queue.size() != 0)
755         {
756                 messages.push_back(m_message_queue.pop_front());
757         }
758 }
759
760
761