3 Copyright (C) 2018 numZero, Lobachevsky Vitaly <numzer0@yandex.com>
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.
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.
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.
20 #include "serveractiveobjectmap.h"
22 #include "constants.h"
24 #include "serverobject.h"
26 static constexpr float granularity = 16.0 * BS;
28 static aabb3s16 calcBox(const aabb3f &cb)
31 std::floor(cb.MinEdge.X / granularity),
32 std::floor(cb.MinEdge.Y / granularity),
33 std::floor(cb.MinEdge.Z / granularity),
34 std::ceil(cb.MaxEdge.X / granularity),
35 std::ceil(cb.MaxEdge.Y / granularity),
36 std::ceil(cb.MaxEdge.Z / granularity));
39 void ServerActiveObjectMap::addObject(ServerActiveObject *object)
43 u16 id = object->getId();
45 throw std::logic_error("ServerActiveObjectMap::addObject: "
46 "object ID in use: " + std::to_string(id));
48 w.has_box = w.object->getCollisionBox(&cb);
51 addObjectRefs(id, w.box);
53 objects.emplace(id, w);
56 ServerActiveObject *ServerActiveObjectMap::removeObject(u16 id)
58 auto pw = objects.find(id);
59 if (pw == objects.end())
60 return nullptr; // silently ignore non-existent object
61 Wrapper w = pw->second;
63 removeObjectRefs(id, w.box);
68 void ServerActiveObjectMap::removeObject(ServerActiveObject *object)
70 removeObject(object->getId());
73 void ServerActiveObjectMap::updateObject(u16 id)
75 auto pw = objects.find(id);
76 if (pw == objects.end()) {
77 warningstream << "Trying to update non-existent object: " << id
81 Wrapper &w = pw->second;
84 bool has_box = w.object->getCollisionBox(&cb);
87 if (w.has_box && has_box && w.box == box)
90 removeObjectRefs(id, w.box);
94 addObjectRefs(id, w.box);
97 void ServerActiveObjectMap::updateObject(ServerActiveObject *object)
99 updateObject(object->getId());
102 ServerActiveObject *ServerActiveObjectMap::getObject(u16 id) const
104 auto pw = objects.find(id);
105 if (pw == objects.end())
107 return pw->second.object;
110 std::vector<u16> ServerActiveObjectMap::getObjectsInsideRadius(v3f pos, float radius)
112 std::vector<u16> result;
113 auto nearby = getObjectsNearBox(calcBox({pos - radius, pos + radius}));
114 for (auto &id : nearby) {
115 ServerActiveObject *obj = getObject(id);
116 v3f objectpos = obj->getBasePosition();
117 if (objectpos.getDistanceFrom(pos) > radius)
119 result.push_back(id);
124 std::vector<u16> ServerActiveObjectMap::getObjectsTouchingBox(const aabb3f &box)
126 std::vector<u16> result;
127 auto nearby = getObjectsNearBox(calcBox(box));
128 for (auto &id : nearby) {
129 ServerActiveObject *obj = getObject(id);
131 if (!obj->getCollisionBox(&cb))
133 if (!box.intersectsWithBox(cb))
135 result.push_back(id);
140 std::unordered_set<u16> ServerActiveObjectMap::getObjectsNearBox(const aabb3s16 &box)
142 std::unordered_set<u16> result;
144 for (p.Z = box.MinEdge.Z; p.Z <= box.MaxEdge.Z; p.Z++)
145 for (p.Y = box.MinEdge.Y; p.Y <= box.MaxEdge.Y; p.Y++)
146 for (p.X = box.MinEdge.X; p.X <= box.MaxEdge.X; p.X++) {
147 auto bounds = refmap.equal_range(p);
148 for (auto iter = bounds.first; iter != bounds.second; ++iter)
149 result.insert(iter->second);
154 void ServerActiveObjectMap::addObjectRefs(u16 id, const aabb3s16 &box)
157 for (p.Z = box.MinEdge.Z; p.Z <= box.MaxEdge.Z; p.Z++)
158 for (p.Y = box.MinEdge.Y; p.Y <= box.MaxEdge.Y; p.Y++)
159 for (p.X = box.MinEdge.X; p.X <= box.MaxEdge.X; p.X++)
160 refmap.emplace(p, id);
163 void ServerActiveObjectMap::removeObjectRefs(u16 id, const aabb3s16 &box)
166 for (p.Z = box.MinEdge.Z; p.Z <= box.MaxEdge.Z; p.Z++)
167 for (p.Y = box.MinEdge.Y; p.Y <= box.MaxEdge.Y; p.Y++)
168 for (p.X = box.MinEdge.X; p.X <= box.MaxEdge.X; p.X++) {
169 auto bounds = refmap.equal_range(p);
170 for (auto iter = bounds.first; iter != bounds.second;)
171 if (iter->second == id)
172 refmap.erase(iter++);
178 bool ServerActiveObjectMap::isFreeId(u16 id)
182 return objects.find(id) == objects.end();
185 u16 ServerActiveObjectMap::getFreeId()
187 // try to reuse id's as late as possible
188 static u16 last_used_id = 0;
189 u16 startid = last_used_id;
192 if (isFreeId(last_used_id))
194 if (last_used_id == startid) // wrapped around