]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_nodemeta.cpp
4368a8c50ba3af2377019cef07945fcc1c98f836
[dragonfireclient.git] / src / script / lua_api / l_nodemeta.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 "lua_api/l_nodemeta.h"
21 #include "lua_api/l_internal.h"
22 #include "lua_api/l_inventory.h"
23 #include "common/c_content.h"
24 #include "serverenvironment.h"
25 #include "map.h"
26 #include "server.h"
27
28 /*
29         NodeMetaRef
30 */
31 NodeMetaRef* NodeMetaRef::checkobject(lua_State *L, int narg)
32 {
33         luaL_checktype(L, narg, LUA_TUSERDATA);
34         void *ud = luaL_checkudata(L, narg, className);
35         if(!ud) luaL_typerror(L, narg, className);
36         return *(NodeMetaRef**)ud;  // unbox pointer
37 }
38
39 Metadata* NodeMetaRef::getmeta(bool auto_create)
40 {
41         if (m_is_local)
42                 return m_meta;
43
44         NodeMetadata *meta = m_env->getMap().getNodeMetadata(m_p);
45         if (meta == NULL && auto_create) {
46                 meta = new NodeMetadata(m_env->getGameDef()->idef());
47                 if (!m_env->getMap().setNodeMetadata(m_p, meta)) {
48                         delete meta;
49                         return NULL;
50                 }
51         }
52         return meta;
53 }
54
55 void NodeMetaRef::clearMeta()
56 {
57         m_env->getMap().removeNodeMetadata(m_p);
58 }
59
60 void NodeMetaRef::reportMetadataChange()
61 {
62         // NOTE: This same code is in rollback_interface.cpp
63         // Inform other things that the metadata has changed
64         v3s16 blockpos = getNodeBlockPos(m_p);
65         MapEditEvent event;
66         event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
67         event.p = blockpos;
68         m_env->getMap().dispatchEvent(&event);
69         // Set the block to be saved
70         MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
71         if (block) {
72                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
73                         MOD_REASON_REPORT_META_CHANGE);
74         }
75 }
76
77 // Exported functions
78
79 // garbage collector
80 int NodeMetaRef::gc_object(lua_State *L) {
81         NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1));
82         delete o;
83         return 0;
84 }
85
86 // get_inventory(self)
87 int NodeMetaRef::l_get_inventory(lua_State *L)
88 {
89         MAP_LOCK_REQUIRED;
90
91         NodeMetaRef *ref = checkobject(L, 1);
92         ref->getmeta(true);  // try to ensure the metadata exists
93         InvRef::createNodeMeta(L, ref->m_p);
94         return 1;
95 }
96
97 void NodeMetaRef::handleToTable(lua_State *L, Metadata *_meta)
98 {
99         // fields
100         MetaDataRef::handleToTable(L, _meta);
101
102         NodeMetadata *meta = (NodeMetadata*) _meta;
103
104         // inventory
105         lua_newtable(L);
106         Inventory *inv = meta->getInventory();
107         if (inv) {
108                 std::vector<const InventoryList *> lists = inv->getLists();
109                 for(std::vector<const InventoryList *>::const_iterator
110                                 i = lists.begin(); i != lists.end(); i++) {
111                         push_inventory_list(L, inv, (*i)->getName().c_str());
112                         lua_setfield(L, -2, (*i)->getName().c_str());
113                 }
114         }
115         lua_setfield(L, -2, "inventory");
116 }
117
118 // from_table(self, table)
119 bool NodeMetaRef::handleFromTable(lua_State *L, int table, Metadata *_meta)
120 {
121         // fields
122         if (!MetaDataRef::handleFromTable(L, table, _meta))
123                 return false;
124
125         NodeMetadata *meta = (NodeMetadata*) _meta;
126
127         // inventory
128         Inventory *inv = meta->getInventory();
129         lua_getfield(L, table, "inventory");
130         if (lua_istable(L, -1)) {
131                 int inventorytable = lua_gettop(L);
132                 lua_pushnil(L);
133                 while (lua_next(L, inventorytable) != 0) {
134                         // key at index -2 and value at index -1
135                         std::string name = lua_tostring(L, -2);
136                         read_inventory_list(L, -1, inv, name.c_str(), getServer(L));
137                         lua_pop(L, 1); // Remove value, keep key for next iteration
138                 }
139                 lua_pop(L, 1);
140         }
141
142         return true;
143 }
144
145
146 NodeMetaRef::NodeMetaRef(v3s16 p, ServerEnvironment *env):
147         m_p(p),
148         m_env(env),
149         m_is_local(false)
150 {
151 }
152
153 NodeMetaRef::NodeMetaRef(Metadata *meta):
154         m_meta(meta),
155         m_is_local(true)
156 {
157 }
158
159 NodeMetaRef::~NodeMetaRef()
160 {
161 }
162
163 // Creates an NodeMetaRef and leaves it on top of stack
164 // Not callable from Lua; all references are created on the C side.
165 void NodeMetaRef::create(lua_State *L, v3s16 p, ServerEnvironment *env)
166 {
167         NodeMetaRef *o = new NodeMetaRef(p, env);
168         //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
169         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
170         luaL_getmetatable(L, className);
171         lua_setmetatable(L, -2);
172 }
173
174 // Client-sided version of the above
175 void NodeMetaRef::createClient(lua_State *L, Metadata *meta)
176 {
177         NodeMetaRef *o = new NodeMetaRef(meta);
178         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
179         luaL_getmetatable(L, className);
180         lua_setmetatable(L, -2);
181 }
182
183 const char NodeMetaRef::className[] = "NodeMetaRef";
184 void NodeMetaRef::RegisterCommon(lua_State *L)
185 {
186         lua_newtable(L);
187         int methodtable = lua_gettop(L);
188         luaL_newmetatable(L, className);
189         int metatable = lua_gettop(L);
190
191         lua_pushliteral(L, "__metatable");
192         lua_pushvalue(L, methodtable);
193         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
194
195         lua_pushliteral(L, "metadata_class");
196         lua_pushlstring(L, className, strlen(className));
197         lua_settable(L, metatable);
198
199         lua_pushliteral(L, "__index");
200         lua_pushvalue(L, methodtable);
201         lua_settable(L, metatable);
202
203         lua_pushliteral(L, "__gc");
204         lua_pushcfunction(L, gc_object);
205         lua_settable(L, metatable);
206
207         lua_pop(L, 1);  // drop metatable
208 }
209
210 void NodeMetaRef::Register(lua_State *L)
211 {
212         RegisterCommon(L);
213         luaL_openlib(L, 0, methodsServer, 0);  // fill methodtable
214         lua_pop(L, 1);  // drop methodtable
215 }
216
217
218 const luaL_reg NodeMetaRef::methodsServer[] = {
219         luamethod(MetaDataRef, get_string),
220         luamethod(MetaDataRef, set_string),
221         luamethod(MetaDataRef, get_int),
222         luamethod(MetaDataRef, set_int),
223         luamethod(MetaDataRef, get_float),
224         luamethod(MetaDataRef, set_float),
225         luamethod(MetaDataRef, to_table),
226         luamethod(MetaDataRef, from_table),
227         luamethod(NodeMetaRef, get_inventory),
228         {0,0}
229 };
230
231
232 void NodeMetaRef::RegisterClient(lua_State *L)
233 {
234         RegisterCommon(L);
235         luaL_openlib(L, 0, methodsClient, 0);  // fill methodtable
236         lua_pop(L, 1);  // drop methodtable
237 }
238
239
240 const luaL_reg NodeMetaRef::methodsClient[] = {
241         luamethod(MetaDataRef, get_string),
242         luamethod(MetaDataRef, get_int),
243         luamethod(MetaDataRef, get_float),
244         luamethod(MetaDataRef, to_table),
245         {0,0}
246 };