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