410b4e2ea78bcb12cf89020dba9451aeb2336312
[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 #include "content_mapnode.h"
27 #include "log.h"
28
29 /*
30         NodeMetadata
31 */
32
33 NodeMetadata::NodeMetadata(IGameDef *gamedef):
34         m_gamedef(gamedef)
35 {
36 }
37
38 NodeMetadata::~NodeMetadata()
39 {
40 }
41
42 NodeMetadata* NodeMetadata::create(const std::string &name, IGameDef *gamedef)
43 {
44         // Find factory function
45         core::map<std::string, Factory2>::Node *n;
46         n = m_names.find(name);
47         if(n == NULL)
48         {
49                 // If factory is not found, just return.
50                 errorstream<<"WARNING: NodeMetadata: No factory for name=\""
51                                 <<name<<"\""<<std::endl;
52                 return NULL;
53         }
54         
55         // Try to load the metadata. If it fails, just return.
56         try
57         {
58                 Factory2 f2 = n->getValue();
59                 NodeMetadata *meta = (*f2)(gamedef);
60                 return meta;
61         }
62         catch(SerializationError &e)
63         {
64                 errorstream<<"NodeMetadata: SerializationError "
65                                 <<"while creating name=\""<<name<<"\""<<std::endl;
66                 return NULL;
67         }
68 }
69
70 NodeMetadata* NodeMetadata::deSerialize(std::istream &is, IGameDef *gamedef)
71 {
72         // Read id
73         u8 buf[2];
74         is.read((char*)buf, 2);
75         s16 id = readS16(buf);
76         
77         // Read data
78         std::string data = deSerializeString(is);
79         
80         // Find factory function
81         core::map<u16, Factory>::Node *n;
82         n = m_types.find(id);
83         if(n == NULL)
84         {
85                 // If factory is not found, just return.
86                 infostream<<"WARNING: NodeMetadata: No factory for typeId="
87                                 <<id<<std::endl;
88                 return NULL;
89         }
90         
91         // Try to load the metadata. If it fails, just return.
92         try
93         {
94                 std::istringstream iss(data, std::ios_base::binary);
95                 
96                 Factory f = n->getValue();
97                 NodeMetadata *meta = (*f)(iss, gamedef);
98                 return meta;
99         }
100         catch(SerializationError &e)
101         {
102                 infostream<<"WARNING: NodeMetadata: ignoring SerializationError"<<std::endl;
103                 return NULL;
104         }
105 }
106
107 void NodeMetadata::serialize(std::ostream &os)
108 {
109         u8 buf[2];
110         writeU16(buf, typeId());
111         os.write((char*)buf, 2);
112         
113         std::ostringstream oss(std::ios_base::binary);
114         serializeBody(oss);
115         os<<serializeString(oss.str());
116 }
117
118 void NodeMetadata::registerType(u16 id, const std::string &name, Factory f,
119                 Factory2 f2)
120 {
121         { // typeId
122                 core::map<u16, Factory>::Node *n;
123                 n = m_types.find(id);
124                 if(!n)
125                         m_types.insert(id, f);
126         }
127         { // typeName
128                 core::map<std::string, Factory2>::Node *n;
129                 n = m_names.find(name);
130                 if(!n)
131                         m_names.insert(name, f2);
132         }
133 }
134
135 /*
136         NodeMetadataList
137 */
138
139 void NodeMetadataList::serialize(std::ostream &os)
140 {
141         u8 buf[6];
142         
143         u16 version = 1;
144         writeU16(buf, version);
145         os.write((char*)buf, 2);
146
147         u16 count = m_data.size();
148         writeU16(buf, count);
149         os.write((char*)buf, 2);
150
151         for(core::map<v3s16, NodeMetadata*>::Iterator
152                         i = m_data.getIterator();
153                         i.atEnd()==false; i++)
154         {
155                 v3s16 p = i.getNode()->getKey();
156                 NodeMetadata *data = i.getNode()->getValue();
157                 
158                 u16 p16 = p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X;
159                 writeU16(buf, p16);
160                 os.write((char*)buf, 2);
161
162                 data->serialize(os);
163         }
164         
165 }
166 void NodeMetadataList::deSerialize(std::istream &is, IGameDef *gamedef)
167 {
168         m_data.clear();
169
170         u8 buf[6];
171         
172         is.read((char*)buf, 2);
173         u16 version = readU16(buf);
174
175         if(version > 1)
176         {
177                 infostream<<__FUNCTION_NAME<<": version "<<version<<" not supported"
178                                 <<std::endl;
179                 throw SerializationError("NodeMetadataList::deSerialize");
180         }
181         
182         is.read((char*)buf, 2);
183         u16 count = readU16(buf);
184         
185         for(u16 i=0; i<count; i++)
186         {
187                 is.read((char*)buf, 2);
188                 u16 p16 = readU16(buf);
189
190                 v3s16 p(0,0,0);
191                 p.Z += p16 / MAP_BLOCKSIZE / MAP_BLOCKSIZE;
192                 p16 -= p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
193                 p.Y += p16 / MAP_BLOCKSIZE;
194                 p16 -= p.Y * MAP_BLOCKSIZE;
195                 p.X += p16;
196                 
197                 NodeMetadata *data = NodeMetadata::deSerialize(is, gamedef);
198
199                 if(data == NULL)
200                         continue;
201                 
202                 if(m_data.find(p))
203                 {
204                         infostream<<"WARNING: NodeMetadataList::deSerialize(): "
205                                         <<"already set data at position"
206                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
207                                         <<std::endl;
208                         delete data;
209                         continue;
210                 }
211
212                 m_data.insert(p, data);
213         }
214 }
215         
216 NodeMetadataList::~NodeMetadataList()
217 {
218         for(core::map<v3s16, NodeMetadata*>::Iterator
219                         i = m_data.getIterator();
220                         i.atEnd()==false; i++)
221         {
222                 delete i.getNode()->getValue();
223         }
224 }
225
226 NodeMetadata* NodeMetadataList::get(v3s16 p)
227 {
228         core::map<v3s16, NodeMetadata*>::Node *n;
229         n = m_data.find(p);
230         if(n == NULL)
231                 return NULL;
232         return n->getValue();
233 }
234
235 void NodeMetadataList::remove(v3s16 p)
236 {
237         NodeMetadata *olddata = get(p);
238         if(olddata)
239         {
240                 delete olddata;
241                 m_data.remove(p);
242         }
243 }
244
245 void NodeMetadataList::set(v3s16 p, NodeMetadata *d)
246 {
247         remove(p);
248         m_data.insert(p, d);
249 }
250
251 bool NodeMetadataList::step(float dtime)
252 {
253         bool something_changed = false;
254         for(core::map<v3s16, NodeMetadata*>::Iterator
255                         i = m_data.getIterator();
256                         i.atEnd()==false; i++)
257         {
258                 v3s16 p = i.getNode()->getKey();
259                 NodeMetadata *meta = i.getNode()->getValue();
260                 bool changed = meta->step(dtime);
261                 if(changed)
262                         something_changed = true;
263         }
264         return something_changed;
265 }
266