]> git.lizzy.rs Git - minetest.git/blob - src/content_nodemeta.cpp
ObjectRef:get_player_name, ObjectRef:inventory_set_list, ObjectRef:inventory_get_list
[minetest.git] / src / content_nodemeta.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 "content_nodemeta.h"
21
22 #include <map>
23 #include "inventory.h"
24 #include "log.h"
25 #include "utility.h"
26
27 class Inventory;
28
29 #define NODEMETA_GENERIC 1
30 #define NODEMETA_SIGN 14
31 #define NODEMETA_CHEST 15
32 #define NODEMETA_FURNACE 16
33 #define NODEMETA_LOCKABLE_CHEST 17
34
35 class SignNodeMetadata : public NodeMetadata
36 {
37 public:
38         SignNodeMetadata(IGameDef *gamedef, std::string text);
39         //~SignNodeMetadata();
40         
41         virtual u16 typeId() const;
42         virtual const char* typeName() const
43         { return "sign"; }
44         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
45         static NodeMetadata* create(IGameDef *gamedef);
46         virtual NodeMetadata* clone(IGameDef *gamedef);
47         virtual void serializeBody(std::ostream &os);
48         virtual std::string infoText();
49
50         virtual bool allowsTextInput(){ return true; }
51         virtual std::string getText(){ return m_text; }
52         virtual void setText(const std::string &t){ m_text = t; }
53
54 private:
55         std::string m_text;
56 };
57
58 class ChestNodeMetadata : public NodeMetadata
59 {
60 public:
61         ChestNodeMetadata(IGameDef *gamedef);
62         ~ChestNodeMetadata();
63         
64         virtual u16 typeId() const;
65         virtual const char* typeName() const
66         { return "chest"; }
67         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
68         static NodeMetadata* create(IGameDef *gamedef);
69         virtual NodeMetadata* clone(IGameDef *gamedef);
70         virtual void serializeBody(std::ostream &os);
71         virtual std::string infoText();
72         virtual Inventory* getInventory() {return m_inventory;}
73         virtual bool nodeRemovalDisabled();
74         virtual std::string getInventoryDrawSpecString();
75         
76 private:
77         Inventory *m_inventory;
78 };
79
80 class LockingChestNodeMetadata : public NodeMetadata
81 {
82 public:
83         LockingChestNodeMetadata(IGameDef *gamedef);
84         ~LockingChestNodeMetadata();
85
86         virtual u16 typeId() const;
87         virtual const char* typeName() const
88         { return "locked_chest"; }
89         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
90         static NodeMetadata* create(IGameDef *gamedef);
91         virtual NodeMetadata* clone(IGameDef *gamedef);
92         virtual void serializeBody(std::ostream &os);
93         virtual std::string infoText();
94         virtual Inventory* getInventory() {return m_inventory;}
95         virtual bool nodeRemovalDisabled();
96         virtual std::string getInventoryDrawSpecString();
97
98         virtual std::string getOwner(){ return m_text; }
99         virtual void setOwner(std::string t){ m_text = t; }
100
101 private:
102         Inventory *m_inventory;
103         std::string m_text;
104 };
105
106 class FurnaceNodeMetadata : public NodeMetadata
107 {
108 public:
109         FurnaceNodeMetadata(IGameDef *gamedef);
110         ~FurnaceNodeMetadata();
111         
112         virtual u16 typeId() const;
113         virtual const char* typeName() const
114         { return "furnace"; }
115         virtual NodeMetadata* clone(IGameDef *gamedef);
116         static NodeMetadata* create(std::istream &is, IGameDef *gamedef);
117         static NodeMetadata* create(IGameDef *gamedef);
118         virtual void serializeBody(std::ostream &os);
119         virtual std::string infoText();
120         virtual Inventory* getInventory() {return m_inventory;}
121         virtual void inventoryModified();
122         virtual bool step(float dtime);
123         virtual bool nodeRemovalDisabled();
124         virtual std::string getInventoryDrawSpecString();
125
126 private:
127         Inventory *m_inventory;
128         float m_step_accumulator;
129         float m_fuel_totaltime;
130         float m_fuel_time;
131         float m_src_totaltime;
132         float m_src_time;
133 };
134
135 /*
136         SignNodeMetadata
137 */
138
139 // Prototype
140 SignNodeMetadata proto_SignNodeMetadata(NULL, "");
141
142 SignNodeMetadata::SignNodeMetadata(IGameDef *gamedef, std::string text):
143         NodeMetadata(gamedef),
144         m_text(text)
145 {
146         NodeMetadata::registerType(typeId(), typeName(), create, create);
147 }
148 u16 SignNodeMetadata::typeId() const
149 {
150         return NODEMETA_SIGN;
151 }
152 NodeMetadata* SignNodeMetadata::create(std::istream &is, IGameDef *gamedef)
153 {
154         std::string text = deSerializeString(is);
155         return new SignNodeMetadata(gamedef, text);
156 }
157 NodeMetadata* SignNodeMetadata::create(IGameDef *gamedef)
158 {
159         return new SignNodeMetadata(gamedef, "");
160 }
161 NodeMetadata* SignNodeMetadata::clone(IGameDef *gamedef)
162 {
163         return new SignNodeMetadata(gamedef, m_text);
164 }
165 void SignNodeMetadata::serializeBody(std::ostream &os)
166 {
167         os<<serializeString(m_text);
168 }
169 std::string SignNodeMetadata::infoText()
170 {
171         return std::string("\"")+m_text+"\"";
172 }
173
174 /*
175         ChestNodeMetadata
176 */
177
178 // Prototype
179 ChestNodeMetadata proto_ChestNodeMetadata(NULL);
180
181 ChestNodeMetadata::ChestNodeMetadata(IGameDef *gamedef):
182         NodeMetadata(gamedef)
183 {
184         NodeMetadata::registerType(typeId(), typeName(), create, create);
185         
186         m_inventory = new Inventory();
187         m_inventory->addList("0", 8*4);
188 }
189 ChestNodeMetadata::~ChestNodeMetadata()
190 {
191         delete m_inventory;
192 }
193 u16 ChestNodeMetadata::typeId() const
194 {
195         return NODEMETA_CHEST;
196 }
197 NodeMetadata* ChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
198 {
199         ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
200         d->m_inventory->deSerialize(is, gamedef);
201         return d;
202 }
203 NodeMetadata* ChestNodeMetadata::create(IGameDef *gamedef)
204 {
205         ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
206         return d;
207 }
208 NodeMetadata* ChestNodeMetadata::clone(IGameDef *gamedef)
209 {
210         ChestNodeMetadata *d = new ChestNodeMetadata(gamedef);
211         *d->m_inventory = *m_inventory;
212         return d;
213 }
214 void ChestNodeMetadata::serializeBody(std::ostream &os)
215 {
216         m_inventory->serialize(os);
217 }
218 std::string ChestNodeMetadata::infoText()
219 {
220         return "Chest";
221 }
222 bool ChestNodeMetadata::nodeRemovalDisabled()
223 {
224         /*
225                 Disable removal if chest contains something
226         */
227         InventoryList *list = m_inventory->getList("0");
228         if(list == NULL)
229                 return false;
230         if(list->getUsedSlots() == 0)
231                 return false;
232         return true;
233 }
234 std::string ChestNodeMetadata::getInventoryDrawSpecString()
235 {
236         return
237                 "invsize[8,9;]"
238                 "list[current_name;0;0,0;8,4;]"
239                 "list[current_player;main;0,5;8,4;]";
240 }
241
242 /*
243         LockingChestNodeMetadata
244 */
245
246 // Prototype
247 LockingChestNodeMetadata proto_LockingChestNodeMetadata(NULL);
248
249 LockingChestNodeMetadata::LockingChestNodeMetadata(IGameDef *gamedef):
250         NodeMetadata(gamedef)
251 {
252         NodeMetadata::registerType(typeId(), typeName(), create, create);
253
254         m_inventory = new Inventory();
255         m_inventory->addList("0", 8*4);
256 }
257 LockingChestNodeMetadata::~LockingChestNodeMetadata()
258 {
259         delete m_inventory;
260 }
261 u16 LockingChestNodeMetadata::typeId() const
262 {
263         return NODEMETA_LOCKABLE_CHEST;
264 }
265 NodeMetadata* LockingChestNodeMetadata::create(std::istream &is, IGameDef *gamedef)
266 {
267         LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
268         d->setOwner(deSerializeString(is));
269         d->m_inventory->deSerialize(is, gamedef);
270         return d;
271 }
272 NodeMetadata* LockingChestNodeMetadata::create(IGameDef *gamedef)
273 {
274         LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
275         return d;
276 }
277 NodeMetadata* LockingChestNodeMetadata::clone(IGameDef *gamedef)
278 {
279         LockingChestNodeMetadata *d = new LockingChestNodeMetadata(gamedef);
280         *d->m_inventory = *m_inventory;
281         return d;
282 }
283 void LockingChestNodeMetadata::serializeBody(std::ostream &os)
284 {
285         os<<serializeString(m_text);
286         m_inventory->serialize(os);
287 }
288 std::string LockingChestNodeMetadata::infoText()
289 {
290         return "Locking Chest";
291 }
292 bool LockingChestNodeMetadata::nodeRemovalDisabled()
293 {
294         /*
295                 Disable removal if chest contains something
296         */
297         InventoryList *list = m_inventory->getList("0");
298         if(list == NULL)
299                 return false;
300         if(list->getUsedSlots() == 0)
301                 return false;
302         return true;
303 }
304 std::string LockingChestNodeMetadata::getInventoryDrawSpecString()
305 {
306         return
307                 "invsize[8,9;]"
308                 "list[current_name;0;0,0;8,4;]"
309                 "list[current_player;main;0,5;8,4;]";
310 }
311
312 /*
313         FurnaceNodeMetadata
314 */
315
316 // Prototype
317 FurnaceNodeMetadata proto_FurnaceNodeMetadata(NULL);
318
319 FurnaceNodeMetadata::FurnaceNodeMetadata(IGameDef *gamedef):
320         NodeMetadata(gamedef)
321 {
322         NodeMetadata::registerType(typeId(), typeName(), create, create);
323         
324         m_inventory = new Inventory();
325         m_inventory->addList("fuel", 1);
326         m_inventory->addList("src", 1);
327         m_inventory->addList("dst", 4);
328
329         m_step_accumulator = 0;
330         m_fuel_totaltime = 0;
331         m_fuel_time = 0;
332         m_src_totaltime = 0;
333         m_src_time = 0;
334 }
335 FurnaceNodeMetadata::~FurnaceNodeMetadata()
336 {
337         delete m_inventory;
338 }
339 u16 FurnaceNodeMetadata::typeId() const
340 {
341         return NODEMETA_FURNACE;
342 }
343 NodeMetadata* FurnaceNodeMetadata::clone(IGameDef *gamedef)
344 {
345         FurnaceNodeMetadata *d = new FurnaceNodeMetadata(m_gamedef);
346         *d->m_inventory = *m_inventory;
347         return d;
348 }
349 NodeMetadata* FurnaceNodeMetadata::create(std::istream &is, IGameDef *gamedef)
350 {
351         FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
352
353         d->m_inventory->deSerialize(is, gamedef);
354
355         int temp;
356         is>>temp;
357         d->m_fuel_totaltime = (float)temp/10;
358         is>>temp;
359         d->m_fuel_time = (float)temp/10;
360
361         return d;
362 }
363 NodeMetadata* FurnaceNodeMetadata::create(IGameDef *gamedef)
364 {
365         FurnaceNodeMetadata *d = new FurnaceNodeMetadata(gamedef);
366         return d;
367 }
368 void FurnaceNodeMetadata::serializeBody(std::ostream &os)
369 {
370         m_inventory->serialize(os);
371         os<<itos(m_fuel_totaltime*10)<<" ";
372         os<<itos(m_fuel_time*10)<<" ";
373 }
374 std::string FurnaceNodeMetadata::infoText()
375 {
376         //return "Furnace";
377         if(m_fuel_time >= m_fuel_totaltime)
378         {
379                 const InventoryList *src_list = m_inventory->getList("src");
380                 assert(src_list);
381                 const InventoryItem *src_item = src_list->getItem(0);
382
383                 if(src_item && src_item->isCookable()) {
384                         InventoryList *dst_list = m_inventory->getList("dst");
385                         if(!dst_list->roomForCookedItem(src_item))
386                                 return "Furnace is overloaded";
387                         return "Furnace is out of fuel";
388                 }
389                 else
390                         return "Furnace is inactive";
391         }
392         else
393         {
394                 std::string s = "Furnace is active";
395                 // Do this so it doesn't always show (0%) for weak fuel
396                 if(m_fuel_totaltime > 3) {
397                         s += " (";
398                         s += itos(m_fuel_time/m_fuel_totaltime*100);
399                         s += "%)";
400                 }
401                 return s;
402         }
403 }
404 bool FurnaceNodeMetadata::nodeRemovalDisabled()
405 {
406         /*
407                 Disable removal if furnace is not empty
408         */
409         InventoryList *list[3] = {m_inventory->getList("src"),
410         m_inventory->getList("dst"), m_inventory->getList("fuel")};
411         
412         for(int i = 0; i < 3; i++) {
413                 if(list[i] == NULL)
414                         continue;
415                 if(list[i]->getUsedSlots() == 0)
416                         continue;
417                 return true;
418         }
419         return false;
420         
421 }
422 void FurnaceNodeMetadata::inventoryModified()
423 {
424         infostream<<"Furnace inventory modification callback"<<std::endl;
425 }
426 bool FurnaceNodeMetadata::step(float dtime)
427 {
428         if(dtime > 60.0)
429                 infostream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
430         // Update at a fixed frequency
431         const float interval = 2.0;
432         m_step_accumulator += dtime;
433         bool changed = false;
434         while(m_step_accumulator > interval)
435         {
436                 m_step_accumulator -= interval;
437                 dtime = interval;
438
439                 //infostream<<"Furnace step dtime="<<dtime<<std::endl;
440                 
441                 InventoryList *dst_list = m_inventory->getList("dst");
442                 assert(dst_list);
443
444                 InventoryList *src_list = m_inventory->getList("src");
445                 assert(src_list);
446                 InventoryItem *src_item = src_list->getItem(0);
447                 
448                 bool room_available = false;
449                 
450                 if(src_item && src_item->isCookable())
451                         room_available = dst_list->roomForCookedItem(src_item);
452                 
453                 // Start only if there are free slots in dst, so that it can
454                 // accomodate any result item
455                 if(room_available)
456                 {
457                         m_src_totaltime = src_item->getCookTime();
458                 }
459                 else
460                 {
461                         m_src_time = 0;
462                         m_src_totaltime = 0;
463                 }
464                 
465                 /*
466                         If fuel is burning, increment the burn counters.
467                         If item finishes cooking, move it to result.
468                 */
469                 if(m_fuel_time < m_fuel_totaltime)
470                 {
471                         //infostream<<"Furnace is active"<<std::endl;
472                         m_fuel_time += dtime;
473                         m_src_time += dtime;
474                         if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
475                                         && src_item)
476                         {
477                                 InventoryItem *cookresult = src_item->createCookResult();
478                                 dst_list->addItem(cookresult);
479                                 src_list->decrementMaterials(1);
480                                 m_src_time = 0;
481                                 m_src_totaltime = 0;
482                         }
483                         changed = true;
484                         
485                         // If the fuel was not used up this step, just keep burning it
486                         if(m_fuel_time < m_fuel_totaltime)
487                                 continue;
488                 }
489                 
490                 /*
491                         Get the source again in case it has all burned
492                 */
493                 src_item = src_list->getItem(0);
494                 
495                 /*
496                         If there is no source item, or the source item is not cookable,
497                         or the furnace is still cooking, or the furnace became overloaded, stop loop.
498                 */
499                 if(src_item == NULL || !room_available || m_fuel_time < m_fuel_totaltime ||
500                         dst_list->roomForCookedItem(src_item) == false)
501                 {
502                         m_step_accumulator = 0;
503                         break;
504                 }
505                 
506                 //infostream<<"Furnace is out of fuel"<<std::endl;
507
508                 InventoryList *fuel_list = m_inventory->getList("fuel");
509                 assert(fuel_list);
510                 const InventoryItem *fuel_item = fuel_list->getItem(0);
511
512                 if(fuel_item && fuel_item->getBurnTime() >= 0){
513                         m_fuel_totaltime = fuel_item->getBurnTime();
514                         m_fuel_time = 0;
515                         fuel_list->decrementMaterials(1);
516                         changed = true;
517                 } else {
518                         //infostream<<"No fuel found"<<std::endl;
519                         // No fuel, stop loop.
520                         m_step_accumulator = 0;
521                         break;
522                 }
523         }
524         return changed;
525 }
526 std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
527 {
528         return
529                 "invsize[8,9;]"
530                 "list[current_name;fuel;2,3;1,1;]"
531                 "list[current_name;src;2,1;1,1;]"
532                 "list[current_name;dst;5,1;2,2;]"
533                 "list[current_player;main;0,5;8,4;]";
534 }
535
536 /*
537         GenericNodeMetadata
538 */
539
540 class GenericNodeMetadata : public NodeMetadata
541 {
542 private:
543         Inventory *m_inventory;
544         std::string m_text;
545         std::string m_owner;
546
547         std::string m_infotext;
548         std::string m_inventorydrawspec;
549         bool m_allow_text_input;
550         bool m_removal_disabled;
551         bool m_enforce_owner;
552
553         bool m_inventory_modified;
554         bool m_text_modified;
555
556         std::map<std::string, std::string> m_stringvars;
557
558 public:
559         u16 typeId() const
560         {
561                 return NODEMETA_GENERIC;
562         }
563         const char* typeName() const
564         {
565                 return "generic";
566         }
567
568         GenericNodeMetadata(IGameDef *gamedef):
569                 NodeMetadata(gamedef),
570
571                 m_inventory(new Inventory()),
572                 m_text(""),
573                 m_owner(""),
574
575                 m_infotext("GenericNodeMetadata"),
576                 m_inventorydrawspec(""),
577                 m_allow_text_input(false),
578                 m_removal_disabled(false),
579                 m_enforce_owner(false),
580
581                 m_inventory_modified(false),
582                 m_text_modified(false)
583         {
584                 NodeMetadata::registerType(typeId(), typeName(), create, create);
585         }
586         virtual ~GenericNodeMetadata()
587         {
588                 delete m_inventory;
589         }
590         NodeMetadata* clone(IGameDef *gamedef)
591         {
592                 GenericNodeMetadata *d = new GenericNodeMetadata(m_gamedef);
593
594                 *d->m_inventory = *m_inventory;
595                 d->m_text = m_text;
596                 d->m_owner = m_owner;
597
598                 d->m_infotext = m_infotext;
599                 d->m_inventorydrawspec = m_inventorydrawspec;
600                 d->m_allow_text_input = m_allow_text_input;
601                 d->m_removal_disabled = m_removal_disabled;
602                 d->m_enforce_owner = m_enforce_owner;
603                 d->m_inventory_modified = m_inventory_modified;
604                 d->m_text_modified = m_text_modified;
605                 return d;
606         }
607         static NodeMetadata* create(IGameDef *gamedef)
608         {
609                 GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
610                 return d;
611         }
612         static NodeMetadata* create(std::istream &is, IGameDef *gamedef)
613         {
614                 GenericNodeMetadata *d = new GenericNodeMetadata(gamedef);
615                 
616                 d->m_inventory->deSerialize(is, gamedef);
617                 d->m_text = deSerializeLongString(is);
618                 d->m_owner = deSerializeString(is);
619                 
620                 d->m_infotext = deSerializeString(is);
621                 d->m_inventorydrawspec = deSerializeString(is);
622                 d->m_allow_text_input = readU8(is);
623                 d->m_removal_disabled = readU8(is);
624                 d->m_enforce_owner = readU8(is);
625
626                 int num_vars = readU32(is);
627                 for(int i=0; i<num_vars; i++){
628                         std::string name = deSerializeString(is);
629                         std::string var = deSerializeLongString(is);
630                         d->m_stringvars[name] = var;
631                 }
632
633                 return d;
634         }
635         void serializeBody(std::ostream &os)
636         {
637                 m_inventory->serialize(os);
638                 os<<serializeLongString(m_text);
639                 os<<serializeString(m_owner);
640
641                 os<<serializeString(m_infotext);
642                 os<<serializeString(m_inventorydrawspec);
643                 writeU8(os, m_allow_text_input);
644                 writeU8(os, m_removal_disabled);
645                 writeU8(os, m_enforce_owner);
646
647                 int num_vars = m_stringvars.size();
648                 writeU32(os, num_vars);
649                 for(std::map<std::string, std::string>::iterator
650                                 i = m_stringvars.begin(); i != m_stringvars.end(); i++){
651                         os<<serializeString(i->first);
652                         os<<serializeLongString(i->second);
653                 }
654         }
655
656         std::string infoText()
657         {
658                 return m_infotext;
659         }
660         Inventory* getInventory()
661         {
662                 return m_inventory;
663         }
664         void inventoryModified()
665         {
666                 m_inventory_modified = true;
667         }
668         bool step(float dtime)
669         {
670                 return false;
671         }
672         bool nodeRemovalDisabled()
673         {
674                 return m_removal_disabled;
675         }
676         std::string getInventoryDrawSpecString()
677         {
678                 return m_inventorydrawspec;
679         }
680         bool allowsTextInput()
681         {
682                 return m_allow_text_input;
683         }
684         std::string getText()
685         {
686                 return m_text;
687         }
688         void setText(const std::string &t)
689         {
690                 m_text = t;
691                 m_text_modified = true;
692         }
693         std::string getOwner()
694         {
695                 if(m_enforce_owner)
696                         return m_owner;
697                 else
698                         return "";
699         }
700         void setOwner(std::string t)
701         {
702                 m_owner = t;
703         }
704         
705         /* Interface for GenericNodeMetadata */
706
707         void setInfoText(const std::string &text)
708         {
709                 infostream<<"GenericNodeMetadata::setInfoText(\""
710                                 <<text<<"\")"<<std::endl;
711                 m_infotext = text;
712         }
713         void setInventoryDrawSpec(const std::string &text)
714         {
715                 m_inventorydrawspec = text;
716         }
717         void setAllowTextInput(bool b)
718         {
719                 m_allow_text_input = b;
720         }
721         void setRemovalDisabled(bool b)
722         {
723                 m_removal_disabled = b;
724         }
725         void setEnforceOwner(bool b)
726         {
727                 m_enforce_owner = b;
728         }
729         bool isInventoryModified()
730         {
731                 return m_inventory_modified;
732         }
733         void resetInventoryModified()
734         {
735                 m_inventory_modified = false;
736         }
737         bool isTextModified()
738         {
739                 return m_text_modified;
740         }
741         void resetTextModified()
742         {
743                 m_text_modified = false;
744         }
745         void setString(const std::string &name, const std::string &var)
746         {
747                 m_stringvars[name] = var;
748         }
749         std::string getString(const std::string &name)
750         {
751                 std::map<std::string, std::string>::iterator i;
752                 i = m_stringvars.find(name);
753                 if(i == m_stringvars.end())
754                         return "";
755                 return i->second;
756         }
757 };
758
759 // Prototype
760 GenericNodeMetadata proto_GenericNodeMetadata(NULL);
761