2405e7601ea7d42c5b0c67840164323ec8ba5d40
[oweals/minetest.git] / src / nodemetadata.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 "nodemetadata.h"
21 #include "utility.h"
22 #include "mapnode.h"
23 #include "exceptions.h"
24 #include "inventory.h"
25 #include <sstream>
26
27 /*
28         NodeMetadata
29 */
30
31 core::map<u16, NodeMetadata::Factory> NodeMetadata::m_types;
32
33 NodeMetadata::NodeMetadata()
34 {
35 }
36
37 NodeMetadata::~NodeMetadata()
38 {
39 }
40
41 NodeMetadata* NodeMetadata::deSerialize(std::istream &is)
42 {
43         // Read id
44         u8 buf[2];
45         is.read((char*)buf, 2);
46         s16 id = readS16(buf);
47         
48         // Read data
49         std::string data = deSerializeString(is);
50         
51         // Find factory function
52         core::map<u16, Factory>::Node *n;
53         n = m_types.find(id);
54         if(n == NULL)
55         {
56                 // If factory is not found, just return.
57                 dstream<<"WARNING: NodeMetadata: No factory for typeId="
58                                 <<id<<std::endl;
59                 return NULL;
60         }
61         
62         // Try to load the metadata. If it fails, just return.
63         try
64         {
65                 std::istringstream iss(data, std::ios_base::binary);
66                 
67                 Factory f = n->getValue();
68                 NodeMetadata *meta = (*f)(iss);
69                 return meta;
70         }
71         catch(SerializationError &e)
72         {
73                 dstream<<"WARNING: NodeMetadata: ignoring SerializationError"<<std::endl;
74                 return NULL;
75         }
76 }
77
78 void NodeMetadata::serialize(std::ostream &os)
79 {
80         u8 buf[2];
81         writeU16(buf, typeId());
82         os.write((char*)buf, 2);
83         
84         std::ostringstream oss(std::ios_base::binary);
85         serializeBody(oss);
86         os<<serializeString(oss.str());
87 }
88
89 void NodeMetadata::registerType(u16 id, Factory f)
90 {
91         core::map<u16, Factory>::Node *n;
92         n = m_types.find(id);
93         if(n)
94                 return;
95         m_types.insert(id, f);
96 }
97
98 /*
99         SignNodeMetadata
100 */
101
102 SignNodeMetadata::SignNodeMetadata(std::string text):
103         m_text(text)
104 {
105         NodeMetadata::registerType(typeId(), create);
106 }
107 u16 SignNodeMetadata::typeId() const
108 {
109         return CONTENT_SIGN_WALL;
110 }
111 NodeMetadata* SignNodeMetadata::create(std::istream &is)
112 {
113         std::string text = deSerializeString(is);
114         return new SignNodeMetadata(text);
115 }
116 NodeMetadata* SignNodeMetadata::clone()
117 {
118         return new SignNodeMetadata(m_text);
119 }
120 void SignNodeMetadata::serializeBody(std::ostream &os)
121 {
122         os<<serializeString(m_text);
123 }
124 std::string SignNodeMetadata::infoText()
125 {
126         return std::string("\"")+m_text+"\"";
127 }
128
129 /*
130         ChestNodeMetadata
131 */
132
133 ChestNodeMetadata::ChestNodeMetadata()
134 {
135         NodeMetadata::registerType(typeId(), create);
136         
137         m_inventory = new Inventory();
138         m_inventory->addList("0", 8*4);
139 }
140 ChestNodeMetadata::~ChestNodeMetadata()
141 {
142         delete m_inventory;
143 }
144 u16 ChestNodeMetadata::typeId() const
145 {
146         return CONTENT_CHEST;
147 }
148 NodeMetadata* ChestNodeMetadata::create(std::istream &is)
149 {
150         ChestNodeMetadata *d = new ChestNodeMetadata();
151         d->m_inventory->deSerialize(is);
152         return d;
153 }
154 NodeMetadata* ChestNodeMetadata::clone()
155 {
156         ChestNodeMetadata *d = new ChestNodeMetadata();
157         *d->m_inventory = *m_inventory;
158         return d;
159 }
160 void ChestNodeMetadata::serializeBody(std::ostream &os)
161 {
162         m_inventory->serialize(os);
163 }
164 std::string ChestNodeMetadata::infoText()
165 {
166         return "Chest";
167 }
168
169 /*
170         FurnaceNodeMetadata
171 */
172
173 FurnaceNodeMetadata::FurnaceNodeMetadata()
174 {
175         NodeMetadata::registerType(typeId(), create);
176         
177         m_inventory = new Inventory();
178         m_inventory->addList("fuel", 1);
179         m_inventory->addList("src", 1);
180         m_inventory->addList("dst", 1);
181 }
182 FurnaceNodeMetadata::~FurnaceNodeMetadata()
183 {
184         delete m_inventory;
185 }
186 u16 FurnaceNodeMetadata::typeId() const
187 {
188         return CONTENT_FURNACE;
189 }
190 NodeMetadata* FurnaceNodeMetadata::clone()
191 {
192         FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
193         *d->m_inventory = *m_inventory;
194         return d;
195 }
196 NodeMetadata* FurnaceNodeMetadata::create(std::istream &is)
197 {
198         FurnaceNodeMetadata *d = new FurnaceNodeMetadata();
199         d->m_inventory->deSerialize(is);
200         /*std::string params;
201         std::getline(is, params, '\n');*/
202         return d;
203 }
204 void FurnaceNodeMetadata::serializeBody(std::ostream &os)
205 {
206         m_inventory->serialize(os);
207         // This line will contain the other parameters
208         //os<<"\n";
209 }
210 std::string FurnaceNodeMetadata::infoText()
211 {
212         return "Furnace";
213 }
214 void FurnaceNodeMetadata::inventoryModified()
215 {
216         dstream<<"Furnace inventory modification callback"<<std::endl;
217 }
218
219 /*
220         NodeMetadatalist
221 */
222
223 void NodeMetadataList::serialize(std::ostream &os)
224 {
225         u8 buf[6];
226         
227         u16 count = m_data.size();
228         writeU16(buf, count);
229         os.write((char*)buf, 2);
230
231         for(core::map<v3s16, NodeMetadata*>::Iterator
232                         i = m_data.getIterator();
233                         i.atEnd()==false; i++)
234         {
235                 v3s16 p = i.getNode()->getKey();
236                 NodeMetadata *data = i.getNode()->getValue();
237                 
238                 u16 p16 = p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X;
239                 writeU16(buf, p16);
240                 os.write((char*)buf, 2);
241
242                 data->serialize(os);
243         }
244         
245 }
246 void NodeMetadataList::deSerialize(std::istream &is)
247 {
248         m_data.clear();
249
250         u8 buf[6];
251         
252         is.read((char*)buf, 2);
253         u16 count = readU16(buf);
254         
255         for(u16 i=0; i<count; i++)
256         {
257                 is.read((char*)buf, 2);
258                 u16 p16 = readU16(buf);
259
260                 v3s16 p(0,0,0);
261                 p.Z += p16 / MAP_BLOCKSIZE / MAP_BLOCKSIZE;
262                 p16 -= p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
263                 p.Y += p16 / MAP_BLOCKSIZE;
264                 p16 -= p.Y * MAP_BLOCKSIZE;
265                 p.X += p16;
266                 
267                 NodeMetadata *data = NodeMetadata::deSerialize(is);
268
269                 if(data == NULL)
270                         continue;
271                 
272                 if(m_data.find(p))
273                 {
274                         dstream<<"WARNING: NodeMetadataList::deSerialize(): "
275                                         <<"already set data at position"
276                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
277                                         <<std::endl;
278                         delete data;
279                         continue;
280                 }
281
282                 m_data.insert(p, data);
283         }
284 }
285         
286 NodeMetadataList::~NodeMetadataList()
287 {
288         for(core::map<v3s16, NodeMetadata*>::Iterator
289                         i = m_data.getIterator();
290                         i.atEnd()==false; i++)
291         {
292                 delete i.getNode()->getValue();
293         }
294 }
295
296 NodeMetadata* NodeMetadataList::get(v3s16 p)
297 {
298         core::map<v3s16, NodeMetadata*>::Node *n;
299         n = m_data.find(p);
300         if(n == NULL)
301                 return NULL;
302         return n->getValue();
303 }
304
305 void NodeMetadataList::remove(v3s16 p)
306 {
307         NodeMetadata *olddata = get(p);
308         if(olddata)
309         {
310                 delete olddata;
311                 m_data.remove(p);
312         }
313 }
314
315 void NodeMetadataList::set(v3s16 p, NodeMetadata *d)
316 {
317         remove(p);
318         m_data.insert(p, d);
319 }
320