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 v3s16 getChunkPos(const v3f &pos)
31 std::floor(pos.X / granularity),
32 std::floor(pos.Y / granularity),
33 std::floor(pos.Z / granularity));
36 static aabb3s16 calcBox(const aabb3f &cb)
38 return { getChunkPos(cb.MinEdge), getChunkPos(cb.MaxEdge) };
41 void ServerActiveObjectMap::addObject(ServerActiveObject *object)
45 u16 id = object->getId();
47 throw std::logic_error("ServerActiveObjectMap::addObject: "
48 "object ID in use: " + std::to_string(id));
50 w.has_box = w.object->getCollisionBox(&cb);
51 w.pos = getChunkPos(w.object->getBasePosition());
54 addObjectRefs(id, w.box);
56 addObjectRef(id, w.pos);
57 objects.emplace(id, w);
60 ServerActiveObject *ServerActiveObjectMap::removeObject(u16 id)
62 auto pw = objects.find(id);
63 if (pw == objects.end())
64 return nullptr; // silently ignore non-existent object
65 Wrapper w = pw->second;
67 removeObjectRefs(id, w.box);
68 removeObjectRef(id, w.pos);
73 void ServerActiveObjectMap::removeObject(ServerActiveObject *object)
75 removeObject(object->getId());
78 void ServerActiveObjectMap::updateObject(u16 id)
80 auto pw = objects.find(id);
81 if (pw == objects.end()) {
82 warningstream << "Trying to update non-existent object: " << id
86 Wrapper &w = pw->second;
87 v3s16 pos = getChunkPos(w.object->getBasePosition());
90 bool has_box = w.object->getCollisionBox(&cb);
93 if (w.has_box && has_box && w.box == box && pos == w.pos)
96 removeObjectRefs(id, w.box);
97 removeObjectRef(id, w.pos);
101 addObjectRefs(id, w.box);
102 addObjectRef(id, w.pos);
105 void ServerActiveObjectMap::updateObject(ServerActiveObject *object)
107 updateObject(object->getId());
110 ServerActiveObject *ServerActiveObjectMap::getObject(u16 id) const
112 auto pw = objects.find(id);
113 if (pw == objects.end())
115 return pw->second.object;
118 std::vector<u16> ServerActiveObjectMap::getObjectsInsideRadius(v3f pos, float radius)
120 std::vector<u16> result;
121 auto nearby = getObjectsNearBox(calcBox({pos - radius, pos + radius}));
122 for (auto &id : nearby) {
123 ServerActiveObject *obj = getObject(id);
124 v3f objectpos = obj->getBasePosition();
125 if (objectpos.getDistanceFrom(pos) > radius)
127 result.push_back(id);
132 std::vector<u16> ServerActiveObjectMap::getObjectsTouchingBox(const aabb3f &box)
134 std::vector<u16> result;
135 auto nearby = getObjectsNearBox(calcBox(box));
136 for (auto &id : nearby) {
137 ServerActiveObject *obj = getObject(id);
139 if (!obj->getCollisionBox(&cb))
141 if (!box.intersectsWithBox(cb))
143 result.push_back(id);
148 std::unordered_set<u16> ServerActiveObjectMap::getObjectsNearBox(const aabb3s16 &box)
150 std::unordered_set<u16> result;
152 for (p.Z = box.MinEdge.Z; p.Z <= box.MaxEdge.Z; p.Z++)
153 for (p.Y = box.MinEdge.Y; p.Y <= box.MaxEdge.Y; p.Y++)
154 for (p.X = box.MinEdge.X; p.X <= box.MaxEdge.X; p.X++) {
155 auto bounds = refmap.equal_range(p);
156 for (auto iter = bounds.first; iter != bounds.second; ++iter)
157 result.insert(iter->second);
162 void ServerActiveObjectMap::addObjectRef(u16 id, v3s16 pos)
164 refmap.emplace(pos, id);
167 void ServerActiveObjectMap::removeObjectRef(u16 id, v3s16 pos)
169 auto bounds = refmap.equal_range(pos);
170 for (auto iter = bounds.first; iter != bounds.second;) {
171 if (iter->second == id)
172 iter = refmap.erase(iter);
178 void ServerActiveObjectMap::addObjectRefs(u16 id, const aabb3s16 &box)
181 for (p.Z = box.MinEdge.Z; p.Z <= box.MaxEdge.Z; p.Z++)
182 for (p.Y = box.MinEdge.Y; p.Y <= box.MaxEdge.Y; p.Y++)
183 for (p.X = box.MinEdge.X; p.X <= box.MaxEdge.X; p.X++)
187 void ServerActiveObjectMap::removeObjectRefs(u16 id, const aabb3s16 &box)
190 for (p.Z = box.MinEdge.Z; p.Z <= box.MaxEdge.Z; p.Z++)
191 for (p.Y = box.MinEdge.Y; p.Y <= box.MaxEdge.Y; p.Y++)
192 for (p.X = box.MinEdge.X; p.X <= box.MaxEdge.X; p.X++)
193 removeObjectRef(id, p);
196 bool ServerActiveObjectMap::isFreeId(u16 id)
200 return objects.find(id) == objects.end();
203 u16 ServerActiveObjectMap::getFreeId()
205 // try to reuse id's as late as possible
206 static u16 last_used_id = 0;
207 u16 startid = last_used_id;
210 if (isFreeId(last_used_id))
212 if (last_used_id == startid) // wrapped around