3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.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.
21 #include "environment.h"
22 #include "collision.h"
24 #include "scripting_server.h"
26 #include "daynightratio.h"
30 Environment::Environment(IGameDef
*gamedef
):
31 m_time_of_day_speed(0.0f
),
35 m_cache_enable_shaders
= g_settings
->getBool("enable_shaders");
36 m_cache_active_block_mgmt_interval
= g_settings
->getFloat("active_block_mgmt_interval");
37 m_cache_abm_interval
= g_settings
->getFloat("abm_interval");
38 m_cache_nodetimer_interval
= g_settings
->getFloat("nodetimer_interval");
39 m_cache_abm_time_budget
= g_settings
->getFloat("abm_time_budget");
41 m_time_of_day
= g_settings
->getU32("world_start_time");
42 m_time_of_day_f
= (float)m_time_of_day
/ 24000.0f
;
45 u32
Environment::getDayNightRatio()
47 MutexAutoLock
lock(this->m_time_lock
);
48 if (g_settings
->getBool("no_night"))
49 return time_to_daynight_ratio(12000, m_cache_enable_shaders
);
50 if (m_enable_day_night_ratio_override
)
51 return m_day_night_ratio_override
;
52 return time_to_daynight_ratio(m_time_of_day_f
* 24000, m_cache_enable_shaders
);
55 void Environment::setTimeOfDaySpeed(float speed
)
57 m_time_of_day_speed
= speed
;
60 void Environment::setDayNightRatioOverride(bool enable
, u32 value
)
62 MutexAutoLock
lock(this->m_time_lock
);
63 m_enable_day_night_ratio_override
= enable
;
64 m_day_night_ratio_override
= value
;
67 void Environment::setTimeOfDay(u32 time
)
69 MutexAutoLock
lock(this->m_time_lock
);
70 if (m_time_of_day
> time
)
73 m_time_of_day_f
= (float)time
/ 24000.0;
76 u32
Environment::getTimeOfDay()
78 MutexAutoLock
lock(this->m_time_lock
);
82 float Environment::getTimeOfDayF()
84 MutexAutoLock
lock(this->m_time_lock
);
85 return m_time_of_day_f
;
88 bool Environment::line_of_sight(v3f pos1
, v3f pos2
, v3s16
*p
)
90 // Iterate trough nodes on the line
91 voxalgo::VoxelLineIterator
iterator(pos1
/ BS
, (pos2
- pos1
) / BS
);
93 MapNode n
= getMap().getNode(iterator
.m_current_node_pos
);
96 if (n
.param0
!= CONTENT_AIR
) {
98 *p
= iterator
.m_current_node_pos
;
102 } while (iterator
.m_current_index
<= iterator
.m_last_index
);
107 Check if a node is pointable
109 inline static bool isPointableNode(const MapNode
&n
,
110 const NodeDefManager
*nodedef
, bool liquids_pointable
, bool nodes_pointable
)
112 if (! nodes_pointable
)
114 const ContentFeatures
&features
= nodedef
->get(n
);
115 return features
.pointable
||
116 ((liquids_pointable
|| g_settings
->getBool("point_liquids")) && features
.isLiquid());
119 void Environment::continueRaycast(RaycastState
*state
, PointedThing
*result
)
121 const NodeDefManager
*nodedef
= getMap().getNodeDefManager();
122 if (state
->m_initialization_needed
) {
124 if (state
->m_objects_pointable
) {
125 std::vector
<PointedThing
> found
;
126 getSelectedActiveObjects(state
->m_shootline
, found
);
127 for (const PointedThing
&pointed
: found
) {
128 state
->m_found
.push(pointed
);
132 core::aabbox3d
<s16
> maximal_exceed
= nodedef
->getSelectionBoxIntUnion();
133 state
->m_search_range
.MinEdge
= -maximal_exceed
.MaxEdge
;
134 state
->m_search_range
.MaxEdge
= -maximal_exceed
.MinEdge
;
136 state
->m_initialization_needed
= false;
139 // The index of the first pointed thing that was not returned
140 // before. The last index which needs to be tested.
141 s16 lastIndex
= state
->m_iterator
.m_last_index
;
142 if (!state
->m_found
.empty()) {
143 lastIndex
= state
->m_iterator
.getIndex(
144 floatToInt(state
->m_found
.top().intersection_point
, BS
));
148 // If a node is found, this is the center of the
149 // first nodebox the shootline meets.
150 v3f
found_boxcenter(0, 0, 0);
151 // The untested nodes are in this range.
152 core::aabbox3d
<s16
> new_nodes
;
153 while (state
->m_iterator
.m_current_index
<= lastIndex
) {
154 // Test the nodes around the current node in search_range.
155 new_nodes
= state
->m_search_range
;
156 new_nodes
.MinEdge
+= state
->m_iterator
.m_current_node_pos
;
157 new_nodes
.MaxEdge
+= state
->m_iterator
.m_current_node_pos
;
159 // Only check new nodes
160 v3s16 delta
= state
->m_iterator
.m_current_node_pos
161 - state
->m_previous_node
;
163 new_nodes
.MinEdge
.X
= new_nodes
.MaxEdge
.X
;
164 } else if (delta
.X
< 0) {
165 new_nodes
.MaxEdge
.X
= new_nodes
.MinEdge
.X
;
166 } else if (delta
.Y
> 0) {
167 new_nodes
.MinEdge
.Y
= new_nodes
.MaxEdge
.Y
;
168 } else if (delta
.Y
< 0) {
169 new_nodes
.MaxEdge
.Y
= new_nodes
.MinEdge
.Y
;
170 } else if (delta
.Z
> 0) {
171 new_nodes
.MinEdge
.Z
= new_nodes
.MaxEdge
.Z
;
172 } else if (delta
.Z
< 0) {
173 new_nodes
.MaxEdge
.Z
= new_nodes
.MinEdge
.Z
;
176 // For each untested node
177 for (s16 x
= new_nodes
.MinEdge
.X
; x
<= new_nodes
.MaxEdge
.X
; x
++)
178 for (s16 y
= new_nodes
.MinEdge
.Y
; y
<= new_nodes
.MaxEdge
.Y
; y
++)
179 for (s16 z
= new_nodes
.MinEdge
.Z
; z
<= new_nodes
.MaxEdge
.Z
; z
++) {
182 bool is_valid_position
;
184 n
= map
.getNode(np
, &is_valid_position
);
185 if (!(is_valid_position
&& isPointableNode(n
, nodedef
,
186 state
->m_liquids_pointable
, state
->m_nodes_pointable
))) {
192 std::vector
<aabb3f
> boxes
;
193 n
.getSelectionBoxes(nodedef
, &boxes
,
194 n
.getNeighbors(np
, &map
));
196 // Is there a collision with a selection box?
197 bool is_colliding
= false;
198 // Minimal distance of all collisions
199 float min_distance_sq
= 10000000;
200 // ID of the current box (loop counter)
203 v3f npf
= intToFloat(np
, BS
);
204 // This loop translates the boxes to their in-world place.
205 for (aabb3f
&box
: boxes
) {
209 v3f intersection_point
;
210 v3s16 intersection_normal
;
211 if (!boxLineCollision(box
, state
->m_shootline
.start
,
212 state
->m_shootline
.getVector(), &intersection_point
,
213 &intersection_normal
)) {
218 f32 distanceSq
= (intersection_point
219 - state
->m_shootline
.start
).getLengthSQ();
220 // If this is the nearest collision, save it
221 if (min_distance_sq
> distanceSq
) {
222 min_distance_sq
= distanceSq
;
223 result
.intersection_point
= intersection_point
;
224 result
.intersection_normal
= intersection_normal
;
226 found_boxcenter
= box
.getCenter();
231 // If there wasn't a collision, stop
235 result
.type
= POINTEDTHING_NODE
;
236 result
.node_undersurface
= np
;
237 result
.distanceSq
= min_distance_sq
;
238 // Set undersurface and abovesurface nodes
240 v3f fake_intersection
= result
.intersection_point
;
241 // Move intersection towards its source block.
242 if (fake_intersection
.X
< found_boxcenter
.X
) {
243 fake_intersection
.X
+= d
;
245 fake_intersection
.X
-= d
;
247 if (fake_intersection
.Y
< found_boxcenter
.Y
) {
248 fake_intersection
.Y
+= d
;
250 fake_intersection
.Y
-= d
;
252 if (fake_intersection
.Z
< found_boxcenter
.Z
) {
253 fake_intersection
.Z
+= d
;
255 fake_intersection
.Z
-= d
;
257 result
.node_real_undersurface
= floatToInt(
258 fake_intersection
, BS
);
259 result
.node_abovesurface
= result
.node_real_undersurface
260 + result
.intersection_normal
;
261 // Push found PointedThing
262 state
->m_found
.push(result
);
263 // If this is nearer than the old nearest object,
264 // the search can be shorter
265 s16 newIndex
= state
->m_iterator
.getIndex(
266 result
.node_real_undersurface
);
267 if (newIndex
< lastIndex
) {
268 lastIndex
= newIndex
;
272 state
->m_previous_node
= state
->m_iterator
.m_current_node_pos
;
273 state
->m_iterator
.next();
275 // Return empty PointedThing if nothing left on the ray
276 if (state
->m_found
.empty()) {
277 result
->type
= POINTEDTHING_NOTHING
;
279 *result
= state
->m_found
.top();
280 state
->m_found
.pop();
284 void Environment::stepTimeOfDay(float dtime
)
286 MutexAutoLock
lock(this->m_time_lock
);
288 // Cached in order to prevent the two reads we do to give
289 // different results (can be written by code not under the lock)
290 f32 cached_time_of_day_speed
= m_time_of_day_speed
;
292 f32 speed
= cached_time_of_day_speed
* 24000. / (24. * 3600);
293 m_time_conversion_skew
+= dtime
;
294 u32 units
= (u32
)(m_time_conversion_skew
* speed
);
298 if (m_time_of_day
+ units
>= 24000) {
302 m_time_of_day
= (m_time_of_day
+ units
) % 24000;
304 m_time_of_day_f
= (float)m_time_of_day
/ 24000.0;
307 m_time_conversion_skew
-= (f32
)units
/ speed
;
310 m_time_of_day_f
+= cached_time_of_day_speed
/ 24 / 3600 * dtime
;
311 if (m_time_of_day_f
> 1.0)
312 m_time_of_day_f
-= 1.0;
313 if (m_time_of_day_f
< 0.0)
314 m_time_of_day_f
+= 1.0;
318 u32
Environment::getDayCount()
320 // Atomic<u32> counter