Split ObjDef/ObjDefManager out to objdef.cpp
[oweals/minetest.git] / src / objdef.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
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 "objdef.h"
21 #include "util/numeric.h"
22 #include "debug.h"
23 #include "log.h"
24 #include "gamedef.h"
25
26 ObjDefManager::ObjDefManager(IGameDef *gamedef, ObjDefType type)
27 {
28         m_objtype = type;
29         m_ndef = gamedef ? gamedef->getNodeDefManager() : NULL;
30 }
31
32
33 ObjDefManager::~ObjDefManager()
34 {
35         for (size_t i = 0; i != m_objects.size(); i++)
36                 delete m_objects[i];
37 }
38
39
40 ObjDefHandle ObjDefManager::add(ObjDef *obj)
41 {
42         assert(obj);
43
44         if (obj->name.length() && getByName(obj->name))
45                 return OBJDEF_INVALID_HANDLE;
46
47         u32 index = addRaw(obj);
48         if (index == OBJDEF_INVALID_INDEX)
49                 return OBJDEF_INVALID_HANDLE;
50
51         obj->handle = createHandle(index, m_objtype, obj->uid);
52         return obj->handle;
53 }
54
55
56 ObjDef *ObjDefManager::get(ObjDefHandle handle) const
57 {
58         u32 index = validateHandle(handle);
59         return (index != OBJDEF_INVALID_INDEX) ? getRaw(index) : NULL;
60 }
61
62
63 ObjDef *ObjDefManager::set(ObjDefHandle handle, ObjDef *obj)
64 {
65         u32 index = validateHandle(handle);
66         if (index == OBJDEF_INVALID_INDEX)
67                 return NULL;
68
69         ObjDef *oldobj = setRaw(index, obj);
70
71         obj->uid    = oldobj->uid;
72         obj->index  = oldobj->index;
73         obj->handle = oldobj->handle;
74
75         return oldobj;
76 }
77
78
79 u32 ObjDefManager::addRaw(ObjDef *obj)
80 {
81         size_t nobjects = m_objects.size();
82         if (nobjects >= OBJDEF_MAX_ITEMS)
83                 return -1;
84
85         obj->index = nobjects;
86
87         // Ensure UID is nonzero so that a valid handle == OBJDEF_INVALID_HANDLE
88         // is not possible.  The slight randomness bias isn't very significant.
89         obj->uid = myrand() & OBJDEF_UID_MASK;
90         if (obj->uid == 0)
91                 obj->uid = 1;
92
93         m_objects.push_back(obj);
94
95         infostream << "ObjDefManager: added " << getObjectTitle()
96                 << ": name=\"" << obj->name
97                 << "\" index=" << obj->index
98                 << " uid="     << obj->uid
99                 << std::endl;
100
101         return nobjects;
102 }
103
104
105 ObjDef *ObjDefManager::getRaw(u32 index) const
106 {
107         return m_objects[index];
108 }
109
110
111 ObjDef *ObjDefManager::setRaw(u32 index, ObjDef *obj)
112 {
113         ObjDef *old_obj = m_objects[index];
114         m_objects[index] = obj;
115         return old_obj;
116 }
117
118
119 ObjDef *ObjDefManager::getByName(const std::string &name) const
120 {
121         for (size_t i = 0; i != m_objects.size(); i++) {
122                 ObjDef *obj = m_objects[i];
123                 if (obj && !strcasecmp(name.c_str(), obj->name.c_str()))
124                         return obj;
125         }
126
127         return NULL;
128 }
129
130
131 void ObjDefManager::clear()
132 {
133         for (size_t i = 0; i != m_objects.size(); i++)
134                 delete m_objects[i];
135
136         m_objects.clear();
137 }
138
139
140 u32 ObjDefManager::validateHandle(ObjDefHandle handle) const
141 {
142         ObjDefType type;
143         u32 index;
144         u32 uid;
145
146         bool is_valid =
147                 (handle != OBJDEF_INVALID_HANDLE)         &&
148                 decodeHandle(handle, &index, &type, &uid) &&
149                 (type == m_objtype)                       &&
150                 (index < m_objects.size())                &&
151                 (m_objects[index]->uid == uid);
152
153         return is_valid ? index : -1;
154 }
155
156
157 ObjDefHandle ObjDefManager::createHandle(u32 index, ObjDefType type, u32 uid)
158 {
159         ObjDefHandle handle = 0;
160         set_bits(&handle, 0, 18, index);
161         set_bits(&handle, 18, 6, type);
162         set_bits(&handle, 24, 7, uid);
163
164         u32 parity = calc_parity(handle);
165         set_bits(&handle, 31, 1, parity);
166
167         return handle ^ OBJDEF_HANDLE_SALT;
168 }
169
170
171 bool ObjDefManager::decodeHandle(ObjDefHandle handle, u32 *index,
172         ObjDefType *type, u32 *uid)
173 {
174         handle ^= OBJDEF_HANDLE_SALT;
175
176         u32 parity = get_bits(handle, 31, 1);
177         set_bits(&handle, 31, 1, 0);
178         if (parity != calc_parity(handle))
179                 return false;
180
181         *index = get_bits(handle, 0, 18);
182         *type  = (ObjDefType)get_bits(handle, 18, 6);
183         *uid   = get_bits(handle, 24, 7);
184         return true;
185 }