forked from Mirrorlandia_minetest/minetest
Expose getPointedThing to Lua
This commit introduces Raycast, a Lua user object, which can be used to perform a raycast on the map. The ray is continuable, so one can also get hidden nodes (for example to see trough glass).
This commit is contained in:
parent
a80ecbee1e
commit
3caad3f3c9
@ -2557,6 +2557,12 @@ and `minetest.auth_reload` call the authetification handler.
|
|||||||
* `pos2`: Second position
|
* `pos2`: Second position
|
||||||
* `stepsize`: smaller gives more accurate results but requires more computing
|
* `stepsize`: smaller gives more accurate results but requires more computing
|
||||||
time. Default is `1`.
|
time. Default is `1`.
|
||||||
|
* `minetest.raycast(pos1, pos2, objects, liquids)`: returns `Raycast`
|
||||||
|
* Creates a `Raycast` object.
|
||||||
|
* `pos1`: start of the ray
|
||||||
|
* `pos2`: end of the ray
|
||||||
|
* `objects` : if false, only nodes will be returned. Default is `true`.
|
||||||
|
* `liquids' : if false, liquid nodes won't be returned. Default is `false`.
|
||||||
* `minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)`
|
* `minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)`
|
||||||
* returns table containing path
|
* returns table containing path
|
||||||
* returns a table of 3D points representing a path from `pos1` to `pos2` or `nil`
|
* returns a table of 3D points representing a path from `pos1` to `pos2` or `nil`
|
||||||
@ -3755,6 +3761,26 @@ It can be created via `Settings(filename)`.
|
|||||||
* Writes changes to file.
|
* Writes changes to file.
|
||||||
* `to_table()`: returns `{[key1]=value1,...}`
|
* `to_table()`: returns `{[key1]=value1,...}`
|
||||||
|
|
||||||
|
### `Raycast`
|
||||||
|
A raycast on the map. It works with selection boxes.
|
||||||
|
Can be used as an iterator in a for loop.
|
||||||
|
|
||||||
|
The map is loaded as the ray advances. If the
|
||||||
|
map is modified after the `Raycast` is created,
|
||||||
|
the changes may or may not have an effect on
|
||||||
|
the object.
|
||||||
|
|
||||||
|
It can be created via `Raycast(pos1, pos2, objects, liquids)` or
|
||||||
|
`minetest.raycast(pos1, pos2, objects, liquids)` where:
|
||||||
|
* `pos1`: start of the ray
|
||||||
|
* `pos2`: end of the ray
|
||||||
|
* `objects` : if false, only nodes will be returned. Default is true.
|
||||||
|
* `liquids' : if false, liquid nodes won't be returned. Default is false.
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
* `next()`: returns a `pointed_thing`
|
||||||
|
* Returns the next thing pointed by the ray or nil.
|
||||||
|
|
||||||
Mapgen objects
|
Mapgen objects
|
||||||
--------------
|
--------------
|
||||||
A mapgen object is a construct used in map generation. Mapgen objects can be used
|
A mapgen object is a construct used in map generation. Mapgen objects can be used
|
||||||
|
@ -428,9 +428,9 @@ set(common_SRCS
|
|||||||
porting.cpp
|
porting.cpp
|
||||||
profiler.cpp
|
profiler.cpp
|
||||||
quicktune.cpp
|
quicktune.cpp
|
||||||
|
raycast.cpp
|
||||||
reflowscan.cpp
|
reflowscan.cpp
|
||||||
remoteplayer.cpp
|
remoteplayer.cpp
|
||||||
raycast.cpp
|
|
||||||
rollback.cpp
|
rollback.cpp
|
||||||
rollback_interface.cpp
|
rollback_interface.cpp
|
||||||
serialization.cpp
|
serialization.cpp
|
||||||
|
@ -65,7 +65,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 getId()
|
u16 getId() const
|
||||||
{
|
{
|
||||||
return m_id;
|
return m_id;
|
||||||
}
|
}
|
||||||
@ -76,7 +76,28 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual ActiveObjectType getType() const = 0;
|
virtual ActiveObjectType getType() const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the collision box of the object.
|
||||||
|
* This box is translated by the object's
|
||||||
|
* location.
|
||||||
|
* The box's coordinates are world coordinates.
|
||||||
|
* @returns true if the object has a collision box.
|
||||||
|
*/
|
||||||
virtual bool getCollisionBox(aabb3f *toset) const = 0;
|
virtual bool getCollisionBox(aabb3f *toset) const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the selection box of the object.
|
||||||
|
* This box is not translated when the
|
||||||
|
* object moves.
|
||||||
|
* The box's coordinates are world coordinates.
|
||||||
|
* @returns true if the object has a selection box.
|
||||||
|
*/
|
||||||
|
virtual bool getSelectionBox(aabb3f *toset) const = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual bool collideWithObjects() const = 0;
|
virtual bool collideWithObjects() const = 0;
|
||||||
protected:
|
protected:
|
||||||
u16 m_id; // 0 is invalid, "no id"
|
u16 m_id; // 0 is invalid, "no id"
|
||||||
|
@ -604,240 +604,31 @@ ClientEnvEvent ClientEnvironment::getClientEnvEvent()
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientActiveObject * ClientEnvironment::getSelectedActiveObject(
|
void ClientEnvironment::getSelectedActiveObjects(
|
||||||
const core::line3d<f32> &shootline_on_map, v3f *intersection_point,
|
const core::line3d<f32> &shootline_on_map,
|
||||||
v3s16 *intersection_normal)
|
std::vector<PointedThing> &objects)
|
||||||
{
|
{
|
||||||
std::vector<DistanceSortedActiveObject> objects;
|
std::vector<DistanceSortedActiveObject> allObjects;
|
||||||
getActiveObjects(shootline_on_map.start,
|
getActiveObjects(shootline_on_map.start,
|
||||||
shootline_on_map.getLength() + 3, objects);
|
shootline_on_map.getLength() + 10.0f, allObjects);
|
||||||
const v3f line_vector = shootline_on_map.getVector();
|
const v3f line_vector = shootline_on_map.getVector();
|
||||||
|
|
||||||
// Sort them.
|
for (u32 i = 0; i < allObjects.size(); i++) {
|
||||||
// After this, the closest object is the first in the array.
|
ClientActiveObject *obj = allObjects[i].obj;
|
||||||
std::sort(objects.begin(), objects.end());
|
aabb3f selection_box;
|
||||||
|
if (!obj->getSelectionBox(&selection_box))
|
||||||
/* Because objects can have different nodebox sizes,
|
|
||||||
* the object whose center is the nearest isn't necessarily
|
|
||||||
* the closest one. If an object is found, don't stop
|
|
||||||
* immediately. */
|
|
||||||
|
|
||||||
f32 d_min = shootline_on_map.getLength();
|
|
||||||
ClientActiveObject *nearest_obj = NULL;
|
|
||||||
for (u32 i = 0; i < objects.size(); i++) {
|
|
||||||
ClientActiveObject *obj = objects[i].obj;
|
|
||||||
|
|
||||||
aabb3f *selection_box = obj->getSelectionBox();
|
|
||||||
if (selection_box == NULL)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
v3f pos = obj->getPosition();
|
v3f pos = obj->getPosition();
|
||||||
|
aabb3f offsetted_box(selection_box.MinEdge + pos,
|
||||||
aabb3f offsetted_box(selection_box->MinEdge + pos,
|
selection_box.MaxEdge + pos);
|
||||||
selection_box->MaxEdge + pos);
|
|
||||||
|
|
||||||
if (offsetted_box.getCenter().getDistanceFrom(
|
|
||||||
shootline_on_map.start) > d_min + 9.6f*BS) {
|
|
||||||
// Probably there is no active object that has bigger nodebox than
|
|
||||||
// (-5.5,-5.5,-5.5,5.5,5.5,5.5)
|
|
||||||
// 9.6 > 5.5*sqrt(3)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
v3f current_intersection;
|
v3f current_intersection;
|
||||||
v3s16 current_normal;
|
v3s16 current_normal;
|
||||||
if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
|
if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
|
||||||
¤t_intersection, ¤t_normal)) {
|
¤t_intersection, ¤t_normal)) {
|
||||||
f32 d_current = current_intersection.getDistanceFrom(
|
objects.push_back(PointedThing(
|
||||||
shootline_on_map.start);
|
(s16) obj->getId(), current_intersection, current_normal,
|
||||||
if (d_current <= d_min) {
|
(current_intersection - shootline_on_map.start).getLengthSQ()));
|
||||||
d_min = d_current;
|
|
||||||
nearest_obj = obj;
|
|
||||||
*intersection_point = current_intersection;
|
|
||||||
*intersection_normal = current_normal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nearest_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Check if a node is pointable
|
|
||||||
*/
|
|
||||||
static inline bool isPointableNode(const MapNode &n,
|
|
||||||
INodeDefManager *ndef, bool liquids_pointable)
|
|
||||||
{
|
|
||||||
const ContentFeatures &features = ndef->get(n);
|
|
||||||
return features.pointable ||
|
|
||||||
(liquids_pointable && features.isLiquid());
|
|
||||||
}
|
|
||||||
|
|
||||||
PointedThing ClientEnvironment::getPointedThing(
|
|
||||||
core::line3d<f32> shootline,
|
|
||||||
bool liquids_pointable,
|
|
||||||
bool look_for_object)
|
|
||||||
{
|
|
||||||
PointedThing result;
|
|
||||||
|
|
||||||
INodeDefManager *nodedef = m_map->getNodeDefManager();
|
|
||||||
|
|
||||||
core::aabbox3d<s16> maximal_exceed = nodedef->getSelectionBoxIntUnion();
|
|
||||||
// The code needs to search these nodes
|
|
||||||
core::aabbox3d<s16> search_range(-maximal_exceed.MaxEdge,
|
|
||||||
-maximal_exceed.MinEdge);
|
|
||||||
// If a node is found, there might be a larger node behind.
|
|
||||||
// To find it, we have to go further.
|
|
||||||
s16 maximal_overcheck =
|
|
||||||
std::max(abs(search_range.MinEdge.X), abs(search_range.MaxEdge.X))
|
|
||||||
+ std::max(abs(search_range.MinEdge.Y), abs(search_range.MaxEdge.Y))
|
|
||||||
+ std::max(abs(search_range.MinEdge.Z), abs(search_range.MaxEdge.Z));
|
|
||||||
|
|
||||||
const v3f original_vector = shootline.getVector();
|
|
||||||
const f32 original_length = original_vector.getLength();
|
|
||||||
|
|
||||||
f32 min_distance = original_length;
|
|
||||||
|
|
||||||
// First try to find an active object
|
|
||||||
if (look_for_object) {
|
|
||||||
ClientActiveObject *selected_object = getSelectedActiveObject(
|
|
||||||
shootline, &result.intersection_point,
|
|
||||||
&result.intersection_normal);
|
|
||||||
|
|
||||||
if (selected_object != NULL) {
|
|
||||||
min_distance =
|
|
||||||
(result.intersection_point - shootline.start).getLength();
|
|
||||||
|
|
||||||
result.type = POINTEDTHING_OBJECT;
|
|
||||||
result.object_id = selected_object->getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce shootline
|
|
||||||
if (original_length > 0) {
|
|
||||||
shootline.end = shootline.start
|
|
||||||
+ shootline.getVector() / original_length * min_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find a node that is closer than the selected active
|
|
||||||
// object (if it exists).
|
|
||||||
|
|
||||||
voxalgo::VoxelLineIterator iterator(shootline.start / BS,
|
|
||||||
shootline.getVector() / BS);
|
|
||||||
v3s16 oldnode = iterator.m_current_node_pos;
|
|
||||||
// Indicates that a node was found.
|
|
||||||
bool is_node_found = false;
|
|
||||||
// If a node is found, it is possible that there's a node
|
|
||||||
// behind it with a large nodebox, so continue the search.
|
|
||||||
u16 node_foundcounter = 0;
|
|
||||||
// If a node is found, this is the center of the
|
|
||||||
// first nodebox the shootline meets.
|
|
||||||
v3f found_boxcenter(0, 0, 0);
|
|
||||||
// The untested nodes are in this range.
|
|
||||||
core::aabbox3d<s16> new_nodes;
|
|
||||||
while (true) {
|
|
||||||
// Test the nodes around the current node in search_range.
|
|
||||||
new_nodes = search_range;
|
|
||||||
new_nodes.MinEdge += iterator.m_current_node_pos;
|
|
||||||
new_nodes.MaxEdge += iterator.m_current_node_pos;
|
|
||||||
|
|
||||||
// Only check new nodes
|
|
||||||
v3s16 delta = iterator.m_current_node_pos - oldnode;
|
|
||||||
if (delta.X > 0)
|
|
||||||
new_nodes.MinEdge.X = new_nodes.MaxEdge.X;
|
|
||||||
else if (delta.X < 0)
|
|
||||||
new_nodes.MaxEdge.X = new_nodes.MinEdge.X;
|
|
||||||
else if (delta.Y > 0)
|
|
||||||
new_nodes.MinEdge.Y = new_nodes.MaxEdge.Y;
|
|
||||||
else if (delta.Y < 0)
|
|
||||||
new_nodes.MaxEdge.Y = new_nodes.MinEdge.Y;
|
|
||||||
else if (delta.Z > 0)
|
|
||||||
new_nodes.MinEdge.Z = new_nodes.MaxEdge.Z;
|
|
||||||
else if (delta.Z < 0)
|
|
||||||
new_nodes.MaxEdge.Z = new_nodes.MinEdge.Z;
|
|
||||||
|
|
||||||
// For each untested node
|
|
||||||
for (s16 x = new_nodes.MinEdge.X; x <= new_nodes.MaxEdge.X; x++) {
|
|
||||||
for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) {
|
|
||||||
for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) {
|
|
||||||
MapNode n;
|
|
||||||
v3s16 np(x, y, z);
|
|
||||||
bool is_valid_position;
|
|
||||||
|
|
||||||
n = m_map->getNodeNoEx(np, &is_valid_position);
|
|
||||||
if (!(is_valid_position &&
|
|
||||||
isPointableNode(n, nodedef, liquids_pointable))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::vector<aabb3f> boxes;
|
|
||||||
n.getSelectionBoxes(nodedef, &boxes,
|
|
||||||
n.getNeighbors(np, m_map));
|
|
||||||
|
|
||||||
v3f npf = intToFloat(np, BS);
|
|
||||||
for (std::vector<aabb3f>::const_iterator i = boxes.begin();
|
|
||||||
i != boxes.end(); ++i) {
|
|
||||||
aabb3f box = *i;
|
|
||||||
box.MinEdge += npf;
|
|
||||||
box.MaxEdge += npf;
|
|
||||||
v3f intersection_point;
|
|
||||||
v3s16 intersection_normal;
|
|
||||||
if (!boxLineCollision(box, shootline.start, shootline.getVector(),
|
|
||||||
&intersection_point, &intersection_normal)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
f32 distance = (intersection_point - shootline.start).getLength();
|
|
||||||
if (distance >= min_distance) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result.type = POINTEDTHING_NODE;
|
|
||||||
result.node_undersurface = np;
|
|
||||||
result.intersection_point = intersection_point;
|
|
||||||
result.intersection_normal = intersection_normal;
|
|
||||||
found_boxcenter = box.getCenter();
|
|
||||||
min_distance = distance;
|
|
||||||
is_node_found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_node_found) {
|
|
||||||
node_foundcounter++;
|
|
||||||
if (node_foundcounter > maximal_overcheck) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Next node
|
|
||||||
if (iterator.hasNext()) {
|
|
||||||
oldnode = iterator.m_current_node_pos;
|
|
||||||
iterator.next();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_node_found) {
|
|
||||||
// Set undersurface and abovesurface nodes
|
|
||||||
f32 d = 0.002 * BS;
|
|
||||||
v3f fake_intersection = result.intersection_point;
|
|
||||||
// Move intersection towards its source block.
|
|
||||||
if (fake_intersection.X < found_boxcenter.X)
|
|
||||||
fake_intersection.X += d;
|
|
||||||
else
|
|
||||||
fake_intersection.X -= d;
|
|
||||||
|
|
||||||
if (fake_intersection.Y < found_boxcenter.Y)
|
|
||||||
fake_intersection.Y += d;
|
|
||||||
else
|
|
||||||
fake_intersection.Y -= d;
|
|
||||||
|
|
||||||
if (fake_intersection.Z < found_boxcenter.Z)
|
|
||||||
fake_intersection.Z += d;
|
|
||||||
else
|
|
||||||
fake_intersection.Z -= d;
|
|
||||||
|
|
||||||
result.node_real_undersurface = floatToInt(fake_intersection, BS);
|
|
||||||
result.node_abovesurface = result.node_real_undersurface
|
|
||||||
+ result.intersection_normal;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ class ClientScripting;
|
|||||||
class ClientActiveObject;
|
class ClientActiveObject;
|
||||||
class GenericCAO;
|
class GenericCAO;
|
||||||
class LocalPlayer;
|
class LocalPlayer;
|
||||||
struct PointedThing;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The client-side environment.
|
The client-side environment.
|
||||||
@ -125,44 +124,15 @@ public:
|
|||||||
std::vector<DistanceSortedActiveObject> &dest);
|
std::vector<DistanceSortedActiveObject> &dest);
|
||||||
|
|
||||||
bool hasClientEnvEvents() const { return !m_client_event_queue.empty(); }
|
bool hasClientEnvEvents() const { return !m_client_event_queue.empty(); }
|
||||||
|
|
||||||
// Get event from queue. If queue is empty, it triggers an assertion failure.
|
// Get event from queue. If queue is empty, it triggers an assertion failure.
|
||||||
ClientEnvEvent getClientEnvEvent();
|
ClientEnvEvent getClientEnvEvent();
|
||||||
|
|
||||||
/*!
|
virtual void getSelectedActiveObjects(
|
||||||
* Gets closest object pointed by the shootline.
|
|
||||||
* Returns NULL if not found.
|
|
||||||
*
|
|
||||||
* \param[in] shootline_on_map the shootline for
|
|
||||||
* the test in world coordinates
|
|
||||||
* \param[out] intersection_point the first point where
|
|
||||||
* the shootline meets the object. Valid only if
|
|
||||||
* not NULL is returned.
|
|
||||||
* \param[out] intersection_normal the normal vector of
|
|
||||||
* the intersection, pointing outwards. Zero vector if
|
|
||||||
* the shootline starts in an active object.
|
|
||||||
* Valid only if not NULL is returned.
|
|
||||||
*/
|
|
||||||
ClientActiveObject * getSelectedActiveObject(
|
|
||||||
const core::line3d<f32> &shootline_on_map,
|
const core::line3d<f32> &shootline_on_map,
|
||||||
v3f *intersection_point,
|
std::vector<PointedThing> &objects
|
||||||
v3s16 *intersection_normal
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/*!
|
|
||||||
* Performs a raycast on the world.
|
|
||||||
* Returns the first thing the shootline meets.
|
|
||||||
*
|
|
||||||
* @param[in] shootline the shootline, starting from
|
|
||||||
* the camera position. This also gives the maximal distance
|
|
||||||
* of the search.
|
|
||||||
* @param[in] liquids_pointable if false, liquids are ignored
|
|
||||||
* @param[in] look_for_object if false, objects are ignored
|
|
||||||
*/
|
|
||||||
PointedThing getPointedThing(
|
|
||||||
core::line3d<f32> shootline,
|
|
||||||
bool liquids_pointable,
|
|
||||||
bool look_for_object);
|
|
||||||
|
|
||||||
u16 attachement_parent_ids[USHRT_MAX + 1];
|
u16 attachement_parent_ids[USHRT_MAX + 1];
|
||||||
|
|
||||||
const std::list<std::string> &getPlayerNames() { return m_player_names; }
|
const std::list<std::string> &getPlayerNames() { return m_player_names; }
|
||||||
|
@ -44,8 +44,8 @@ public:
|
|||||||
virtual void updateLight(u8 light_at_pos){}
|
virtual void updateLight(u8 light_at_pos){}
|
||||||
virtual void updateLightNoCheck(u8 light_at_pos){}
|
virtual void updateLightNoCheck(u8 light_at_pos){}
|
||||||
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
|
virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
|
||||||
virtual aabb3f *getSelectionBox() { return NULL; }
|
|
||||||
virtual bool getCollisionBox(aabb3f *toset) const { return false; }
|
virtual bool getCollisionBox(aabb3f *toset) const { return false; }
|
||||||
|
virtual bool getSelectionBox(aabb3f *toset) const { return false; }
|
||||||
virtual bool collideWithObjects() const { return false; }
|
virtual bool collideWithObjects() const { return false; }
|
||||||
virtual v3f getPosition(){ return v3f(0,0,0); }
|
virtual v3f getPosition(){ return v3f(0,0,0); }
|
||||||
virtual float getYaw() const { return 0; }
|
virtual float getYaw() const { return 0; }
|
||||||
|
@ -283,8 +283,14 @@ public:
|
|||||||
|
|
||||||
void initialize(const std::string &data);
|
void initialize(const std::string &data);
|
||||||
|
|
||||||
aabb3f *getSelectionBox()
|
|
||||||
{return &m_selection_box;}
|
virtual bool getSelectionBox(aabb3f *toset) const
|
||||||
|
{
|
||||||
|
*toset = m_selection_box;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
v3f getPosition()
|
v3f getPosition()
|
||||||
{return m_position;}
|
{return m_position;}
|
||||||
inline float getYaw() const
|
inline float getYaw() const
|
||||||
@ -605,11 +611,14 @@ GenericCAO::~GenericCAO()
|
|||||||
removeFromScene(true);
|
removeFromScene(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
aabb3f *GenericCAO::getSelectionBox()
|
bool GenericCAO::getSelectionBox(aabb3f *toset) const
|
||||||
{
|
{
|
||||||
if(!m_prop.is_visible || !m_is_visible || m_is_local_player || getParent() != NULL)
|
if (!m_prop.is_visible || !m_is_visible || m_is_local_player
|
||||||
return NULL;
|
|| getParent() != NULL){
|
||||||
return &m_selection_box;
|
return false;
|
||||||
|
}
|
||||||
|
*toset = m_selection_box;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
v3f GenericCAO::getPosition()
|
v3f GenericCAO::getPosition()
|
||||||
@ -658,7 +667,7 @@ void GenericCAO::setAttachments()
|
|||||||
updateAttachments();
|
updateAttachments();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientActiveObject* GenericCAO::getParent()
|
ClientActiveObject* GenericCAO::getParent() const
|
||||||
{
|
{
|
||||||
ClientActiveObject *obj = NULL;
|
ClientActiveObject *obj = NULL;
|
||||||
|
|
||||||
|
@ -129,13 +129,13 @@ public:
|
|||||||
|
|
||||||
void processInitData(const std::string &data);
|
void processInitData(const std::string &data);
|
||||||
|
|
||||||
ClientActiveObject *getParent();
|
ClientActiveObject *getParent() const;
|
||||||
|
|
||||||
bool getCollisionBox(aabb3f *toset) const;
|
bool getCollisionBox(aabb3f *toset) const;
|
||||||
|
|
||||||
bool collideWithObjects() const;
|
bool collideWithObjects() const;
|
||||||
|
|
||||||
aabb3f *getSelectionBox();
|
virtual bool getSelectionBox(aabb3f *toset) const;
|
||||||
|
|
||||||
v3f getPosition();
|
v3f getPosition();
|
||||||
inline float getYaw() const
|
inline float getYaw() const
|
||||||
|
@ -91,6 +91,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool getCollisionBox(aabb3f *toset) const { return false; }
|
bool getCollisionBox(aabb3f *toset) const { return false; }
|
||||||
|
|
||||||
|
virtual bool getSelectionBox(aabb3f *toset) const { return false; }
|
||||||
|
|
||||||
bool collideWithObjects() const { return false; }
|
bool collideWithObjects() const { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -746,6 +749,18 @@ bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LuaEntitySAO::getSelectionBox(aabb3f *toset) const
|
||||||
|
{
|
||||||
|
if (!m_prop.is_visible) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
|
||||||
|
toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool LuaEntitySAO::collideWithObjects() const
|
bool LuaEntitySAO::collideWithObjects() const
|
||||||
{
|
{
|
||||||
return m_prop.collideWithObjects;
|
return m_prop.collideWithObjects;
|
||||||
@ -1405,3 +1420,14 @@ bool PlayerSAO::getCollisionBox(aabb3f *toset) const
|
|||||||
toset->MaxEdge += m_base_position;
|
toset->MaxEdge += m_base_position;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlayerSAO::getSelectionBox(aabb3f *toset) const
|
||||||
|
{
|
||||||
|
if (!m_prop.is_visible) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCollisionBox(toset);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -127,6 +127,7 @@ public:
|
|||||||
bool select_horiz_by_yawpitch);
|
bool select_horiz_by_yawpitch);
|
||||||
std::string getName();
|
std::string getName();
|
||||||
bool getCollisionBox(aabb3f *toset) const;
|
bool getCollisionBox(aabb3f *toset) const;
|
||||||
|
bool getSelectionBox(aabb3f *toset) const;
|
||||||
bool collideWithObjects() const;
|
bool collideWithObjects() const;
|
||||||
private:
|
private:
|
||||||
std::string getPropertyPacket();
|
std::string getPropertyPacket();
|
||||||
@ -357,6 +358,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool getCollisionBox(aabb3f *toset) const;
|
bool getCollisionBox(aabb3f *toset) const;
|
||||||
|
bool getSelectionBox(aabb3f *toset) const;
|
||||||
bool collideWithObjects() const { return true; }
|
bool collideWithObjects() const { return true; }
|
||||||
|
|
||||||
void finalize(RemotePlayer *player, const std::set<std::string> &privs);
|
void finalize(RemotePlayer *player, const std::set<std::string> &privs);
|
||||||
|
@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "collision.h"
|
#include "collision.h"
|
||||||
|
#include "raycast.h"
|
||||||
#include "serverobject.h"
|
#include "serverobject.h"
|
||||||
#include "scripting_server.h"
|
#include "scripting_server.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
@ -83,6 +84,179 @@ float Environment::getTimeOfDayF()
|
|||||||
return m_time_of_day_f;
|
return m_time_of_day_f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if a node is pointable
|
||||||
|
*/
|
||||||
|
inline static bool isPointableNode(const MapNode &n,
|
||||||
|
INodeDefManager *nodedef , bool liquids_pointable)
|
||||||
|
{
|
||||||
|
const ContentFeatures &features = nodedef->get(n);
|
||||||
|
return features.pointable ||
|
||||||
|
(liquids_pointable && features.isLiquid());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Environment::continueRaycast(RaycastState *state, PointedThing *result)
|
||||||
|
{
|
||||||
|
INodeDefManager *nodedef = getMap().getNodeDefManager();
|
||||||
|
if (state->m_initialization_needed) {
|
||||||
|
// Add objects
|
||||||
|
if (state->m_objects_pointable) {
|
||||||
|
std::vector<PointedThing> found;
|
||||||
|
getSelectedActiveObjects(state->m_shootline, found);
|
||||||
|
for (std::vector<PointedThing>::iterator pointed = found.begin();
|
||||||
|
pointed != found.end(); ++pointed) {
|
||||||
|
state->m_found.push(*pointed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set search range
|
||||||
|
core::aabbox3d<s16> maximal_exceed = nodedef->getSelectionBoxIntUnion();
|
||||||
|
state->m_search_range.MinEdge = -maximal_exceed.MaxEdge;
|
||||||
|
state->m_search_range.MaxEdge = -maximal_exceed.MinEdge;
|
||||||
|
// Setting is done
|
||||||
|
state->m_initialization_needed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The index of the first pointed thing that was not returned
|
||||||
|
// before. The last index which needs to be tested.
|
||||||
|
s16 lastIndex = state->m_iterator.m_last_index;
|
||||||
|
if (!state->m_found.empty()) {
|
||||||
|
lastIndex = state->m_iterator.getIndex(
|
||||||
|
floatToInt(state->m_found.top().intersection_point, BS));
|
||||||
|
}
|
||||||
|
|
||||||
|
Map &map = getMap();
|
||||||
|
// If a node is found, this is the center of the
|
||||||
|
// first nodebox the shootline meets.
|
||||||
|
v3f found_boxcenter(0, 0, 0);
|
||||||
|
// The untested nodes are in this range.
|
||||||
|
core::aabbox3d<s16> new_nodes;
|
||||||
|
while (state->m_iterator.m_current_index <= lastIndex) {
|
||||||
|
// Test the nodes around the current node in search_range.
|
||||||
|
new_nodes = state->m_search_range;
|
||||||
|
new_nodes.MinEdge += state->m_iterator.m_current_node_pos;
|
||||||
|
new_nodes.MaxEdge += state->m_iterator.m_current_node_pos;
|
||||||
|
|
||||||
|
// Only check new nodes
|
||||||
|
v3s16 delta = state->m_iterator.m_current_node_pos
|
||||||
|
- state->m_previous_node;
|
||||||
|
if (delta.X > 0) {
|
||||||
|
new_nodes.MinEdge.X = new_nodes.MaxEdge.X;
|
||||||
|
} else if (delta.X < 0) {
|
||||||
|
new_nodes.MaxEdge.X = new_nodes.MinEdge.X;
|
||||||
|
} else if (delta.Y > 0) {
|
||||||
|
new_nodes.MinEdge.Y = new_nodes.MaxEdge.Y;
|
||||||
|
} else if (delta.Y < 0) {
|
||||||
|
new_nodes.MaxEdge.Y = new_nodes.MinEdge.Y;
|
||||||
|
} else if (delta.Z > 0) {
|
||||||
|
new_nodes.MinEdge.Z = new_nodes.MaxEdge.Z;
|
||||||
|
} else if (delta.Z < 0) {
|
||||||
|
new_nodes.MaxEdge.Z = new_nodes.MinEdge.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each untested node
|
||||||
|
for (s16 x = new_nodes.MinEdge.X; x <= new_nodes.MaxEdge.X; x++)
|
||||||
|
for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++)
|
||||||
|
for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) {
|
||||||
|
MapNode n;
|
||||||
|
v3s16 np(x, y, z);
|
||||||
|
bool is_valid_position;
|
||||||
|
|
||||||
|
n = map.getNodeNoEx(np, &is_valid_position);
|
||||||
|
if (!(is_valid_position && isPointableNode(n, nodedef,
|
||||||
|
state->m_liquids_pointable))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PointedThing result;
|
||||||
|
|
||||||
|
std::vector<aabb3f> boxes;
|
||||||
|
n.getSelectionBoxes(nodedef, &boxes,
|
||||||
|
n.getNeighbors(np, &map));
|
||||||
|
|
||||||
|
// Is there a collision with a selection box?
|
||||||
|
bool is_colliding = false;
|
||||||
|
// Minimal distance of all collisions
|
||||||
|
float min_distance_sq = 10000000;
|
||||||
|
|
||||||
|
v3f npf = intToFloat(np, BS);
|
||||||
|
for (std::vector<aabb3f>::const_iterator i = boxes.begin();
|
||||||
|
i != boxes.end(); ++i) {
|
||||||
|
// Get current collision box
|
||||||
|
aabb3f box = *i;
|
||||||
|
box.MinEdge += npf;
|
||||||
|
box.MaxEdge += npf;
|
||||||
|
|
||||||
|
v3f intersection_point;
|
||||||
|
v3s16 intersection_normal;
|
||||||
|
if (!boxLineCollision(box, state->m_shootline.start,
|
||||||
|
state->m_shootline.getVector(), &intersection_point,
|
||||||
|
&intersection_normal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
f32 distanceSq = (intersection_point
|
||||||
|
- state->m_shootline.start).getLengthSQ();
|
||||||
|
// If this is the nearest collision, save it
|
||||||
|
if (min_distance_sq > distanceSq) {
|
||||||
|
min_distance_sq = distanceSq;
|
||||||
|
result.intersection_point = intersection_point;
|
||||||
|
result.intersection_normal = intersection_normal;
|
||||||
|
found_boxcenter = box.getCenter();
|
||||||
|
is_colliding = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If there wasn't a collision, stop
|
||||||
|
if (!is_colliding) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.type = POINTEDTHING_NODE;
|
||||||
|
result.node_undersurface = np;
|
||||||
|
result.distanceSq = min_distance_sq;
|
||||||
|
// Set undersurface and abovesurface nodes
|
||||||
|
f32 d = 0.002 * BS;
|
||||||
|
v3f fake_intersection = result.intersection_point;
|
||||||
|
// Move intersection towards its source block.
|
||||||
|
if (fake_intersection.X < found_boxcenter.X) {
|
||||||
|
fake_intersection.X += d;
|
||||||
|
} else {
|
||||||
|
fake_intersection.X -= d;
|
||||||
|
}
|
||||||
|
if (fake_intersection.Y < found_boxcenter.Y) {
|
||||||
|
fake_intersection.Y += d;
|
||||||
|
} else {
|
||||||
|
fake_intersection.Y -= d;
|
||||||
|
}
|
||||||
|
if (fake_intersection.Z < found_boxcenter.Z) {
|
||||||
|
fake_intersection.Z += d;
|
||||||
|
} else {
|
||||||
|
fake_intersection.Z -= d;
|
||||||
|
}
|
||||||
|
result.node_real_undersurface = floatToInt(
|
||||||
|
fake_intersection, BS);
|
||||||
|
result.node_abovesurface = result.node_real_undersurface
|
||||||
|
+ result.intersection_normal;
|
||||||
|
// Push found PointedThing
|
||||||
|
state->m_found.push(result);
|
||||||
|
// If this is nearer than the old nearest object,
|
||||||
|
// the search can be shorter
|
||||||
|
s16 newIndex = state->m_iterator.getIndex(
|
||||||
|
result.node_real_undersurface);
|
||||||
|
if (newIndex < lastIndex) {
|
||||||
|
lastIndex = newIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Next node
|
||||||
|
state->m_previous_node = state->m_iterator.m_current_node_pos;
|
||||||
|
state->m_iterator.next();
|
||||||
|
}
|
||||||
|
// Return empty PointedThing if nothing left on the ray
|
||||||
|
if (state->m_found.empty()) {
|
||||||
|
result->type = POINTEDTHING_NOTHING;
|
||||||
|
} else {
|
||||||
|
*result = state->m_found.top();
|
||||||
|
state->m_found.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Environment::stepTimeOfDay(float dtime)
|
void Environment::stepTimeOfDay(float dtime)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(this->m_time_lock);
|
MutexAutoLock lock(this->m_time_lock);
|
||||||
|
@ -42,6 +42,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
class IGameDef;
|
class IGameDef;
|
||||||
class Map;
|
class Map;
|
||||||
|
struct PointedThing;
|
||||||
|
class RaycastState;
|
||||||
|
|
||||||
class Environment
|
class Environment
|
||||||
{
|
{
|
||||||
@ -76,6 +78,26 @@ public:
|
|||||||
|
|
||||||
u32 getDayCount();
|
u32 getDayCount();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Gets the objects pointed by the shootline as
|
||||||
|
* pointed things.
|
||||||
|
* If this is a client environment, the local player
|
||||||
|
* won't be returned.
|
||||||
|
* @param[in] shootline_on_map the shootline for
|
||||||
|
* the test in world coordinates
|
||||||
|
*
|
||||||
|
* @param[out] objects found objects
|
||||||
|
*/
|
||||||
|
virtual void getSelectedActiveObjects(const core::line3d<f32> &shootline_on_map,
|
||||||
|
std::vector<PointedThing> &objects) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the next node or object the shootline meets.
|
||||||
|
* @param state current state of the raycast
|
||||||
|
* @result output, will contain the next pointed thing
|
||||||
|
*/
|
||||||
|
void continueRaycast(RaycastState *state, PointedThing *result);
|
||||||
|
|
||||||
// counter used internally when triggering ABMs
|
// counter used internally when triggering ABMs
|
||||||
u32 m_added_objects;
|
u32 m_added_objects;
|
||||||
|
|
||||||
|
27
src/game.cpp
27
src/game.cpp
@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "particles.h"
|
#include "particles.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "quicktune_shortcutter.h"
|
#include "quicktune_shortcutter.h"
|
||||||
|
#include "raycast.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "sky.h"
|
#include "sky.h"
|
||||||
@ -3667,28 +3668,22 @@ PointedThing Game::updatePointedThing(
|
|||||||
static thread_local const bool show_entity_selectionbox = g_settings->getBool(
|
static thread_local const bool show_entity_selectionbox = g_settings->getBool(
|
||||||
"show_entity_selectionbox");
|
"show_entity_selectionbox");
|
||||||
|
|
||||||
ClientMap &map = client->getEnv().getClientMap();
|
ClientEnvironment &env = client->getEnv();
|
||||||
INodeDefManager *nodedef=client->getNodeDefManager();
|
ClientMap &map = env.getClientMap();
|
||||||
|
INodeDefManager *nodedef = map.getNodeDefManager();
|
||||||
|
|
||||||
runData.selected_object = NULL;
|
runData.selected_object = NULL;
|
||||||
|
|
||||||
PointedThing result=client->getEnv().getPointedThing(
|
RaycastState s(shootline, look_for_object, liquids_pointable);
|
||||||
shootline, liquids_pointable, look_for_object);
|
PointedThing result;
|
||||||
|
env.continueRaycast(&s, &result);
|
||||||
if (result.type == POINTEDTHING_OBJECT) {
|
if (result.type == POINTEDTHING_OBJECT) {
|
||||||
runData.selected_object = client->getEnv().getActiveObject(result.object_id);
|
runData.selected_object = client->getEnv().getActiveObject(result.object_id);
|
||||||
if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox()) {
|
aabb3f selection_box;
|
||||||
aabb3f *selection_box = runData.selected_object->getSelectionBox();
|
if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox() &&
|
||||||
|
runData.selected_object->getSelectionBox(&selection_box)) {
|
||||||
// Box should exist because object was
|
|
||||||
// returned in the first place
|
|
||||||
|
|
||||||
assert(selection_box);
|
|
||||||
|
|
||||||
v3f pos = runData.selected_object->getPosition();
|
v3f pos = runData.selected_object->getPosition();
|
||||||
selectionboxes->push_back(aabb3f(
|
selectionboxes->push_back(aabb3f(selection_box));
|
||||||
selection_box->MinEdge, selection_box->MaxEdge));
|
|
||||||
selectionboxes->push_back(
|
|
||||||
aabb3f(selection_box->MinEdge, selection_box->MaxEdge));
|
|
||||||
hud->setSelectionPos(pos, camera_offset);
|
hud->setSelectionPos(pos, camera_offset);
|
||||||
}
|
}
|
||||||
} else if (result.type == POINTEDTHING_NODE) {
|
} else if (result.type == POINTEDTHING_NODE) {
|
||||||
|
@ -17,11 +17,47 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "raycast.h"
|
||||||
#include "irr_v3d.h"
|
#include "irr_v3d.h"
|
||||||
#include "irr_aabb3d.h"
|
#include "irr_aabb3d.h"
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
|
bool RaycastSort::operator() (const PointedThing &pt1,
|
||||||
|
const PointedThing &pt2) const
|
||||||
|
{
|
||||||
|
// "nothing" can not be sorted
|
||||||
|
assert(pt1.type != POINTEDTHING_NOTHING);
|
||||||
|
assert(pt2.type != POINTEDTHING_NOTHING);
|
||||||
|
// returns false if pt1 is nearer than pt2
|
||||||
|
if (pt1.distanceSq < pt2.distanceSq) {
|
||||||
|
return false;
|
||||||
|
} else if (pt1.distanceSq == pt2.distanceSq) {
|
||||||
|
// Sort them to allow only one order
|
||||||
|
if (pt1.type == POINTEDTHING_OBJECT)
|
||||||
|
return (pt2.type == POINTEDTHING_OBJECT
|
||||||
|
&& pt1.object_id < pt2.object_id);
|
||||||
|
else
|
||||||
|
return (pt2.type == POINTEDTHING_OBJECT
|
||||||
|
|| pt1.node_undersurface < pt2.node_undersurface);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RaycastState::RaycastState(const core::line3d<f32> &shootline,
|
||||||
|
bool objects_pointable, bool liquids_pointable) :
|
||||||
|
m_shootline(shootline),
|
||||||
|
m_iterator(shootline.start / BS, shootline.getVector() / BS),
|
||||||
|
m_previous_node(m_iterator.m_current_node_pos),
|
||||||
|
m_objects_pointable(objects_pointable),
|
||||||
|
m_liquids_pointable(liquids_pointable)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool boxLineCollision(const aabb3f &box, const v3f &start,
|
bool boxLineCollision(const aabb3f &box, const v3f &start,
|
||||||
const v3f &dir, v3f *collision_point, v3s16 *collision_normal) {
|
const v3f &dir, v3f *collision_point, v3s16 *collision_normal)
|
||||||
|
{
|
||||||
if (box.isPointInside(start)) {
|
if (box.isPointInside(start)) {
|
||||||
*collision_point = start;
|
*collision_point = start;
|
||||||
collision_normal->set(0, 0, 0);
|
collision_normal->set(0, 0, 0);
|
||||||
|
@ -20,6 +20,49 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#ifndef SRC_RAYCAST_H_
|
#ifndef SRC_RAYCAST_H_
|
||||||
#define SRC_RAYCAST_H_
|
#define SRC_RAYCAST_H_
|
||||||
|
|
||||||
|
#include "voxelalgorithms.h"
|
||||||
|
#include "util/pointedthing.h"
|
||||||
|
|
||||||
|
//! Sorts PointedThings based on their distance.
|
||||||
|
struct RaycastSort
|
||||||
|
{
|
||||||
|
bool operator() (const PointedThing &pt1, const PointedThing &pt2) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Describes the state of a raycast.
|
||||||
|
class RaycastState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
* Creates a raycast.
|
||||||
|
* @param objects_pointable if false, only nodes will be found
|
||||||
|
* @param liquids pointable if false, liquid nodes won't be found
|
||||||
|
*/
|
||||||
|
RaycastState(const core::line3d<f32> &shootline, bool objects_pointable,
|
||||||
|
bool liquids_pointable);
|
||||||
|
|
||||||
|
//! Shootline of the raycast.
|
||||||
|
core::line3d<f32> m_shootline;
|
||||||
|
//! Iterator to store the progress of the raycast.
|
||||||
|
voxalgo::VoxelLineIterator m_iterator;
|
||||||
|
//! Previous tested node during the raycast.
|
||||||
|
v3s16 m_previous_node;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This priority queue stores the found pointed things
|
||||||
|
* waiting to be returned.
|
||||||
|
*/
|
||||||
|
std::priority_queue<PointedThing, std::vector<PointedThing>, RaycastSort> m_found;
|
||||||
|
|
||||||
|
bool m_objects_pointable;
|
||||||
|
bool m_liquids_pointable;
|
||||||
|
|
||||||
|
//! The code needs to search these nodes around the center node.
|
||||||
|
core::aabbox3d<s16> m_search_range { 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
//! If true, the Environment will initialize this state.
|
||||||
|
bool m_initialization_needed = true;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Checks if a line and a box intersects.
|
* Checks if a line and a box intersects.
|
||||||
|
@ -52,6 +52,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
friend class LuaItemStack;
|
friend class LuaItemStack;
|
||||||
friend class ModApiItemMod;
|
friend class ModApiItemMod;
|
||||||
|
friend class LuaRaycast;
|
||||||
|
|
||||||
bool getItemCallback(const char *name, const char *callbackname);
|
bool getItemCallback(const char *name, const char *callbackname);
|
||||||
void pushPointedThing(const PointedThing& pointed);
|
void pushPointedThing(const PointedThing& pointed);
|
||||||
|
@ -131,6 +131,105 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
|
|||||||
lua_pop(L, 1); // Pop error handler
|
lua_pop(L, 1); // Pop error handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LuaRaycast::l_next(lua_State *L)
|
||||||
|
{
|
||||||
|
MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
ScriptApiItem *script = getScriptApi<ScriptApiItem>(L);
|
||||||
|
GET_ENV_PTR;
|
||||||
|
|
||||||
|
LuaRaycast *o = checkobject(L, 1);
|
||||||
|
PointedThing pointed;
|
||||||
|
env->continueRaycast(&o->state, &pointed);
|
||||||
|
if (pointed.type == POINTEDTHING_NOTHING)
|
||||||
|
lua_pushnil(L);
|
||||||
|
else
|
||||||
|
script->pushPointedThing(pointed);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LuaRaycast::create_object(lua_State *L)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
bool objects = true;
|
||||||
|
bool liquids = false;
|
||||||
|
|
||||||
|
v3f pos1 = checkFloatPos(L, 1);
|
||||||
|
v3f pos2 = checkFloatPos(L, 2);
|
||||||
|
if (lua_isboolean(L, 3)) {
|
||||||
|
objects = lua_toboolean(L, 3);
|
||||||
|
}
|
||||||
|
if (lua_isboolean(L, 4)) {
|
||||||
|
liquids = lua_toboolean(L, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2),
|
||||||
|
objects, liquids);
|
||||||
|
|
||||||
|
*(void **) (lua_newuserdata(L, sizeof(void *))) = o;
|
||||||
|
luaL_getmetatable(L, className);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaRaycast *LuaRaycast::checkobject(lua_State *L, int narg)
|
||||||
|
{
|
||||||
|
NO_MAP_LOCK_REQUIRED;
|
||||||
|
|
||||||
|
luaL_checktype(L, narg, LUA_TUSERDATA);
|
||||||
|
void *ud = luaL_checkudata(L, narg, className);
|
||||||
|
if (!ud)
|
||||||
|
luaL_typerror(L, narg, className);
|
||||||
|
return *(LuaRaycast **) ud;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LuaRaycast::gc_object(lua_State *L)
|
||||||
|
{
|
||||||
|
LuaRaycast *o = *(LuaRaycast **) (lua_touserdata(L, 1));
|
||||||
|
delete o;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaRaycast::Register(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_newtable(L);
|
||||||
|
int methodtable = lua_gettop(L);
|
||||||
|
luaL_newmetatable(L, className);
|
||||||
|
int metatable = lua_gettop(L);
|
||||||
|
|
||||||
|
lua_pushliteral(L, "__metatable");
|
||||||
|
lua_pushvalue(L, methodtable);
|
||||||
|
lua_settable(L, metatable);
|
||||||
|
|
||||||
|
lua_pushliteral(L, "__index");
|
||||||
|
lua_pushvalue(L, methodtable);
|
||||||
|
lua_settable(L, metatable);
|
||||||
|
|
||||||
|
lua_pushliteral(L, "__gc");
|
||||||
|
lua_pushcfunction(L, gc_object);
|
||||||
|
lua_settable(L, metatable);
|
||||||
|
|
||||||
|
lua_pushliteral(L, "__call");
|
||||||
|
lua_pushcfunction(L, l_next);
|
||||||
|
lua_settable(L, metatable);
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
luaL_openlib(L, 0, methods, 0);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
lua_register(L, className, create_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char LuaRaycast::className[] = "Raycast";
|
||||||
|
const luaL_Reg LuaRaycast::methods[] =
|
||||||
|
{
|
||||||
|
luamethod(LuaRaycast, next),
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
|
void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
|
||||||
{
|
{
|
||||||
ScriptCallbackState *state = (ScriptCallbackState *)param;
|
ScriptCallbackState *state = (ScriptCallbackState *)param;
|
||||||
@ -904,6 +1003,11 @@ int ModApiEnvMod::l_fix_light(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ModApiEnvMod::l_raycast(lua_State *L)
|
||||||
|
{
|
||||||
|
return LuaRaycast::create_object(L);
|
||||||
|
}
|
||||||
|
|
||||||
// emerge_area(p1, p2, [callback, context])
|
// emerge_area(p1, p2, [callback, context])
|
||||||
// emerge mapblocks in area p1..p2, calls callback with context upon completion
|
// emerge mapblocks in area p1..p2, calls callback with context upon completion
|
||||||
int ModApiEnvMod::l_emerge_area(lua_State *L)
|
int ModApiEnvMod::l_emerge_area(lua_State *L)
|
||||||
@ -1155,6 +1259,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
|
|||||||
API_FCT(spawn_tree);
|
API_FCT(spawn_tree);
|
||||||
API_FCT(find_path);
|
API_FCT(find_path);
|
||||||
API_FCT(line_of_sight);
|
API_FCT(line_of_sight);
|
||||||
|
API_FCT(raycast);
|
||||||
API_FCT(transforming_liquid_add);
|
API_FCT(transforming_liquid_add);
|
||||||
API_FCT(forceload_block);
|
API_FCT(forceload_block);
|
||||||
API_FCT(forceload_free_block);
|
API_FCT(forceload_free_block);
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "lua_api/l_base.h"
|
#include "lua_api/l_base.h"
|
||||||
#include "serverenvironment.h"
|
#include "serverenvironment.h"
|
||||||
|
#include "raycast.h"
|
||||||
|
|
||||||
class ModApiEnvMod : public ModApiBase {
|
class ModApiEnvMod : public ModApiBase {
|
||||||
private:
|
private:
|
||||||
@ -159,6 +160,9 @@ private:
|
|||||||
// line_of_sight(pos1, pos2, stepsize) -> true/false
|
// line_of_sight(pos1, pos2, stepsize) -> true/false
|
||||||
static int l_line_of_sight(lua_State *L);
|
static int l_line_of_sight(lua_State *L);
|
||||||
|
|
||||||
|
// raycast(pos1, pos2, objects, liquids) -> Raycast
|
||||||
|
static int l_raycast(lua_State *L);
|
||||||
|
|
||||||
// find_path(pos1, pos2, searchdistance,
|
// find_path(pos1, pos2, searchdistance,
|
||||||
// max_jump, max_drop, algorithm) -> table containing path
|
// max_jump, max_drop, algorithm) -> table containing path
|
||||||
static int l_find_path(lua_State *L);
|
static int l_find_path(lua_State *L);
|
||||||
@ -245,6 +249,47 @@ public:
|
|||||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n);
|
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Lua wrapper for RaycastState objects
|
||||||
|
class LuaRaycast : public ModApiBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static const char className[];
|
||||||
|
static const luaL_Reg methods[];
|
||||||
|
//! Inner state
|
||||||
|
RaycastState state;
|
||||||
|
|
||||||
|
// Exported functions
|
||||||
|
|
||||||
|
// garbage collector
|
||||||
|
static int gc_object(lua_State *L);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Raycast:next() -> pointed_thing
|
||||||
|
* Returns the next pointed thing on the ray.
|
||||||
|
*/
|
||||||
|
static int l_next(lua_State *L);
|
||||||
|
public:
|
||||||
|
//! Constructor with the same arguments as RaycastState.
|
||||||
|
LuaRaycast(
|
||||||
|
const core::line3d<f32> &shootline,
|
||||||
|
bool objects_pointable,
|
||||||
|
bool liquids_pointable) :
|
||||||
|
state(shootline, objects_pointable, liquids_pointable)
|
||||||
|
{}
|
||||||
|
|
||||||
|
//! Creates a LuaRaycast and leaves it on top of the stack.
|
||||||
|
static int create_object(lua_State *L);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the Raycast from the stack or throws an error.
|
||||||
|
* @param narg location of the RaycastState in the stack
|
||||||
|
*/
|
||||||
|
static LuaRaycast *checkobject(lua_State *L, int narg);
|
||||||
|
|
||||||
|
//! Registers Raycast as a Lua userdata type.
|
||||||
|
static void Register(lua_State *L);
|
||||||
|
};
|
||||||
|
|
||||||
struct ScriptCallbackState {
|
struct ScriptCallbackState {
|
||||||
ServerScripting *script;
|
ServerScripting *script;
|
||||||
int callback_ref;
|
int callback_ref;
|
||||||
|
@ -92,6 +92,7 @@ void ServerScripting::InitializeModApi(lua_State *L, int top)
|
|||||||
LuaPerlinNoiseMap::Register(L);
|
LuaPerlinNoiseMap::Register(L);
|
||||||
LuaPseudoRandom::Register(L);
|
LuaPseudoRandom::Register(L);
|
||||||
LuaPcgRandom::Register(L);
|
LuaPcgRandom::Register(L);
|
||||||
|
LuaRaycast::Register(L);
|
||||||
LuaSecureRandom::Register(L);
|
LuaSecureRandom::Register(L);
|
||||||
LuaVoxelManip::Register(L);
|
LuaVoxelManip::Register(L);
|
||||||
NodeMetaRef::Register(L);
|
NodeMetaRef::Register(L);
|
||||||
|
@ -30,7 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
#include "scripting_server.h"
|
#include "scripting_server.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "voxelalgorithms.h"
|
|
||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include "util/basic_macros.h"
|
#include "util/basic_macros.h"
|
||||||
#include "util/pointedthing.h"
|
#include "util/pointedthing.h"
|
||||||
@ -1662,6 +1661,38 @@ ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ServerEnvironment::getSelectedActiveObjects(
|
||||||
|
const core::line3d<f32> &shootline_on_map,
|
||||||
|
std::vector<PointedThing> &objects)
|
||||||
|
{
|
||||||
|
std::vector<u16> objectIds;
|
||||||
|
getObjectsInsideRadius(objectIds, shootline_on_map.start,
|
||||||
|
shootline_on_map.getLength() + 10.0f);
|
||||||
|
const v3f line_vector = shootline_on_map.getVector();
|
||||||
|
|
||||||
|
for (u32 i = 0; i < objectIds.size(); i++) {
|
||||||
|
ServerActiveObject* obj = getActiveObject(objectIds[i]);
|
||||||
|
|
||||||
|
aabb3f selection_box;
|
||||||
|
if (!obj->getSelectionBox(&selection_box))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
v3f pos = obj->getBasePosition();
|
||||||
|
|
||||||
|
aabb3f offsetted_box(selection_box.MinEdge + pos,
|
||||||
|
selection_box.MaxEdge + pos);
|
||||||
|
|
||||||
|
v3f current_intersection;
|
||||||
|
v3s16 current_normal;
|
||||||
|
if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
|
||||||
|
¤t_intersection, ¤t_normal)) {
|
||||||
|
objects.push_back(PointedThing(
|
||||||
|
(s16) objectIds[i], current_intersection, current_normal,
|
||||||
|
(current_intersection - shootline_on_map.start).getLengthSQ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
************ Private methods *************
|
************ Private methods *************
|
||||||
*/
|
*/
|
||||||
|
@ -284,6 +284,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
ActiveObjectMessage getActiveObjectMessage();
|
ActiveObjectMessage getActiveObjectMessage();
|
||||||
|
|
||||||
|
virtual void getSelectedActiveObjects(
|
||||||
|
const core::line3d<f32> &shootline_on_map,
|
||||||
|
std::vector<PointedThing> &objects
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Activate objects and dynamically modify for the dtime determined
|
Activate objects and dynamically modify for the dtime determined
|
||||||
from timestamp and additional_dtime
|
from timestamp and additional_dtime
|
||||||
|
@ -23,20 +23,47 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "../exceptions.h"
|
#include "../exceptions.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
PointedThing::PointedThing(const v3s16 &under, const v3s16 &above,
|
||||||
|
const v3s16 &real_under, const v3f &point, const v3s16 &normal,
|
||||||
|
f32 distSq):
|
||||||
|
type(POINTEDTHING_NODE),
|
||||||
|
node_undersurface(under),
|
||||||
|
node_abovesurface(above),
|
||||||
|
node_real_undersurface(real_under),
|
||||||
|
intersection_point(point),
|
||||||
|
intersection_normal(normal),
|
||||||
|
distanceSq(distSq)
|
||||||
|
{}
|
||||||
|
|
||||||
|
PointedThing::PointedThing(s16 id, const v3f &point, const v3s16 &normal,
|
||||||
|
f32 distSq) :
|
||||||
|
type(POINTEDTHING_OBJECT),
|
||||||
|
object_id(id),
|
||||||
|
intersection_point(point),
|
||||||
|
intersection_normal(normal),
|
||||||
|
distanceSq(distSq)
|
||||||
|
{}
|
||||||
|
|
||||||
std::string PointedThing::dump() const
|
std::string PointedThing::dump() const
|
||||||
{
|
{
|
||||||
std::ostringstream os(std::ios::binary);
|
std::ostringstream os(std::ios::binary);
|
||||||
if (type == POINTEDTHING_NOTHING) {
|
switch (type) {
|
||||||
os<<"[nothing]";
|
case POINTEDTHING_NOTHING:
|
||||||
} else if (type == POINTEDTHING_NODE) {
|
os << "[nothing]";
|
||||||
|
break;
|
||||||
|
case POINTEDTHING_NODE:
|
||||||
|
{
|
||||||
const v3s16 &u = node_undersurface;
|
const v3s16 &u = node_undersurface;
|
||||||
const v3s16 &a = node_abovesurface;
|
const v3s16 &a = node_abovesurface;
|
||||||
os<<"[node under="<<u.X<<","<<u.Y<<","<<u.Z
|
os << "[node under=" << u.X << "," << u.Y << "," << u.Z << " above="
|
||||||
<< " above="<<a.X<<","<<a.Y<<","<<a.Z<<"]";
|
<< a.X << "," << a.Y << "," << a.Z << "]";
|
||||||
} else if (type == POINTEDTHING_OBJECT) {
|
}
|
||||||
os<<"[object "<<object_id<<"]";
|
break;
|
||||||
} else {
|
case POINTEDTHING_OBJECT:
|
||||||
os<<"[unknown PointedThing]";
|
os << "[object " << object_id << "]";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
os << "[unknown PointedThing]";
|
||||||
}
|
}
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
@ -104,4 +131,3 @@ bool PointedThing::operator!=(const PointedThing &pt2) const
|
|||||||
{
|
{
|
||||||
return !(*this == pt2);
|
return !(*this == pt2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,11 @@ struct PointedThing
|
|||||||
* point of the collision and the nodebox of the node.
|
* point of the collision and the nodebox of the node.
|
||||||
*/
|
*/
|
||||||
v3s16 node_real_undersurface;
|
v3s16 node_real_undersurface;
|
||||||
|
/*!
|
||||||
|
* Only valid if type is POINTEDTHING_OBJECT.
|
||||||
|
* The ID of the object the ray hit.
|
||||||
|
*/
|
||||||
|
s16 object_id = -1;
|
||||||
/*!
|
/*!
|
||||||
* Only valid if type isn't POINTEDTHING_NONE.
|
* Only valid if type isn't POINTEDTHING_NONE.
|
||||||
* First intersection point of the ray and the nodebox.
|
* First intersection point of the ray and the nodebox.
|
||||||
@ -71,12 +76,19 @@ struct PointedThing
|
|||||||
*/
|
*/
|
||||||
v3s16 intersection_normal;
|
v3s16 intersection_normal;
|
||||||
/*!
|
/*!
|
||||||
* Only valid if type is POINTEDTHING_OBJECT.
|
* Square of the distance between the pointing
|
||||||
* The ID of the object the ray hit.
|
* ray's start point and the intersection point.
|
||||||
*/
|
*/
|
||||||
s16 object_id = -1;
|
f32 distanceSq = 0;
|
||||||
|
|
||||||
|
//! Constructor for POINTEDTHING_NOTHING
|
||||||
PointedThing() {};
|
PointedThing() {};
|
||||||
|
//! Constructor for POINTEDTHING_NODE
|
||||||
|
PointedThing(const v3s16 &under, const v3s16 &above,
|
||||||
|
const v3s16 &real_under, const v3f &point, const v3s16 &normal,
|
||||||
|
f32 distSq);
|
||||||
|
//! Constructor for POINTEDTHING_OBJECT
|
||||||
|
PointedThing(s16 id, const v3f &point, const v3s16 &normal, f32 distSq);
|
||||||
std::string dump() const;
|
std::string dump() const;
|
||||||
void serialize(std::ostream &os) const;
|
void serialize(std::ostream &os) const;
|
||||||
void deSerialize(std::istream &is);
|
void deSerialize(std::istream &is);
|
||||||
|
@ -1407,6 +1407,8 @@ VoxelLineIterator::VoxelLineIterator(const v3f &start_position, const v3f &line_
|
|||||||
m_line_vector(line_vector)
|
m_line_vector(line_vector)
|
||||||
{
|
{
|
||||||
m_current_node_pos = floatToInt(m_start_position, 1);
|
m_current_node_pos = floatToInt(m_start_position, 1);
|
||||||
|
m_start_node_pos = m_current_node_pos;
|
||||||
|
m_last_index = getIndex(floatToInt(start_position + line_vector, 1));
|
||||||
|
|
||||||
if (m_line_vector.X > 0) {
|
if (m_line_vector.X > 0) {
|
||||||
m_next_intersection_multi.X = (floorf(m_start_position.X - 0.5) + 1.5
|
m_next_intersection_multi.X = (floorf(m_start_position.X - 0.5) + 1.5
|
||||||
@ -1440,14 +1442,11 @@ VoxelLineIterator::VoxelLineIterator(const v3f &start_position, const v3f &line_
|
|||||||
m_intersection_multi_inc.Z = -1 / m_line_vector.Z;
|
m_intersection_multi_inc.Z = -1 / m_line_vector.Z;
|
||||||
m_step_directions.Z = -1;
|
m_step_directions.Z = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_has_next = (m_next_intersection_multi.X <= 1)
|
|
||||||
|| (m_next_intersection_multi.Y <= 1)
|
|
||||||
|| (m_next_intersection_multi.Z <= 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelLineIterator::next()
|
void VoxelLineIterator::next()
|
||||||
{
|
{
|
||||||
|
m_current_index++;
|
||||||
if ((m_next_intersection_multi.X < m_next_intersection_multi.Y)
|
if ((m_next_intersection_multi.X < m_next_intersection_multi.Y)
|
||||||
&& (m_next_intersection_multi.X < m_next_intersection_multi.Z)) {
|
&& (m_next_intersection_multi.X < m_next_intersection_multi.Z)) {
|
||||||
m_next_intersection_multi.X += m_intersection_multi_inc.X;
|
m_next_intersection_multi.X += m_intersection_multi_inc.X;
|
||||||
@ -1459,10 +1458,13 @@ void VoxelLineIterator::next()
|
|||||||
m_next_intersection_multi.Z += m_intersection_multi_inc.Z;
|
m_next_intersection_multi.Z += m_intersection_multi_inc.Z;
|
||||||
m_current_node_pos.Z += m_step_directions.Z;
|
m_current_node_pos.Z += m_step_directions.Z;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_has_next = (m_next_intersection_multi.X <= 1)
|
s16 VoxelLineIterator::getIndex(v3s16 voxel){
|
||||||
|| (m_next_intersection_multi.Y <= 1)
|
return
|
||||||
|| (m_next_intersection_multi.Z <= 1);
|
abs(voxel.X - m_start_node_pos.X) +
|
||||||
|
abs(voxel.Y - m_start_node_pos.Y) +
|
||||||
|
abs(voxel.Z - m_start_node_pos.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace voxalgo
|
} // namespace voxalgo
|
||||||
|
@ -123,21 +123,25 @@ public:
|
|||||||
* which multiplying the line's vector gives a vector that ends
|
* which multiplying the line's vector gives a vector that ends
|
||||||
* on the intersection of two nodes.
|
* on the intersection of two nodes.
|
||||||
*/
|
*/
|
||||||
v3f m_next_intersection_multi = v3f(10000.0f, 10000.0f, 10000.0f);
|
v3f m_next_intersection_multi { 10000.0f, 10000.0f, 10000.0f };
|
||||||
/*!
|
/*!
|
||||||
* Each component stores the smallest positive number, by which
|
* Each component stores the smallest positive number, by which
|
||||||
* m_next_intersection_multi's components can be increased.
|
* m_next_intersection_multi's components can be increased.
|
||||||
*/
|
*/
|
||||||
v3f m_intersection_multi_inc = v3f(10000.0f, 10000.0f, 10000.0f);
|
v3f m_intersection_multi_inc { 10000.0f, 10000.0f, 10000.0f };
|
||||||
/*!
|
/*!
|
||||||
* Direction of the line. Each component can be -1 or 1 (if a
|
* Direction of the line. Each component can be -1 or 1 (if a
|
||||||
* component of the line's vector is 0, then there will be 1).
|
* component of the line's vector is 0, then there will be 1).
|
||||||
*/
|
*/
|
||||||
v3s16 m_step_directions = v3s16(1, 1, 1);
|
v3s16 m_step_directions { 1, 1, 1 };
|
||||||
//! Position of the current node.
|
//! Position of the current node.
|
||||||
v3s16 m_current_node_pos;
|
v3s16 m_current_node_pos;
|
||||||
//! If true, the next node will intersect the line, too.
|
//! Index of the current node
|
||||||
bool m_has_next;
|
s16 m_current_index = 0;
|
||||||
|
//! Position of the start node.
|
||||||
|
v3s16 m_start_node_pos;
|
||||||
|
//! Index of the last node
|
||||||
|
s16 m_last_index;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Creates a voxel line iterator with the given line.
|
* Creates a voxel line iterator with the given line.
|
||||||
@ -161,7 +165,18 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
* Returns true if the next voxel intersects the given line.
|
* Returns true if the next voxel intersects the given line.
|
||||||
*/
|
*/
|
||||||
inline bool hasNext() const { return m_has_next; }
|
inline bool hasNext() const
|
||||||
|
{
|
||||||
|
return m_current_index < m_last_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns how many times next() must be called until
|
||||||
|
* voxel==m_current_node_pos.
|
||||||
|
* If voxel does not intersect with the line,
|
||||||
|
* the result is undefined.
|
||||||
|
*/
|
||||||
|
s16 getIndex(v3s16 voxel);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace voxalgo
|
} // namespace voxalgo
|
||||||
|
Loading…
Reference in New Issue
Block a user