summaryrefslogtreecommitdiff
path: root/src/server/serveractiveobjectmap.h
blob: 60f6890bddc79ac65c663c07f71522d645a0cffb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
Minetest
Copyright (C) 2018 numZero, Lobachevsky Vitaly <numzer0@yandex.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#pragma once
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include "irr_v3d.h"
#include "irr_aabb3d.h"

class ServerActiveObject;

/*!
 * The class to speed up collision tests.
 *
 * @note It stores any objects but only those that has valid collision box
 * (`physical` Lua entities) are actually processed.
 * @note It uses world coordinate units, i.e. node size is always BS.
 */
struct ServerActiveObjectMap
{
	struct Wrapper
	{
		ServerActiveObject *object;
		aabb3s16 box;
		v3s16 pos;
		bool has_box;
	};

	/*!
	 * Adds object to the map. It must have valid ID.
	 *
	 * If an object with the same ID already exists in the map,
	 * std::logic_error is thrown.
	 */
	void addObject(ServerActiveObject *object);

	/*!
	 * Removes object from the map. The pointer must be valid.
	 * See `removeObject(u16)` for details.
	 */
	void removeObject(ServerActiveObject *object);

	/*!
	 * Removes object from the map.
	 *
	 * If the object is not found, the call is ignored.
	 * The function never throws, unless the underlying container throws.
	 */
	ServerActiveObject *removeObject(u16 id);

	/*!
	 * Updates object metadata stored in the map.
	 * See `updateObject(u16)` for details.
	 */
	void updateObject(ServerActiveObject *object);

	/*!
	 * Updates object metadata stored in the map.
	 *
	 * The metadata includes (approximate) absolute collision box and
	 * its existence (`physical` property for Lua entities).
	 * This function must be called after each change of these properties,
	 * including each object movement.
	 */
	void updateObject(u16 id);

	/*!
	 * Returns the object with given ID, if any.
	 * Returns NULL otherwise.
	 */
	ServerActiveObject *getObject(u16 id) const;

	/*!
	 * Checks if the given ID is free and valid (i.e. non-zero).
	 */
	bool isFreeId(u16 id);

	/*!
	 * Returns a free ID, if any. Returns 0 in the case of failure.
	 *
	 * @note This function doesn't reserve the ID; it remains free until
	 * an object with that ID is added.
	 * @note This function tries to reclaim freed IDs as late as possible.
	 * However, there is no guarantee.
	 */
	u16 getFreeId();

	/*!
	 * Returns a list of objects whose base position is at distance less
	 * than @p radius from @p pos.
	 *
	 * @note Due to inexact nature of floating-point computations, it is
	 * undefined whether an object lying exactly at the boundary is included
	 * in the list or not.
	 */
	std::vector<u16> getObjectsInsideRadius(v3f pos, float radius);

	/*!
	 * Returns a list of objects whose collision box intersects with @p box
	 *
	 * @note Due to inexact nature of floating-point computations, it is
	 * undefined whether an object lying exactly at the boundary is included
	 * in the list or not.
	 */
	std::vector<u16> getObjectsTouchingBox(const aabb3f &box);

	/*!
	 * Returns count of objects in the map.
	 */
	std::size_t size() const { return objects.size(); }

	/*!
	 * Returns reference to the underlying container.
	 */
	const std::unordered_map<u16, Wrapper> &getObjects() const { return objects; }

private:
	void addObjectRef(u16 id, v3s16 pos);
	void removeObjectRef(u16 id, v3s16 pos);
	void addObjectRefs(u16 id, const aabb3s16 &box);
	void removeObjectRefs(u16 id, const aabb3s16 &box);
	std::unordered_set<u16> getObjectsNearBox(const aabb3s16 &box);

	std::unordered_map<u16, Wrapper> objects;
	std::unordered_multimap<v3s16, u16> refmap;
};