Private nodemeta (#5702)
[oweals/minetest.git] / src / nodemetadata.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-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 "nodemetadata.h"
21 #include "exceptions.h"
22 #include "gamedef.h"
23 #include "inventory.h"
24 #include "log.h"
25 #include "util/serialize.h"
26 #include "util/basic_macros.h"
27 #include "constants.h" // MAP_BLOCKSIZE
28 #include <sstream>
29
30 /*
31         NodeMetadata
32 */
33
34 NodeMetadata::NodeMetadata(IItemDefManager *item_def_mgr):
35         m_inventory(new Inventory(item_def_mgr))
36 {}
37
38 NodeMetadata::~NodeMetadata()
39 {
40         delete m_inventory;
41 }
42
43 void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const
44 {
45         int num_vars = disk ? m_stringvars.size() : countNonPrivate();
46         writeU32(os, num_vars);
47         for (StringMap::const_iterator
48                         it = m_stringvars.begin();
49                         it != m_stringvars.end(); ++it) {
50                 bool priv = isPrivate(it->first);
51                 if (!disk && priv)
52                         continue;
53
54                 os << serializeString(it->first);
55                 os << serializeLongString(it->second);
56                 if (version >= 2)
57                         writeU8(os, (priv) ? 1 : 0);
58         }
59
60         m_inventory->serialize(os);
61 }
62
63 void NodeMetadata::deSerialize(std::istream &is, u8 version)
64 {
65         clear();
66         int num_vars = readU32(is);
67         for(int i=0; i<num_vars; i++){
68                 std::string name = deSerializeString(is);
69                 std::string var = deSerializeLongString(is);
70                 m_stringvars[name] = var;
71                 if (version >= 2) {
72                         if (readU8(is) == 1)
73                                 markPrivate(name, true);
74                 }
75         }
76
77         m_inventory->deSerialize(is);
78 }
79
80 void NodeMetadata::clear()
81 {
82         Metadata::clear();
83         m_privatevars.clear();
84         m_inventory->clear();
85 }
86
87 bool NodeMetadata::empty() const
88 {
89         return Metadata::empty() && m_inventory->getLists().size() == 0;
90 }
91
92
93 void NodeMetadata::markPrivate(const std::string &name, bool set)
94 {
95         if (set)
96                 m_privatevars.insert(name);
97         else
98                 m_privatevars.erase(name);
99 }
100
101 int NodeMetadata::countNonPrivate() const
102 {
103         // m_privatevars can contain names not actually present
104         // DON'T: return m_stringvars.size() - m_privatevars.size();
105         int n = 0;
106         for (StringMap::const_iterator
107                         it = m_stringvars.begin();
108                         it != m_stringvars.end(); ++it) {
109                 if (isPrivate(it->first) == false)
110                         n++;
111         }
112         return n;
113 }
114
115 /*
116         NodeMetadataList
117 */
118
119 void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk) const
120 {
121         /*
122                 Version 0 is a placeholder for "nothing to see here; go away."
123         */
124
125         u16 count = countNonEmpty();
126         if (count == 0) {
127                 writeU8(os, 0); // version
128                 return;
129         }
130
131         u8 version = (blockver > 27) ? 2 : 1;
132         writeU8(os, version);
133         writeU16(os, count);
134
135         for(std::map<v3s16, NodeMetadata*>::const_iterator
136                         i = m_data.begin();
137                         i != m_data.end(); ++i)
138         {
139                 v3s16 p = i->first;
140                 NodeMetadata *data = i->second;
141                 if (data->empty())
142                         continue;
143
144                 u16 p16 = p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + p.Y * MAP_BLOCKSIZE + p.X;
145                 writeU16(os, p16);
146
147                 data->serialize(os, version, disk);
148         }
149 }
150
151 void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_mgr)
152 {
153         clear();
154
155         u8 version = readU8(is);
156
157         if (version == 0) {
158                 // Nothing
159                 return;
160         }
161
162         if (version > 2) {
163                 std::string err_str = std::string(FUNCTION_NAME)
164                         + ": version " + itos(version) + " not supported";
165                 infostream << err_str << std::endl;
166                 throw SerializationError(err_str);
167         }
168
169         u16 count = readU16(is);
170
171         for (u16 i = 0; i < count; i++) {
172                 u16 p16 = readU16(is);
173
174                 v3s16 p;
175                 p.Z = p16 / MAP_BLOCKSIZE / MAP_BLOCKSIZE;
176                 p16 &= MAP_BLOCKSIZE * MAP_BLOCKSIZE - 1;
177                 p.Y = p16 / MAP_BLOCKSIZE;
178                 p16 &= MAP_BLOCKSIZE - 1;
179                 p.X = p16;
180
181                 if (m_data.find(p) != m_data.end()) {
182                         warningstream << "NodeMetadataList::deSerialize(): "
183                                         << "already set data at position " << PP(p)
184                                         << ": Ignoring." << std::endl;
185                         continue;
186                 }
187
188                 NodeMetadata *data = new NodeMetadata(item_def_mgr);
189                 data->deSerialize(is, version);
190                 m_data[p] = data;
191         }
192 }
193
194 NodeMetadataList::~NodeMetadataList()
195 {
196         clear();
197 }
198
199 std::vector<v3s16> NodeMetadataList::getAllKeys()
200 {
201         std::vector<v3s16> keys;
202
203         std::map<v3s16, NodeMetadata *>::const_iterator it;
204         for (it = m_data.begin(); it != m_data.end(); ++it)
205                 keys.push_back(it->first);
206
207         return keys;
208 }
209
210 NodeMetadata *NodeMetadataList::get(v3s16 p)
211 {
212         std::map<v3s16, NodeMetadata *>::const_iterator n = m_data.find(p);
213         if (n == m_data.end())
214                 return NULL;
215         return n->second;
216 }
217
218 void NodeMetadataList::remove(v3s16 p)
219 {
220         NodeMetadata *olddata = get(p);
221         if (olddata) {
222                 delete olddata;
223                 m_data.erase(p);
224         }
225 }
226
227 void NodeMetadataList::set(v3s16 p, NodeMetadata *d)
228 {
229         remove(p);
230         m_data.insert(std::make_pair(p, d));
231 }
232
233 void NodeMetadataList::clear()
234 {
235         std::map<v3s16, NodeMetadata*>::iterator it;
236         for (it = m_data.begin(); it != m_data.end(); ++it) {
237                 delete it->second;
238         }
239         m_data.clear();
240 }
241
242 int NodeMetadataList::countNonEmpty() const
243 {
244         int n = 0;
245         std::map<v3s16, NodeMetadata*>::const_iterator it;
246         for (it = m_data.begin(); it != m_data.end(); ++it) {
247                 if (!it->second->empty())
248                         n++;
249         }
250         return n;
251 }