]> git.lizzy.rs Git - minetest.git/blob - src/script/lua_api/l_nodemeta.cpp
f4edc17900da52524acf97788d090dad94a6e0a5
[minetest.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 "mapblock.h"
27 #include "server.h"
28
29 /*
30         NodeMetaRef
31 */
32
33 IMetadata* NodeMetaRef::getmeta(bool auto_create)
34 {
35         if (m_is_local)
36                 return m_local_meta;
37
38         NodeMetadata *meta = m_env->getMap().getNodeMetadata(m_p);
39         if (meta == NULL && auto_create) {
40                 meta = new NodeMetadata(m_env->getGameDef()->idef());
41                 if (!m_env->getMap().setNodeMetadata(m_p, meta)) {
42                         delete meta;
43                         return NULL;
44                 }
45         }
46         return meta;
47 }
48
49 void NodeMetaRef::clearMeta()
50 {
51         SANITY_CHECK(!m_is_local);
52         m_env->getMap().removeNodeMetadata(m_p);
53 }
54
55 void NodeMetaRef::reportMetadataChange(const std::string *name)
56 {
57         SANITY_CHECK(!m_is_local);
58         // Inform other things that the metadata has changed
59         NodeMetadata *meta = dynamic_cast<NodeMetadata*>(getmeta(false));
60
61         // If the metadata is now empty, get rid of it
62         if (meta && meta->empty()) {
63                 clearMeta();
64                 meta = nullptr;
65         }
66
67         MapEditEvent event;
68         event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
69         event.p = m_p;
70         event.is_private_change = name && meta && meta->isPrivate(*name);
71         m_env->getMap().dispatchEvent(event);
72 }
73
74 // Exported functions
75
76 // get_inventory(self)
77 int NodeMetaRef::l_get_inventory(lua_State *L)
78 {
79         MAP_LOCK_REQUIRED;
80
81         NodeMetaRef *ref = checkObject<NodeMetaRef>(L, 1);
82         ref->getmeta(true);  // try to ensure the metadata exists
83
84         InventoryLocation loc;
85         loc.setNodeMeta(ref->m_p);
86         InvRef::create(L, loc);
87         return 1;
88 }
89
90 // mark_as_private(self, <string> or {<string>, <string>, ...})
91 int NodeMetaRef::l_mark_as_private(lua_State *L)
92 {
93         MAP_LOCK_REQUIRED;
94
95         NodeMetaRef *ref = checkObject<NodeMetaRef>(L, 1);
96         NodeMetadata *meta = dynamic_cast<NodeMetadata*>(ref->getmeta(true));
97         assert(meta);
98
99         if (lua_istable(L, 2)) {
100                 lua_pushnil(L);
101                 while (lua_next(L, 2) != 0) {
102                         // key at index -2 and value at index -1
103                         luaL_checktype(L, -1, LUA_TSTRING);
104                         meta->markPrivate(readParam<std::string>(L, -1), true);
105                         // removes value, keeps key for next iteration
106                         lua_pop(L, 1);
107                 }
108         } else if (lua_isstring(L, 2)) {
109                 meta->markPrivate(readParam<std::string>(L, 2), true);
110         }
111         ref->reportMetadataChange();
112
113         return 0;
114 }
115
116 void NodeMetaRef::handleToTable(lua_State *L, IMetadata *_meta)
117 {
118         // fields
119         MetaDataRef::handleToTable(L, _meta);
120
121         NodeMetadata *meta = dynamic_cast<NodeMetadata*>(_meta);
122         assert(meta);
123
124         // inventory
125         Inventory *inv = meta->getInventory();
126         if (inv) {
127                 push_inventory_lists(L, *inv);
128         } else {
129                 lua_newtable(L);
130         }
131         lua_setfield(L, -2, "inventory");
132 }
133
134 // from_table(self, table)
135 bool NodeMetaRef::handleFromTable(lua_State *L, int table, IMetadata *_meta)
136 {
137         // fields
138         if (!MetaDataRef::handleFromTable(L, table, _meta))
139                 return false;
140
141         NodeMetadata *meta = dynamic_cast<NodeMetadata*>(_meta);
142         assert(meta);
143
144         // inventory
145         Inventory *inv = meta->getInventory();
146         lua_getfield(L, table, "inventory");
147         if (lua_istable(L, -1)) {
148                 int inventorytable = lua_gettop(L);
149                 lua_pushnil(L);
150                 while (lua_next(L, inventorytable) != 0) {
151                         // key at index -2 and value at index -1
152                         std::string name = luaL_checkstring(L, -2);
153                         read_inventory_list(L, -1, inv, name.c_str(), getServer(L));
154                         lua_pop(L, 1); // Remove value, keep key for next iteration
155                 }
156                 lua_pop(L, 1);
157         }
158
159         return true;
160 }
161
162
163 NodeMetaRef::NodeMetaRef(v3s16 p, ServerEnvironment *env):
164         m_p(p),
165         m_env(env)
166 {
167 }
168
169 NodeMetaRef::NodeMetaRef(IMetadata *meta):
170         m_is_local(true),
171         m_local_meta(meta)
172 {
173 }
174
175 // Creates an NodeMetaRef and leaves it on top of stack
176 // Not callable from Lua; all references are created on the C side.
177 void NodeMetaRef::create(lua_State *L, v3s16 p, ServerEnvironment *env)
178 {
179         NodeMetaRef *o = new NodeMetaRef(p, env);
180         //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
181         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
182         luaL_getmetatable(L, className);
183         lua_setmetatable(L, -2);
184 }
185
186 // Client-sided version of the above
187 void NodeMetaRef::createClient(lua_State *L, IMetadata *meta)
188 {
189         NodeMetaRef *o = new NodeMetaRef(meta);
190         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
191         luaL_getmetatable(L, className);
192         lua_setmetatable(L, -2);
193 }
194
195 const char NodeMetaRef::className[] = "NodeMetaRef";
196
197 void NodeMetaRef::Register(lua_State *L)
198 {
199         registerMetadataClass(L, className, methodsServer);
200 }
201
202
203 const luaL_Reg NodeMetaRef::methodsServer[] = {
204         luamethod(MetaDataRef, contains),
205         luamethod(MetaDataRef, get),
206         luamethod(MetaDataRef, get_string),
207         luamethod(MetaDataRef, set_string),
208         luamethod(MetaDataRef, get_int),
209         luamethod(MetaDataRef, set_int),
210         luamethod(MetaDataRef, get_float),
211         luamethod(MetaDataRef, set_float),
212         luamethod(MetaDataRef, get_keys),
213         luamethod(MetaDataRef, to_table),
214         luamethod(MetaDataRef, from_table),
215         luamethod(NodeMetaRef, get_inventory),
216         luamethod(NodeMetaRef, mark_as_private),
217         luamethod(MetaDataRef, equals),
218         {0,0}
219 };
220
221
222 void NodeMetaRef::RegisterClient(lua_State *L)
223 {
224         registerMetadataClass(L, className, methodsClient);
225 }
226
227
228 const luaL_Reg NodeMetaRef::methodsClient[] = {
229         luamethod(MetaDataRef, contains),
230         luamethod(MetaDataRef, get),
231         luamethod(MetaDataRef, get_string),
232         luamethod(MetaDataRef, get_int),
233         luamethod(MetaDataRef, get_float),
234         luamethod(MetaDataRef, get_keys),
235         luamethod(MetaDataRef, to_table),
236         {0,0}
237 };