Line data Source code
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_converter.h"
24 : #include "common/c_content.h"
25 : #include "environment.h"
26 : #include "map.h"
27 : #include "nodemetadata.h"
28 :
29 :
30 :
31 : /*
32 : NodeMetaRef
33 : */
34 0 : NodeMetaRef* NodeMetaRef::checkobject(lua_State *L, int narg)
35 : {
36 0 : luaL_checktype(L, narg, LUA_TUSERDATA);
37 0 : void *ud = luaL_checkudata(L, narg, className);
38 0 : if(!ud) luaL_typerror(L, narg, className);
39 0 : return *(NodeMetaRef**)ud; // unbox pointer
40 : }
41 :
42 0 : NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create)
43 : {
44 0 : NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
45 0 : if(meta == NULL && auto_create) {
46 0 : meta = new NodeMetadata(ref->m_env->getGameDef());
47 0 : if(!ref->m_env->getMap().setNodeMetadata(ref->m_p, meta)) {
48 0 : delete meta;
49 0 : return NULL;
50 : }
51 : }
52 0 : return meta;
53 : }
54 :
55 0 : void NodeMetaRef::reportMetadataChange(NodeMetaRef *ref)
56 : {
57 : // NOTE: This same code is in rollback_interface.cpp
58 : // Inform other things that the metadata has changed
59 0 : v3s16 blockpos = getNodeBlockPos(ref->m_p);
60 0 : MapEditEvent event;
61 0 : event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
62 0 : event.p = blockpos;
63 0 : ref->m_env->getMap().dispatchEvent(&event);
64 : // Set the block to be saved
65 0 : MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
66 0 : if (block) {
67 : block->raiseModified(MOD_STATE_WRITE_NEEDED,
68 0 : MOD_REASON_REPORT_META_CHANGE);
69 : }
70 0 : }
71 :
72 : // Exported functions
73 :
74 : // garbage collector
75 0 : int NodeMetaRef::gc_object(lua_State *L) {
76 0 : NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1));
77 0 : delete o;
78 0 : return 0;
79 : }
80 :
81 : // get_string(self, name)
82 0 : int NodeMetaRef::l_get_string(lua_State *L)
83 : {
84 0 : NodeMetaRef *ref = checkobject(L, 1);
85 0 : std::string name = luaL_checkstring(L, 2);
86 :
87 0 : NodeMetadata *meta = getmeta(ref, false);
88 0 : if(meta == NULL){
89 0 : lua_pushlstring(L, "", 0);
90 0 : return 1;
91 : }
92 0 : std::string str = meta->getString(name);
93 0 : lua_pushlstring(L, str.c_str(), str.size());
94 0 : return 1;
95 : }
96 :
97 : // set_string(self, name, var)
98 0 : int NodeMetaRef::l_set_string(lua_State *L)
99 : {
100 0 : NodeMetaRef *ref = checkobject(L, 1);
101 0 : std::string name = luaL_checkstring(L, 2);
102 0 : size_t len = 0;
103 0 : const char *s = lua_tolstring(L, 3, &len);
104 0 : std::string str(s, len);
105 :
106 0 : NodeMetadata *meta = getmeta(ref, !str.empty());
107 0 : if(meta == NULL || str == meta->getString(name))
108 0 : return 0;
109 0 : meta->setString(name, str);
110 0 : reportMetadataChange(ref);
111 0 : return 0;
112 : }
113 :
114 : // get_int(self, name)
115 0 : int NodeMetaRef::l_get_int(lua_State *L)
116 : {
117 0 : NodeMetaRef *ref = checkobject(L, 1);
118 0 : std::string name = lua_tostring(L, 2);
119 :
120 0 : NodeMetadata *meta = getmeta(ref, false);
121 0 : if(meta == NULL){
122 0 : lua_pushnumber(L, 0);
123 0 : return 1;
124 : }
125 0 : std::string str = meta->getString(name);
126 0 : lua_pushnumber(L, stoi(str));
127 0 : return 1;
128 : }
129 :
130 : // set_int(self, name, var)
131 0 : int NodeMetaRef::l_set_int(lua_State *L)
132 : {
133 0 : NodeMetaRef *ref = checkobject(L, 1);
134 0 : std::string name = lua_tostring(L, 2);
135 0 : int a = lua_tointeger(L, 3);
136 0 : std::string str = itos(a);
137 :
138 0 : NodeMetadata *meta = getmeta(ref, true);
139 0 : if(meta == NULL || str == meta->getString(name))
140 0 : return 0;
141 0 : meta->setString(name, str);
142 0 : reportMetadataChange(ref);
143 0 : return 0;
144 : }
145 :
146 : // get_float(self, name)
147 0 : int NodeMetaRef::l_get_float(lua_State *L)
148 : {
149 0 : NodeMetaRef *ref = checkobject(L, 1);
150 0 : std::string name = lua_tostring(L, 2);
151 :
152 0 : NodeMetadata *meta = getmeta(ref, false);
153 0 : if(meta == NULL){
154 0 : lua_pushnumber(L, 0);
155 0 : return 1;
156 : }
157 0 : std::string str = meta->getString(name);
158 0 : lua_pushnumber(L, stof(str));
159 0 : return 1;
160 : }
161 :
162 : // set_float(self, name, var)
163 0 : int NodeMetaRef::l_set_float(lua_State *L)
164 : {
165 0 : NodeMetaRef *ref = checkobject(L, 1);
166 0 : std::string name = lua_tostring(L, 2);
167 0 : float a = lua_tonumber(L, 3);
168 0 : std::string str = ftos(a);
169 :
170 0 : NodeMetadata *meta = getmeta(ref, true);
171 0 : if(meta == NULL || str == meta->getString(name))
172 0 : return 0;
173 0 : meta->setString(name, str);
174 0 : reportMetadataChange(ref);
175 0 : return 0;
176 : }
177 :
178 : // get_inventory(self)
179 0 : int NodeMetaRef::l_get_inventory(lua_State *L)
180 : {
181 0 : NodeMetaRef *ref = checkobject(L, 1);
182 0 : getmeta(ref, true); // try to ensure the metadata exists
183 0 : InvRef::createNodeMeta(L, ref->m_p);
184 0 : return 1;
185 : }
186 :
187 : // to_table(self)
188 0 : int NodeMetaRef::l_to_table(lua_State *L)
189 : {
190 0 : NodeMetaRef *ref = checkobject(L, 1);
191 :
192 0 : NodeMetadata *meta = getmeta(ref, true);
193 0 : if (meta == NULL) {
194 0 : lua_pushnil(L);
195 0 : return 1;
196 : }
197 0 : lua_newtable(L);
198 :
199 : // fields
200 0 : lua_newtable(L);
201 : {
202 0 : StringMap fields = meta->getStrings();
203 0 : for (StringMap::const_iterator
204 0 : it = fields.begin(); it != fields.end(); ++it) {
205 0 : const std::string &name = it->first;
206 0 : const std::string &value = it->second;
207 0 : lua_pushlstring(L, name.c_str(), name.size());
208 0 : lua_pushlstring(L, value.c_str(), value.size());
209 0 : lua_settable(L, -3);
210 : }
211 : }
212 0 : lua_setfield(L, -2, "fields");
213 :
214 : // inventory
215 0 : lua_newtable(L);
216 0 : Inventory *inv = meta->getInventory();
217 0 : if (inv) {
218 0 : std::vector<const InventoryList *> lists = inv->getLists();
219 0 : for(std::vector<const InventoryList *>::const_iterator
220 0 : i = lists.begin(); i != lists.end(); i++) {
221 0 : push_inventory_list(L, inv, (*i)->getName().c_str());
222 0 : lua_setfield(L, -2, (*i)->getName().c_str());
223 : }
224 : }
225 0 : lua_setfield(L, -2, "inventory");
226 0 : return 1;
227 : }
228 :
229 : // from_table(self, table)
230 0 : int NodeMetaRef::l_from_table(lua_State *L)
231 : {
232 0 : NodeMetaRef *ref = checkobject(L, 1);
233 0 : int base = 2;
234 :
235 : // clear old metadata first
236 0 : ref->m_env->getMap().removeNodeMetadata(ref->m_p);
237 :
238 0 : if(lua_isnil(L, base)){
239 : // No metadata
240 0 : lua_pushboolean(L, true);
241 0 : return 1;
242 : }
243 :
244 : // Create new metadata
245 0 : NodeMetadata *meta = getmeta(ref, true);
246 0 : if(meta == NULL){
247 0 : lua_pushboolean(L, false);
248 0 : return 1;
249 : }
250 : // Set fields
251 0 : lua_getfield(L, base, "fields");
252 0 : int fieldstable = lua_gettop(L);
253 0 : lua_pushnil(L);
254 0 : while(lua_next(L, fieldstable) != 0){
255 : // key at index -2 and value at index -1
256 0 : std::string name = lua_tostring(L, -2);
257 : size_t cl;
258 0 : const char *cs = lua_tolstring(L, -1, &cl);
259 0 : std::string value(cs, cl);
260 0 : meta->setString(name, value);
261 0 : lua_pop(L, 1); // removes value, keeps key for next iteration
262 : }
263 : // Set inventory
264 0 : Inventory *inv = meta->getInventory();
265 0 : lua_getfield(L, base, "inventory");
266 0 : int inventorytable = lua_gettop(L);
267 0 : lua_pushnil(L);
268 0 : while(lua_next(L, inventorytable) != 0){
269 : // key at index -2 and value at index -1
270 0 : std::string name = lua_tostring(L, -2);
271 0 : read_inventory_list(L, -1, inv, name.c_str(), getServer(L));
272 0 : lua_pop(L, 1); // removes value, keeps key for next iteration
273 : }
274 0 : reportMetadataChange(ref);
275 0 : lua_pushboolean(L, true);
276 0 : return 1;
277 : }
278 :
279 :
280 0 : NodeMetaRef::NodeMetaRef(v3s16 p, ServerEnvironment *env):
281 : m_p(p),
282 0 : m_env(env)
283 : {
284 0 : }
285 :
286 0 : NodeMetaRef::~NodeMetaRef()
287 : {
288 0 : }
289 :
290 : // Creates an NodeMetaRef and leaves it on top of stack
291 : // Not callable from Lua; all references are created on the C side.
292 0 : void NodeMetaRef::create(lua_State *L, v3s16 p, ServerEnvironment *env)
293 : {
294 0 : NodeMetaRef *o = new NodeMetaRef(p, env);
295 : //infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
296 0 : *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
297 0 : luaL_getmetatable(L, className);
298 0 : lua_setmetatable(L, -2);
299 0 : }
300 :
301 0 : void NodeMetaRef::Register(lua_State *L)
302 : {
303 0 : lua_newtable(L);
304 0 : int methodtable = lua_gettop(L);
305 0 : luaL_newmetatable(L, className);
306 0 : int metatable = lua_gettop(L);
307 :
308 0 : lua_pushliteral(L, "__metatable");
309 0 : lua_pushvalue(L, methodtable);
310 0 : lua_settable(L, metatable); // hide metatable from Lua getmetatable()
311 :
312 0 : lua_pushliteral(L, "__index");
313 0 : lua_pushvalue(L, methodtable);
314 0 : lua_settable(L, metatable);
315 :
316 0 : lua_pushliteral(L, "__gc");
317 0 : lua_pushcfunction(L, gc_object);
318 0 : lua_settable(L, metatable);
319 :
320 0 : lua_pop(L, 1); // drop metatable
321 :
322 0 : luaL_openlib(L, 0, methods, 0); // fill methodtable
323 0 : lua_pop(L, 1); // drop methodtable
324 :
325 : // Cannot be created from Lua
326 : //lua_register(L, className, create_object);
327 0 : }
328 :
329 : const char NodeMetaRef::className[] = "NodeMetaRef";
330 : const luaL_reg NodeMetaRef::methods[] = {
331 : luamethod(NodeMetaRef, get_string),
332 : luamethod(NodeMetaRef, set_string),
333 : luamethod(NodeMetaRef, get_int),
334 : luamethod(NodeMetaRef, set_int),
335 : luamethod(NodeMetaRef, get_float),
336 : luamethod(NodeMetaRef, set_float),
337 : luamethod(NodeMetaRef, get_inventory),
338 : luamethod(NodeMetaRef, to_table),
339 : luamethod(NodeMetaRef, from_table),
340 : {0,0}
341 3 : };
|