forked from Mirrorlandia_minetest/minetest
Tool specific pointing and blocking pointable type (#13992)
This commit is contained in:
parent
fb461d21a5
commit
5958714309
@ -33,6 +33,8 @@ core.features = {
|
||||
random_state_restore = true,
|
||||
after_order_expiry_registration = true,
|
||||
wallmounted_rotate = true,
|
||||
item_specific_pointabilities = true,
|
||||
blocking_pointability_type = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
@ -5298,6 +5298,10 @@ Utilities
|
||||
-- wallmounted nodes mounted at floor or ceiling may additionally
|
||||
-- be rotated by 90° with special param2 values (5.9.0)
|
||||
wallmounted_rotate = true,
|
||||
-- Availability of the `pointabilities` property in the item definition (5.9.0)
|
||||
item_specific_pointabilities = true,
|
||||
-- Nodes `pointable` property can be `"blocking"` (5.9.0)
|
||||
blocking_pointability_type = true,
|
||||
}
|
||||
```
|
||||
|
||||
@ -8382,7 +8386,9 @@ Player properties need to be saved manually.
|
||||
|
||||
|
||||
pointable = true,
|
||||
-- Whether the object can be pointed at
|
||||
-- Can be `true` if it is pointable, `false` if it can be pointed through,
|
||||
-- or `"blocking"` if it is pointable but not selectable.
|
||||
-- Can be overridden by the `pointabilities` of the held item.
|
||||
|
||||
visual = "cube" / "sprite" / "upright_sprite" / "mesh" / "wielditem" / "item",
|
||||
-- "cube" is a node-sized cube.
|
||||
@ -8746,6 +8752,27 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
|
||||
-- If true, item can point to all liquid nodes (`liquidtype ~= "none"`),
|
||||
-- even those for which `pointable = false`
|
||||
|
||||
pointabilities = {
|
||||
nodes = {
|
||||
["default:stone"] = "blocking",
|
||||
["group:leaves"] = false,
|
||||
},
|
||||
objects = {
|
||||
["modname:entityname"] = true,
|
||||
["group:ghosty"] = true, -- (an armor group)
|
||||
}
|
||||
},
|
||||
-- Contains lists to override the `pointable` property of pointed nodes and objects.
|
||||
-- The index can be a node/entity name or a group with the prefix `"group:"`.
|
||||
-- (For objects `armor_groups` are used and for players the entity name is irrelevant.)
|
||||
-- If multiple fields fit, the following priority order is applied:
|
||||
-- value of matching node/entity name
|
||||
-- `true` for any group
|
||||
-- `false` for any group
|
||||
-- `"blocking"` for any group
|
||||
-- `liquids_pointable` if it is a liquid node
|
||||
-- `pointable` property of the node or object
|
||||
|
||||
light_source = 0,
|
||||
-- When used for nodes: Defines amount of light emitted by node.
|
||||
-- Otherwise: Defines texture glow when viewed as a dropped item
|
||||
@ -8971,7 +8998,11 @@ Used by `minetest.register_node`.
|
||||
|
||||
walkable = true, -- If true, objects collide with node
|
||||
|
||||
pointable = true, -- If true, can be pointed at
|
||||
pointable = true,
|
||||
-- Can be `true` if it is pointable, `false` if it can be pointed through,
|
||||
-- or `"blocking"` if it is pointable but not selectable.
|
||||
-- Can be overridden by the `pointabilities` of the held item.
|
||||
-- A client may be able to point non-pointable nodes, since it isn't checked server-side.
|
||||
|
||||
diggable = true, -- If false, can never be dug
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
dofile(minetest.get_modpath("testentities").."/visuals.lua")
|
||||
dofile(minetest.get_modpath("testentities").."/selectionbox.lua")
|
||||
dofile(minetest.get_modpath("testentities").."/armor.lua")
|
||||
dofile(minetest.get_modpath("testentities").."/pointable.lua")
|
||||
|
23
games/devtest/mods/testentities/pointable.lua
Normal file
23
games/devtest/mods/testentities/pointable.lua
Normal file
@ -0,0 +1,23 @@
|
||||
-- Pointability test Entities
|
||||
|
||||
-- Register wrapper for compactness
|
||||
local function register_pointable_testentity(name, pointable)
|
||||
local texture = "testnodes_"..name..".png"
|
||||
minetest.register_entity("testentities:"..name, {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
visual_size = {x = 0.6, y = 0.6, z = 0.6},
|
||||
textures = {
|
||||
texture, texture, texture, texture, texture, texture
|
||||
},
|
||||
pointable = pointable,
|
||||
},
|
||||
on_activate = function(self)
|
||||
self.object:set_armor_groups({[name.."_test"] = 1})
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
register_pointable_testentity("pointable", true)
|
||||
register_pointable_testentity("not_pointable", false)
|
||||
register_pointable_testentity("blocking_pointable", "blocking")
|
@ -663,3 +663,23 @@ minetest.register_node("testnodes:post_effect_color_shaded_true", {
|
||||
is_ground_content = false,
|
||||
groups = {dig_immediate=3},
|
||||
})
|
||||
|
||||
-- Pointability
|
||||
|
||||
-- Register wrapper for compactness
|
||||
local function register_pointable_test_node(name, description, pointable)
|
||||
local texture = "testnodes_"..name..".png"
|
||||
minetest.register_node("testnodes:"..name, {
|
||||
description = S(description),
|
||||
tiles = {texture},
|
||||
drawtype = "glasslike_framed",
|
||||
paramtype = "light",
|
||||
walkable = false,
|
||||
pointable = pointable,
|
||||
groups = {dig_immediate=3, [name.."_test"]=1},
|
||||
})
|
||||
end
|
||||
|
||||
register_pointable_test_node("pointable", "Pointable Node", true)
|
||||
register_pointable_test_node("not_pointable", "Not Pointable Node", false)
|
||||
register_pointable_test_node("blocking_pointable", "Blocking Pointable Node", "blocking")
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 150 B |
Binary file not shown.
After Width: | Height: | Size: 152 B |
BIN
games/devtest/mods/testnodes/textures/testnodes_pointable.png
Normal file
BIN
games/devtest/mods/testnodes/textures/testnodes_pointable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 144 B |
@ -7,6 +7,20 @@ dofile(minetest.get_modpath("testtools") .. "/light.lua")
|
||||
dofile(minetest.get_modpath("testtools") .. "/privatizer.lua")
|
||||
dofile(minetest.get_modpath("testtools") .. "/particles.lua")
|
||||
|
||||
local pointabilities_nodes = {
|
||||
nodes = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:not_pointable_test"] = true,
|
||||
},
|
||||
}
|
||||
|
||||
local pointabilities_objects = {
|
||||
objects = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:not_pointable_test"] = true,
|
||||
},
|
||||
}
|
||||
|
||||
minetest.register_tool("testtools:param2tool", {
|
||||
description = S("Param2 Tool") .."\n"..
|
||||
S("Modify param2 value of nodes") .."\n"..
|
||||
@ -16,6 +30,7 @@ minetest.register_tool("testtools:param2tool", {
|
||||
S("Sneak+Place: -8"),
|
||||
inventory_image = "testtools_param2tool.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_nodes,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
if pointed_thing.type ~= "node" or (not pos) then
|
||||
@ -58,6 +73,7 @@ minetest.register_tool("testtools:node_setter", {
|
||||
S("Place in air: Manually select a node"),
|
||||
inventory_image = "testtools_node_setter.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_nodes,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
if pointed_thing.type == "nothing" then
|
||||
@ -118,6 +134,10 @@ minetest.register_tool("testtools:remover", {
|
||||
S("Punch: Remove pointed node or object"),
|
||||
inventory_image = "testtools_remover.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = {
|
||||
nodes = pointabilities_nodes.nodes,
|
||||
objects = pointabilities_objects.objects,
|
||||
},
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
if pointed_thing.type == "node" and pos ~= nil then
|
||||
@ -139,6 +159,7 @@ minetest.register_tool("testtools:falling_node_tool", {
|
||||
S("Place: Move pointed node 2 units upwards, then make it fall"),
|
||||
inventory_image = "testtools_falling_node_tool.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_nodes,
|
||||
on_place = function(itemstack, user, pointed_thing)
|
||||
-- Teleport node 1-2 units upwards (if possible) and make it fall
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
@ -192,6 +213,7 @@ minetest.register_tool("testtools:rotator", {
|
||||
S("Aux1+Punch: Roll"),
|
||||
inventory_image = "testtools_entity_rotator.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if pointed_thing.type ~= "object" then
|
||||
return
|
||||
@ -250,6 +272,7 @@ minetest.register_tool("testtools:object_mover", {
|
||||
S("Sneak+Place: Decrease distance"),
|
||||
inventory_image = "testtools_object_mover.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_place = mover_config,
|
||||
on_secondary_use = mover_config,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
@ -296,6 +319,7 @@ minetest.register_tool("testtools:entity_scaler", {
|
||||
S("Sneak+Punch: Decrease scale"),
|
||||
inventory_image = "testtools_entity_scaler.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if pointed_thing.type ~= "object" then
|
||||
return
|
||||
@ -355,6 +379,7 @@ minetest.register_tool("testtools:branding_iron", {
|
||||
S("Devices that accept the returned name also accept \"player:<playername>\" for players."),
|
||||
inventory_image = "testtools_branding_iron.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(_itemstack, user, pointed_thing)
|
||||
local obj
|
||||
local msg
|
||||
@ -499,6 +524,7 @@ minetest.register_tool("testtools:object_editor", {
|
||||
S("Punch air: Edit yourself"),
|
||||
inventory_image = "testtools_object_editor.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if user and user:is_player() then
|
||||
local name = user:get_player_name()
|
||||
@ -586,6 +612,7 @@ minetest.register_tool("testtools:object_attacher", {
|
||||
S("Aux1+Sneak+Place: Decrease attachment rotation"),
|
||||
inventory_image = "testtools_object_attacher.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_place = attacher_config,
|
||||
on_secondary_use = attacher_config,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
@ -679,6 +706,7 @@ minetest.register_tool("testtools:children_getter", {
|
||||
S("Punch air to show your own 'children'"),
|
||||
inventory_image = "testtools_children_getter.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
pointabilities = pointabilities_objects,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if user and user:is_player() then
|
||||
local name = user:get_player_name()
|
||||
@ -998,3 +1026,41 @@ minetest.register_on_leaveplayer(function(player)
|
||||
meta_latest_keylist[name] = nil
|
||||
node_meta_posses[name] = nil
|
||||
end)
|
||||
|
||||
-- Pointing Staffs
|
||||
|
||||
minetest.register_tool("testtools:blocked_pointing_staff", {
|
||||
description = S("Blocked Pointing Staff").."\n"..
|
||||
S("Can point the Blocking Pointable Node/Object and "..
|
||||
"the Pointable Node/Object is point blocking."),
|
||||
inventory_image = "testtools_blocked_pointing_staff.png",
|
||||
pointabilities = {
|
||||
nodes = {
|
||||
["testnodes:blocking_pointable"] = true,
|
||||
["group:pointable_test"] = "blocking"
|
||||
},
|
||||
objects = {
|
||||
["testentities:blocking_pointable"] = true,
|
||||
["group:pointable_test"] = "blocking"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_tool("testtools:ultimate_pointing_staff", {
|
||||
description = S("Ultimate Pointing Staff").."\n"..
|
||||
S("Can point all pointable test nodes, objects and liquids."),
|
||||
inventory_image = "testtools_ultimate_pointing_staff.png",
|
||||
liquids_pointable = true,
|
||||
pointabilities = {
|
||||
nodes = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:pointable_test"] = true,
|
||||
["testnodes:not_pointable"] = true
|
||||
},
|
||||
objects = {
|
||||
["group:blocking_pointable_test"] = true,
|
||||
["group:pointable_test"] = true,
|
||||
["testentities:not_pointable"] = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 136 B |
Binary file not shown.
After Width: | Height: | Size: 136 B |
@ -489,7 +489,8 @@ ClientEnvEvent ClientEnvironment::getClientEnvEvent()
|
||||
|
||||
void ClientEnvironment::getSelectedActiveObjects(
|
||||
const core::line3d<f32> &shootline_on_map,
|
||||
std::vector<PointedThing> &objects)
|
||||
std::vector<PointedThing> &objects,
|
||||
const std::optional<Pointabilities> &pointabilities)
|
||||
{
|
||||
auto allObjects = m_ao_manager.getActiveSelectableObjects(shootline_on_map);
|
||||
const v3f line_vector = shootline_on_map.getVector();
|
||||
@ -516,9 +517,23 @@ void ClientEnvironment::getSelectedActiveObjects(
|
||||
current_raw_normal = current_normal;
|
||||
}
|
||||
if (collision) {
|
||||
PointabilityType pointable;
|
||||
if (pointabilities) {
|
||||
if (gcao->isPlayer()) {
|
||||
pointable = pointabilities->matchPlayer(gcao->getGroups()).value_or(
|
||||
gcao->getProperties().pointable);
|
||||
} else {
|
||||
pointable = pointabilities->matchObject(gcao->getName(),
|
||||
gcao->getGroups()).value_or(gcao->getProperties().pointable);
|
||||
}
|
||||
} else {
|
||||
pointable = gcao->getProperties().pointable;
|
||||
}
|
||||
if (pointable != PointabilityType::POINTABLE_NOT) {
|
||||
current_intersection += obj->getPosition();
|
||||
objects.emplace_back(obj->getId(), current_intersection, current_normal, current_raw_normal,
|
||||
(current_intersection - shootline_on_map.start).getLengthSQ());
|
||||
(current_intersection - shootline_on_map.start).getLengthSQ(), pointable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,8 @@ public:
|
||||
|
||||
virtual void getSelectedActiveObjects(
|
||||
const core::line3d<f32> &shootline_on_map,
|
||||
std::vector<PointedThing> &objects
|
||||
std::vector<PointedThing> &objects,
|
||||
const std::optional<Pointabilities> &pointabilities
|
||||
);
|
||||
|
||||
const std::set<std::string> &getPlayerNames() { return m_player_names; }
|
||||
|
@ -411,8 +411,7 @@ GenericCAO::~GenericCAO()
|
||||
|
||||
bool GenericCAO::getSelectionBox(aabb3f *toset) const
|
||||
{
|
||||
if (!m_prop.is_visible || !m_is_visible || m_is_local_player
|
||||
|| !m_prop.pointable) {
|
||||
if (!m_prop.is_visible || !m_is_visible || m_is_local_player) {
|
||||
return false;
|
||||
}
|
||||
*toset = m_selection_box;
|
||||
|
@ -174,6 +174,8 @@ public:
|
||||
|
||||
inline const ObjectProperties &getProperties() const { return m_prop; }
|
||||
|
||||
inline const std::string &getName() const { return m_name; }
|
||||
|
||||
scene::ISceneNode *getSceneNode() const override;
|
||||
|
||||
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const override;
|
||||
@ -208,6 +210,11 @@ public:
|
||||
return m_is_local_player;
|
||||
}
|
||||
|
||||
inline bool isPlayer() const
|
||||
{
|
||||
return m_is_player;
|
||||
}
|
||||
|
||||
inline bool isVisible() const
|
||||
{
|
||||
return m_is_visible;
|
||||
|
@ -841,6 +841,7 @@ protected:
|
||||
* the camera position. This also gives the maximal distance
|
||||
* of the search.
|
||||
* @param[in] liquids_pointable if false, liquids are ignored
|
||||
* @param[in] pointabilities item specific pointable overriding
|
||||
* @param[in] look_for_object if false, objects are ignored
|
||||
* @param[in] camera_offset offset of the camera
|
||||
* @param[out] selected_object the selected object or
|
||||
@ -848,6 +849,7 @@ protected:
|
||||
*/
|
||||
PointedThing updatePointedThing(
|
||||
const core::line3d<f32> &shootline, bool liquids_pointable,
|
||||
const std::optional<Pointabilities> &pointabilities,
|
||||
bool look_for_object, const v3s16 &camera_offset);
|
||||
void handlePointingAtNothing(const ItemStack &playerItem);
|
||||
void handlePointingAtNode(const PointedThing &pointed,
|
||||
@ -3343,6 +3345,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
||||
|
||||
PointedThing pointed = updatePointedThing(shootline,
|
||||
selected_def.liquids_pointable,
|
||||
selected_def.pointabilities,
|
||||
!runData.btn_down_for_dig,
|
||||
camera_offset);
|
||||
|
||||
@ -3454,6 +3457,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
|
||||
PointedThing Game::updatePointedThing(
|
||||
const core::line3d<f32> &shootline,
|
||||
bool liquids_pointable,
|
||||
const std::optional<Pointabilities> &pointabilities,
|
||||
bool look_for_object,
|
||||
const v3s16 &camera_offset)
|
||||
{
|
||||
@ -3470,7 +3474,7 @@ PointedThing Game::updatePointedThing(
|
||||
runData.selected_object = NULL;
|
||||
hud->pointing_at_object = false;
|
||||
|
||||
RaycastState s(shootline, look_for_object, liquids_pointable);
|
||||
RaycastState s(shootline, look_for_object, liquids_pointable, pointabilities);
|
||||
PointedThing result;
|
||||
env.continueRaycast(&s, &result);
|
||||
if (result.type == POINTEDTHING_OBJECT) {
|
||||
|
@ -102,24 +102,33 @@ bool Environment::line_of_sight(v3f pos1, v3f pos2, v3s16 *p)
|
||||
}
|
||||
|
||||
/*
|
||||
Check if a node is pointable
|
||||
Check how a node can be pointed at
|
||||
*/
|
||||
inline static bool isPointableNode(const MapNode &n,
|
||||
const NodeDefManager *nodedef , bool liquids_pointable)
|
||||
inline static PointabilityType isPointableNode(const MapNode &n,
|
||||
const NodeDefManager *nodedef, bool liquids_pointable,
|
||||
const std::optional<Pointabilities> &pointabilities)
|
||||
{
|
||||
const ContentFeatures &features = nodedef->get(n);
|
||||
return features.pointable ||
|
||||
(liquids_pointable && features.isLiquid());
|
||||
if (pointabilities) {
|
||||
std::optional<PointabilityType> match =
|
||||
pointabilities->matchNode(features.name, features.groups);
|
||||
if (match)
|
||||
return match.value();
|
||||
}
|
||||
|
||||
void Environment::continueRaycast(RaycastState *state, PointedThing *result)
|
||||
if (features.isLiquid() && liquids_pointable)
|
||||
return PointabilityType::POINTABLE;
|
||||
return features.pointable;
|
||||
}
|
||||
|
||||
void Environment::continueRaycast(RaycastState *state, PointedThing *result_p)
|
||||
{
|
||||
const NodeDefManager *nodedef = getMap().getNodeDefManager();
|
||||
if (state->m_initialization_needed) {
|
||||
// Add objects
|
||||
if (state->m_objects_pointable) {
|
||||
std::vector<PointedThing> found;
|
||||
getSelectedActiveObjects(state->m_shootline, found);
|
||||
getSelectedActiveObjects(state->m_shootline, found, state->m_pointabilities);
|
||||
for (const PointedThing &pointed : found) {
|
||||
state->m_found.push(pointed);
|
||||
}
|
||||
@ -184,10 +193,15 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
|
||||
bool is_valid_position;
|
||||
|
||||
n = map.getNode(np, &is_valid_position);
|
||||
if (!(is_valid_position && isPointableNode(n, nodedef,
|
||||
state->m_liquids_pointable))) {
|
||||
if (!is_valid_position)
|
||||
continue;
|
||||
|
||||
PointabilityType pointable = isPointableNode(n, nodedef,
|
||||
state->m_liquids_pointable,
|
||||
state->m_pointabilities);
|
||||
// If it can be pointed through skip
|
||||
if (pointable == PointabilityType::POINTABLE_NOT)
|
||||
continue;
|
||||
}
|
||||
|
||||
PointedThing result;
|
||||
|
||||
@ -234,6 +248,7 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
|
||||
if (!is_colliding) {
|
||||
continue;
|
||||
}
|
||||
result.pointability = pointable;
|
||||
result.type = POINTEDTHING_NODE;
|
||||
result.node_undersurface = np;
|
||||
result.distanceSq = min_distance_sq;
|
||||
@ -275,12 +290,16 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
|
||||
state->m_previous_node = state->m_iterator.m_current_node_pos;
|
||||
state->m_iterator.next();
|
||||
}
|
||||
// Return empty PointedThing if nothing left on the ray
|
||||
|
||||
// Return empty PointedThing if nothing left on the ray or it is blocking pointable
|
||||
if (state->m_found.empty()) {
|
||||
result->type = POINTEDTHING_NOTHING;
|
||||
result_p->type = POINTEDTHING_NOTHING;
|
||||
} else {
|
||||
*result = state->m_found.top();
|
||||
*result_p = state->m_found.top();
|
||||
state->m_found.pop();
|
||||
if (result_p->pointability == PointabilityType::POINTABLE_BLOCKING) {
|
||||
result_p->type = POINTEDTHING_NOTHING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include "irr_v3d.h"
|
||||
#include "util/basic_macros.h"
|
||||
#include "line3d.h"
|
||||
@ -42,6 +43,7 @@ class IGameDef;
|
||||
class Map;
|
||||
struct PointedThing;
|
||||
class RaycastState;
|
||||
struct Pointabilities;
|
||||
|
||||
class Environment
|
||||
{
|
||||
@ -97,7 +99,8 @@ public:
|
||||
* @param[out] objects found objects
|
||||
*/
|
||||
virtual void getSelectedActiveObjects(const core::line3d<f32> &shootline_on_map,
|
||||
std::vector<PointedThing> &objects) = 0;
|
||||
std::vector<PointedThing> &objects,
|
||||
const std::optional<Pointabilities> &pointabilities) = 0;
|
||||
|
||||
/*!
|
||||
* Returns the next node or object the shootline meets.
|
||||
|
@ -122,6 +122,7 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
|
||||
stack_max = def.stack_max;
|
||||
usable = def.usable;
|
||||
liquids_pointable = def.liquids_pointable;
|
||||
pointabilities = def.pointabilities;
|
||||
if (def.tool_capabilities)
|
||||
tool_capabilities = new ToolCapabilities(*def.tool_capabilities);
|
||||
groups = def.groups;
|
||||
@ -167,6 +168,7 @@ void ItemDefinition::reset()
|
||||
stack_max = 99;
|
||||
usable = false;
|
||||
liquids_pointable = false;
|
||||
pointabilities = std::nullopt;
|
||||
delete tool_capabilities;
|
||||
tool_capabilities = NULL;
|
||||
groups.clear();
|
||||
@ -241,6 +243,14 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
|
||||
|
||||
writeU8(os, wallmounted_rotate_vertical);
|
||||
touch_interaction.serialize(os);
|
||||
|
||||
std::string pointabilities_s;
|
||||
if (pointabilities) {
|
||||
std::ostringstream tmp_os(std::ios::binary);
|
||||
pointabilities->serialize(tmp_os);
|
||||
pointabilities_s = tmp_os.str();
|
||||
}
|
||||
os << serializeString16(pointabilities_s);
|
||||
}
|
||||
|
||||
void ItemDefinition::deSerialize(std::istream &is, u16 protocol_version)
|
||||
@ -316,6 +326,13 @@ void ItemDefinition::deSerialize(std::istream &is, u16 protocol_version)
|
||||
|
||||
wallmounted_rotate_vertical = readU8(is); // 0 if missing
|
||||
touch_interaction.deSerialize(is);
|
||||
|
||||
std::string pointabilities_s = deSerializeString16(is);
|
||||
if (!pointabilities_s.empty()) {
|
||||
std::istringstream tmp_is(pointabilities_s, std::ios::binary);
|
||||
pointabilities = std::make_optional<Pointabilities>();
|
||||
pointabilities->deSerialize(tmp_is);
|
||||
}
|
||||
} catch(SerializationError &e) {};
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "itemgroup.h"
|
||||
#include "sound.h"
|
||||
#include "texture_override.h" // TextureOverride
|
||||
#include "util/pointabilities.h"
|
||||
class IGameDef;
|
||||
class Client;
|
||||
struct ToolCapabilities;
|
||||
@ -97,8 +98,11 @@ struct ItemDefinition
|
||||
u16 stack_max;
|
||||
bool usable;
|
||||
bool liquids_pointable;
|
||||
// May be NULL. If non-NULL, deleted by destructor
|
||||
std::optional<Pointabilities> pointabilities;
|
||||
|
||||
// They may be NULL. If non-NULL, deleted by destructor
|
||||
ToolCapabilities *tool_capabilities;
|
||||
|
||||
ItemGroupList groups;
|
||||
SoundSpec sound_place;
|
||||
SoundSpec sound_place_failed;
|
||||
|
@ -386,7 +386,7 @@ void ContentFeatures::reset()
|
||||
light_propagates = false;
|
||||
sunlight_propagates = false;
|
||||
walkable = true;
|
||||
pointable = true;
|
||||
pointable = PointabilityType::POINTABLE;
|
||||
diggable = true;
|
||||
climbable = false;
|
||||
buildable_to = false;
|
||||
@ -504,7 +504,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
|
||||
|
||||
// interaction
|
||||
writeU8(os, walkable);
|
||||
writeU8(os, pointable);
|
||||
Pointabilities::serializePointabilityType(os, pointable);
|
||||
writeU8(os, diggable);
|
||||
writeU8(os, climbable);
|
||||
writeU8(os, buildable_to);
|
||||
@ -617,7 +617,7 @@ void ContentFeatures::deSerialize(std::istream &is, u16 protocol_version)
|
||||
|
||||
// interaction
|
||||
walkable = readU8(is);
|
||||
pointable = readU8(is);
|
||||
pointable = Pointabilities::deSerializePointabilityType(is);
|
||||
diggable = readU8(is);
|
||||
climbable = readU8(is);
|
||||
buildable_to = readU8(is);
|
||||
@ -1083,7 +1083,7 @@ void NodeDefManager::clear()
|
||||
f.light_propagates = true;
|
||||
f.sunlight_propagates = true;
|
||||
f.walkable = false;
|
||||
f.pointable = false;
|
||||
f.pointable = PointabilityType::POINTABLE_NOT;
|
||||
f.diggable = false;
|
||||
f.buildable_to = true;
|
||||
f.floodable = true;
|
||||
@ -1104,7 +1104,7 @@ void NodeDefManager::clear()
|
||||
f.light_propagates = false;
|
||||
f.sunlight_propagates = false;
|
||||
f.walkable = false;
|
||||
f.pointable = false;
|
||||
f.pointable = PointabilityType::POINTABLE_NOT;
|
||||
f.diggable = false;
|
||||
f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs
|
||||
f.is_ground_content = true;
|
||||
|
@ -35,6 +35,7 @@ class Client;
|
||||
#include "constants.h" // BS
|
||||
#include "texture_override.h" // TextureOverride
|
||||
#include "tileanimation.h"
|
||||
#include "util/pointabilities.h"
|
||||
|
||||
class IItemDefManager;
|
||||
class ITextureSource;
|
||||
@ -395,8 +396,8 @@ struct ContentFeatures
|
||||
// This is used for collision detection.
|
||||
// Also for general solidness queries.
|
||||
bool walkable;
|
||||
// Player can point to these
|
||||
bool pointable;
|
||||
// Player can point to these, point through or it is blocking
|
||||
PointabilityType pointable;
|
||||
// Player can dig these
|
||||
bool diggable;
|
||||
// Player can climb these
|
||||
|
@ -73,7 +73,7 @@ std::string ObjectProperties::dump()
|
||||
|
||||
os << ", selectionbox=" << selectionbox.MinEdge << "," << selectionbox.MaxEdge;
|
||||
os << ", rotate_selectionbox=" << rotate_selectionbox;
|
||||
os << ", pointable=" << pointable;
|
||||
os << ", pointable=" << Pointabilities::toStringPointabilityType(pointable);
|
||||
os << ", static_save=" << static_save;
|
||||
os << ", eye_height=" << eye_height;
|
||||
os << ", zoom_fov=" << zoom_fov;
|
||||
@ -127,7 +127,7 @@ void ObjectProperties::serialize(std::ostream &os) const
|
||||
writeV3F32(os, collisionbox.MaxEdge);
|
||||
writeV3F32(os, selectionbox.MinEdge);
|
||||
writeV3F32(os, selectionbox.MaxEdge);
|
||||
writeU8(os, pointable);
|
||||
Pointabilities::serializePointabilityType(os, pointable);
|
||||
os << serializeString16(visual);
|
||||
writeV3F32(os, visual_size);
|
||||
writeU16(os, textures.size());
|
||||
@ -188,7 +188,7 @@ void ObjectProperties::deSerialize(std::istream &is)
|
||||
collisionbox.MaxEdge = readV3F32(is);
|
||||
selectionbox.MinEdge = readV3F32(is);
|
||||
selectionbox.MaxEdge = readV3F32(is);
|
||||
pointable = readU8(is);
|
||||
pointable = Pointabilities::deSerializePointabilityType(is);
|
||||
visual = deSerializeString16(is);
|
||||
visual_size = readV3F32(is);
|
||||
textures.clear();
|
||||
|
@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "util/pointabilities.h"
|
||||
|
||||
struct ObjectProperties
|
||||
{
|
||||
@ -36,7 +37,7 @@ struct ObjectProperties
|
||||
aabb3f collisionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f);
|
||||
aabb3f selectionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f);
|
||||
bool rotate_selectionbox = false;
|
||||
bool pointable = true;
|
||||
PointabilityType pointable = PointabilityType::POINTABLE;
|
||||
std::string visual = "sprite";
|
||||
std::string mesh = "";
|
||||
v3f visual_size = v3f(1, 1, 1);
|
||||
|
@ -58,12 +58,14 @@ bool RaycastSort::operator() (const PointedThing &pt1,
|
||||
|
||||
|
||||
RaycastState::RaycastState(const core::line3d<f32> &shootline,
|
||||
bool objects_pointable, bool liquids_pointable) :
|
||||
bool objects_pointable, bool liquids_pointable,
|
||||
const std::optional<Pointabilities> &pointabilities) :
|
||||
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)
|
||||
m_liquids_pointable(liquids_pointable),
|
||||
m_pointabilities(pointabilities)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
* @param liquids pointable if false, liquid nodes won't be found
|
||||
*/
|
||||
RaycastState(const core::line3d<f32> &shootline, bool objects_pointable,
|
||||
bool liquids_pointable);
|
||||
bool liquids_pointable, const std::optional<Pointabilities> &pointabilities);
|
||||
|
||||
//! Shootline of the raycast.
|
||||
core::line3d<f32> m_shootline;
|
||||
@ -55,6 +55,7 @@ public:
|
||||
|
||||
bool m_objects_pointable;
|
||||
bool m_liquids_pointable;
|
||||
const std::optional<Pointabilities> &m_pointabilities;
|
||||
|
||||
//! The code needs to search these nodes around the center node.
|
||||
core::aabbox3d<s16> m_search_range { 0, 0, 0, 0, 0, 0 };
|
||||
|
@ -83,6 +83,12 @@ void read_item_definition(lua_State* L, int index,
|
||||
|
||||
getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
|
||||
|
||||
lua_getfield(L, index, "pointabilities");
|
||||
if(lua_istable(L, -1)){
|
||||
def.pointabilities = std::make_optional<Pointabilities>(
|
||||
read_pointabilities(L, -1));
|
||||
}
|
||||
|
||||
lua_getfield(L, index, "tool_capabilities");
|
||||
if(lua_istable(L, -1)){
|
||||
def.tool_capabilities = new ToolCapabilities(
|
||||
@ -199,6 +205,10 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
|
||||
lua_setfield(L, -2, "usable");
|
||||
lua_pushboolean(L, i.liquids_pointable);
|
||||
lua_setfield(L, -2, "liquids_pointable");
|
||||
if (i.pointabilities) {
|
||||
push_pointabilities(L, *i.pointabilities);
|
||||
lua_setfield(L, -2, "pointabilities");
|
||||
}
|
||||
if (i.tool_capabilities) {
|
||||
push_tool_capabilities(L, *i.tool_capabilities);
|
||||
lua_setfield(L, -2, "tool_capabilities");
|
||||
@ -311,7 +321,12 @@ void read_object_properties(lua_State *L, int index,
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
getboolfield(L, -1, "pointable", prop->pointable);
|
||||
lua_getfield(L, -1, "pointable");
|
||||
if(!lua_isnil(L, -1)){
|
||||
prop->pointable = read_pointability_type(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
getstringfield(L, -1, "visual", prop->visual);
|
||||
|
||||
getstringfield(L, -1, "mesh", prop->mesh);
|
||||
@ -452,7 +467,7 @@ void push_object_properties(lua_State *L, ObjectProperties *prop)
|
||||
lua_pushboolean(L, prop->rotate_selectionbox);
|
||||
lua_setfield(L, -2, "rotate");
|
||||
lua_setfield(L, -2, "selectionbox");
|
||||
lua_pushboolean(L, prop->pointable);
|
||||
push_pointability_type(L, prop->pointable);
|
||||
lua_setfield(L, -2, "pointable");
|
||||
lua_pushlstring(L, prop->visual.c_str(), prop->visual.size());
|
||||
lua_setfield(L, -2, "visual");
|
||||
@ -781,8 +796,14 @@ void read_content_features(lua_State *L, ContentFeatures &f, int index)
|
||||
// This is used for collision detection.
|
||||
// Also for general solidness queries.
|
||||
getboolfield(L, index, "walkable", f.walkable);
|
||||
// Player can point to these
|
||||
getboolfield(L, index, "pointable", f.pointable);
|
||||
|
||||
// Player can point to these, point through or it is blocking
|
||||
lua_getfield(L, index, "pointable");
|
||||
if(!lua_isnil(L, -1)){
|
||||
f.pointable = read_pointability_type(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Player can dig these
|
||||
getboolfield(L, index, "diggable", f.diggable);
|
||||
// Player can climb these
|
||||
@ -1005,7 +1026,7 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
|
||||
lua_setfield(L, -2, "is_ground_content");
|
||||
lua_pushboolean(L, c.walkable);
|
||||
lua_setfield(L, -2, "walkable");
|
||||
lua_pushboolean(L, c.pointable);
|
||||
push_pointability_type(L, c.pointable);
|
||||
lua_setfield(L, -2, "pointable");
|
||||
lua_pushboolean(L, c.diggable);
|
||||
lua_setfield(L, -2, "diggable");
|
||||
@ -1592,6 +1613,125 @@ ToolCapabilities read_tool_capabilities(
|
||||
return toolcap;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
PointabilityType read_pointability_type(lua_State *L, int index)
|
||||
{
|
||||
if (lua_isboolean(L, index)) {
|
||||
if (lua_toboolean(L, index))
|
||||
return PointabilityType::POINTABLE;
|
||||
else
|
||||
return PointabilityType::POINTABLE_NOT;
|
||||
} else {
|
||||
const char* s = luaL_checkstring(L, index);
|
||||
if (s && !strcmp(s, "blocking")) {
|
||||
return PointabilityType::POINTABLE_BLOCKING;
|
||||
}
|
||||
}
|
||||
throw LuaError("Invalid pointable type.");
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
Pointabilities read_pointabilities(lua_State *L, int index)
|
||||
{
|
||||
Pointabilities pointabilities;
|
||||
|
||||
lua_getfield(L, index, "nodes");
|
||||
if(lua_istable(L, -1)){
|
||||
int ti = lua_gettop(L);
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, ti) != 0) {
|
||||
// key at index -2 and value at index -1
|
||||
std::string name = luaL_checkstring(L, -2);
|
||||
|
||||
// handle groups
|
||||
if(std::string_view(name).substr(0,6)=="group:") {
|
||||
pointabilities.node_groups[name.substr(6)] = read_pointability_type(L, -1);
|
||||
} else {
|
||||
pointabilities.nodes[name] = read_pointability_type(L, -1);
|
||||
}
|
||||
|
||||
// removes value, keeps key for next iteration
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, index, "objects");
|
||||
if(lua_istable(L, -1)){
|
||||
int ti = lua_gettop(L);
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L, ti) != 0) {
|
||||
// key at index -2 and value at index -1
|
||||
std::string name = luaL_checkstring(L, -2);
|
||||
|
||||
// handle groups
|
||||
if(std::string_view(name).substr(0,6)=="group:") {
|
||||
pointabilities.object_groups[name.substr(6)] = read_pointability_type(L, -1);
|
||||
} else {
|
||||
pointabilities.objects[name] = read_pointability_type(L, -1);
|
||||
}
|
||||
|
||||
// removes value, keeps key for next iteration
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
return pointabilities;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void push_pointability_type(lua_State *L, PointabilityType pointable)
|
||||
{
|
||||
switch(pointable)
|
||||
{
|
||||
case PointabilityType::POINTABLE:
|
||||
lua_pushboolean(L, true);
|
||||
break;
|
||||
case PointabilityType::POINTABLE_NOT:
|
||||
lua_pushboolean(L, false);
|
||||
break;
|
||||
case PointabilityType::POINTABLE_BLOCKING:
|
||||
lua_pushliteral(L, "blocking");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void push_pointabilities(lua_State *L, const Pointabilities &pointabilities)
|
||||
{
|
||||
// pointabilities table
|
||||
lua_newtable(L);
|
||||
|
||||
if (!pointabilities.nodes.empty() || !pointabilities.node_groups.empty()) {
|
||||
// Create and fill table
|
||||
lua_newtable(L);
|
||||
for (const auto &entry : pointabilities.nodes) {
|
||||
push_pointability_type(L, entry.second);
|
||||
lua_setfield(L, -2, entry.first.c_str());
|
||||
}
|
||||
for (const auto &entry : pointabilities.node_groups) {
|
||||
push_pointability_type(L, entry.second);
|
||||
lua_setfield(L, -2, ("group:" + entry.first).c_str());
|
||||
}
|
||||
lua_setfield(L, -2, "nodes");
|
||||
}
|
||||
|
||||
if (!pointabilities.objects.empty() || !pointabilities.object_groups.empty()) {
|
||||
// Create and fill table
|
||||
lua_newtable(L);
|
||||
for (const auto &entry : pointabilities.objects) {
|
||||
push_pointability_type(L, entry.second);
|
||||
lua_setfield(L, -2, entry.first.c_str());
|
||||
}
|
||||
for (const auto &entry : pointabilities.object_groups) {
|
||||
push_pointability_type(L, entry.second);
|
||||
lua_setfield(L, -2, ("group:" + entry.first).c_str());
|
||||
}
|
||||
lua_setfield(L, -2, "objects");
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void push_dig_params(lua_State *L,const DigParams ¶ms)
|
||||
{
|
||||
|
@ -39,6 +39,7 @@ extern "C" {
|
||||
#include "util/string.h"
|
||||
#include "itemgroup.h"
|
||||
#include "itemdef.h"
|
||||
#include "util/pointabilities.h"
|
||||
#include "c_types.h"
|
||||
// We do an explicit path include because by default c_content.h include src/client/hud.h
|
||||
// prior to the src/hud.h, which is not good on server only build
|
||||
@ -107,6 +108,11 @@ ItemStack read_item (lua_State *L, int index, IItemDefM
|
||||
|
||||
struct TileAnimationParams read_animation_definition(lua_State *L, int index);
|
||||
|
||||
PointabilityType read_pointability_type (lua_State *L, int index);
|
||||
Pointabilities read_pointabilities (lua_State *L, int index);
|
||||
void push_pointability_type (lua_State *L, PointabilityType pointable);
|
||||
void push_pointabilities (lua_State *L, const Pointabilities &pointabilities);
|
||||
|
||||
ToolCapabilities read_tool_capabilities (lua_State *L, int table);
|
||||
void push_tool_capabilities (lua_State *L,
|
||||
const ToolCapabilities &prop);
|
||||
|
@ -188,7 +188,7 @@ int LuaRaycast::create_object(lua_State *L)
|
||||
}
|
||||
|
||||
LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2),
|
||||
objects, liquids);
|
||||
objects, liquids, std::nullopt);
|
||||
|
||||
*(void **) (lua_newuserdata(L, sizeof(void *))) = o;
|
||||
luaL_getmetatable(L, className);
|
||||
|
@ -336,8 +336,9 @@ public:
|
||||
LuaRaycast(
|
||||
const core::line3d<f32> &shootline,
|
||||
bool objects_pointable,
|
||||
bool liquids_pointable) :
|
||||
state(shootline, objects_pointable, liquids_pointable)
|
||||
bool liquids_pointable,
|
||||
const std::optional<Pointabilities> &pointabilities) :
|
||||
state(shootline, objects_pointable, liquids_pointable, pointabilities)
|
||||
{}
|
||||
|
||||
//! Creates a LuaRaycast and leaves it on top of the stack.
|
||||
|
@ -245,7 +245,7 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version)
|
||||
|
||||
// PROTOCOL_VERSION >= 37
|
||||
writeU8(os, 1); // version
|
||||
os << serializeString16(""); // name
|
||||
os << serializeString16(m_init_name); // name
|
||||
writeU8(os, 0); // is_player
|
||||
writeU16(os, getId()); //id
|
||||
writeV3F32(os, m_base_position);
|
||||
@ -553,7 +553,7 @@ bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const
|
||||
|
||||
bool LuaEntitySAO::getSelectionBox(aabb3f *toset) const
|
||||
{
|
||||
if (!m_prop.is_visible || !m_prop.pointable) {
|
||||
if (!m_prop.is_visible) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t p
|
||||
m_prop.physical = false;
|
||||
m_prop.collisionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f);
|
||||
m_prop.selectionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f);
|
||||
m_prop.pointable = true;
|
||||
m_prop.pointable = PointabilityType::POINTABLE;
|
||||
// Start of default appearance, this should be overwritten by Lua
|
||||
m_prop.visual = "upright_sprite";
|
||||
m_prop.visual_size = v3f(1, 2, 1);
|
||||
@ -724,7 +724,7 @@ bool PlayerSAO::getCollisionBox(aabb3f *toset) const
|
||||
|
||||
bool PlayerSAO::getSelectionBox(aabb3f *toset) const
|
||||
{
|
||||
if (!m_prop.is_visible || !m_prop.pointable) {
|
||||
if (!m_prop.is_visible) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1830,7 +1830,8 @@ bool ServerEnvironment::getActiveObjectMessage(ActiveObjectMessage *dest)
|
||||
|
||||
void ServerEnvironment::getSelectedActiveObjects(
|
||||
const core::line3d<f32> &shootline_on_map,
|
||||
std::vector<PointedThing> &objects)
|
||||
std::vector<PointedThing> &objects,
|
||||
const std::optional<Pointabilities> &pointabilities)
|
||||
{
|
||||
std::vector<ServerActiveObject *> objs;
|
||||
getObjectsInsideRadius(objs, shootline_on_map.start,
|
||||
@ -1863,10 +1864,26 @@ void ServerEnvironment::getSelectedActiveObjects(
|
||||
current_raw_normal = current_normal;
|
||||
}
|
||||
if (collision) {
|
||||
PointabilityType pointable;
|
||||
if (pointabilities) {
|
||||
if (LuaEntitySAO* lsao = dynamic_cast<LuaEntitySAO*>(obj)) {
|
||||
pointable = pointabilities->matchObject(lsao->getName(),
|
||||
usao->getArmorGroups()).value_or(props->pointable);
|
||||
} else if (PlayerSAO* psao = dynamic_cast<PlayerSAO*>(obj)) {
|
||||
pointable = pointabilities->matchPlayer(psao->getArmorGroups()).value_or(
|
||||
props->pointable);
|
||||
} else {
|
||||
pointable = props->pointable;
|
||||
}
|
||||
} else {
|
||||
pointable = props->pointable;
|
||||
}
|
||||
if (pointable != PointabilityType::POINTABLE_NOT) {
|
||||
current_intersection += pos;
|
||||
objects.emplace_back(
|
||||
(s16) obj->getId(), current_intersection, current_normal, current_raw_normal,
|
||||
(current_intersection - shootline_on_map.start).getLengthSQ());
|
||||
(current_intersection - shootline_on_map.start).getLengthSQ(), pointable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +315,8 @@ public:
|
||||
|
||||
virtual void getSelectedActiveObjects(
|
||||
const core::line3d<f32> &shootline_on_map,
|
||||
std::vector<PointedThing> &objects
|
||||
std::vector<PointedThing> &objects,
|
||||
const std::optional<Pointabilities> &pointabilities
|
||||
);
|
||||
|
||||
/*
|
||||
|
@ -8,6 +8,7 @@ set(UTIL_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/metricsbackend.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/numeric.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pointedthing.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pointabilities.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/quicktune.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/serialize.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sha1.cpp
|
||||
|
147
src/util/pointabilities.cpp
Normal file
147
src/util/pointabilities.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2023 cx384
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "pointabilities.h"
|
||||
|
||||
#include "serialize.h"
|
||||
#include "exceptions.h"
|
||||
#include <sstream>
|
||||
|
||||
PointabilityType Pointabilities::deSerializePointabilityType(std::istream &is)
|
||||
{
|
||||
PointabilityType pointable_type = static_cast<PointabilityType>(readU8(is));
|
||||
switch(pointable_type) {
|
||||
case PointabilityType::POINTABLE:
|
||||
case PointabilityType::POINTABLE_NOT:
|
||||
case PointabilityType::POINTABLE_BLOCKING:
|
||||
break;
|
||||
default:
|
||||
// Default to POINTABLE in case of unknown PointabilityType type.
|
||||
pointable_type = PointabilityType::POINTABLE;
|
||||
break;
|
||||
}
|
||||
return pointable_type;
|
||||
}
|
||||
|
||||
void Pointabilities::serializePointabilityType(std::ostream &os, PointabilityType pointable_type)
|
||||
{
|
||||
writeU8(os, static_cast<u8>(pointable_type));
|
||||
}
|
||||
|
||||
std::string Pointabilities::toStringPointabilityType(PointabilityType pointable_type)
|
||||
{
|
||||
switch(pointable_type) {
|
||||
case PointabilityType::POINTABLE:
|
||||
return "true";
|
||||
case PointabilityType::POINTABLE_NOT:
|
||||
return "false";
|
||||
case PointabilityType::POINTABLE_BLOCKING:
|
||||
return "\"blocking\"";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::optional<PointabilityType> Pointabilities::matchNode(const std::string &name,
|
||||
const ItemGroupList &groups) const
|
||||
{
|
||||
auto i = nodes.find(name);
|
||||
return i == nodes.end() ? matchGroups(groups, node_groups) : i->second;
|
||||
}
|
||||
|
||||
std::optional<PointabilityType> Pointabilities::matchObject(const std::string &name,
|
||||
const ItemGroupList &groups) const
|
||||
{
|
||||
auto i = objects.find(name);
|
||||
return i == objects.end() ? matchGroups(groups, object_groups) : i->second;
|
||||
}
|
||||
|
||||
std::optional<PointabilityType> Pointabilities::matchPlayer(const ItemGroupList &groups) const
|
||||
{
|
||||
return matchGroups(groups, object_groups);
|
||||
}
|
||||
|
||||
std::optional<PointabilityType> Pointabilities::matchGroups(const ItemGroupList &groups,
|
||||
const std::unordered_map<std::string, PointabilityType> &pointable_groups)
|
||||
{
|
||||
// prefers POINTABLE over POINTABLE_NOT over POINTABLE_BLOCKING
|
||||
bool blocking = false;
|
||||
bool not_pointable = false;
|
||||
for (auto const &ability : pointable_groups) {
|
||||
if (itemgroup_get(groups, ability.first) > 0) {
|
||||
switch(ability.second) {
|
||||
case PointabilityType::POINTABLE:
|
||||
return PointabilityType::POINTABLE;
|
||||
case PointabilityType::POINTABLE_NOT:
|
||||
not_pointable = true;
|
||||
break;
|
||||
default:
|
||||
blocking = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (not_pointable)
|
||||
return PointabilityType::POINTABLE_NOT;
|
||||
if (blocking)
|
||||
return PointabilityType::POINTABLE_BLOCKING;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Pointabilities::serializeTypeMap(std::ostream &os,
|
||||
const std::unordered_map<std::string, PointabilityType> &map)
|
||||
{
|
||||
writeU32(os, map.size());
|
||||
for (const auto &entry : map) {
|
||||
os << serializeString16(entry.first);
|
||||
writeU8(os, (u8)entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
void Pointabilities::deSerializeTypeMap(std::istream &is,
|
||||
std::unordered_map<std::string, PointabilityType> &map)
|
||||
{
|
||||
map.clear();
|
||||
u32 size = readU32(is);
|
||||
for (u32 i = 0; i < size; i++) {
|
||||
std::string name = deSerializeString16(is);
|
||||
PointabilityType type = Pointabilities::deSerializePointabilityType(is);
|
||||
map[name] = type;
|
||||
}
|
||||
}
|
||||
|
||||
void Pointabilities::serialize(std::ostream &os) const
|
||||
{
|
||||
writeU8(os, 0); // version
|
||||
serializeTypeMap(os, nodes);
|
||||
serializeTypeMap(os, node_groups);
|
||||
serializeTypeMap(os, objects);
|
||||
serializeTypeMap(os, object_groups);
|
||||
}
|
||||
|
||||
void Pointabilities::deSerialize(std::istream &is)
|
||||
{
|
||||
int version = readU8(is);
|
||||
if (version != 0)
|
||||
throw SerializationError("unsupported Pointabilities version");
|
||||
|
||||
deSerializeTypeMap(is, nodes);
|
||||
deSerializeTypeMap(is, node_groups);
|
||||
deSerializeTypeMap(is, objects);
|
||||
deSerializeTypeMap(is, object_groups);
|
||||
}
|
70
src/util/pointabilities.h
Normal file
70
src/util/pointabilities.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2023 cx384
|
||||
|
||||
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 <string>
|
||||
#include <unordered_map>
|
||||
#include "itemgroup.h"
|
||||
#include <optional>
|
||||
#include "irrlichttypes.h"
|
||||
|
||||
enum class PointabilityType : u8
|
||||
{
|
||||
POINTABLE,
|
||||
POINTABLE_NOT, // Can be pointed through.
|
||||
POINTABLE_BLOCKING,
|
||||
};
|
||||
|
||||
// An object to store overridden pointable properties
|
||||
struct Pointabilities
|
||||
{
|
||||
// Nodes
|
||||
std::unordered_map<std::string, PointabilityType> nodes;
|
||||
std::unordered_map<std::string, PointabilityType> node_groups;
|
||||
|
||||
// Objects
|
||||
std::unordered_map<std::string, PointabilityType> objects;
|
||||
std::unordered_map<std::string, PointabilityType> object_groups; // armor_groups
|
||||
|
||||
// Match functions return fitting pointability,
|
||||
// otherwise the default pointability should be used.
|
||||
|
||||
std::optional<PointabilityType> matchNode(const std::string &name,
|
||||
const ItemGroupList &groups) const;
|
||||
std::optional<PointabilityType> matchObject(const std::string &name,
|
||||
const ItemGroupList &groups) const;
|
||||
// For players only armor groups will work
|
||||
std::optional<PointabilityType> matchPlayer(const ItemGroupList &groups) const;
|
||||
|
||||
void serialize(std::ostream &os) const;
|
||||
void deSerialize(std::istream &is);
|
||||
|
||||
// For a save enum conversion.
|
||||
static PointabilityType deSerializePointabilityType(std::istream &is);
|
||||
static void serializePointabilityType(std::ostream &os, PointabilityType pointable_type);
|
||||
static std::string toStringPointabilityType(PointabilityType pointable_type);
|
||||
|
||||
private:
|
||||
static std::optional<PointabilityType> matchGroups(const ItemGroupList &groups,
|
||||
const std::unordered_map<std::string, PointabilityType> &pointable_groups);
|
||||
static void serializeTypeMap(std::ostream &os,
|
||||
const std::unordered_map<std::string, PointabilityType> &map);
|
||||
static void deSerializeTypeMap(std::istream &is,
|
||||
std::unordered_map<std::string, PointabilityType> &map);
|
||||
};
|
@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
PointedThing::PointedThing(const v3s16 &under, const v3s16 &above,
|
||||
const v3s16 &real_under, const v3f &point, const v3f &normal,
|
||||
u16 box_id, f32 distSq):
|
||||
u16 box_id, f32 distSq, PointabilityType pointab):
|
||||
type(POINTEDTHING_NODE),
|
||||
node_undersurface(under),
|
||||
node_abovesurface(above),
|
||||
@ -33,17 +33,19 @@ PointedThing::PointedThing(const v3s16 &under, const v3s16 &above,
|
||||
intersection_point(point),
|
||||
intersection_normal(normal),
|
||||
box_id(box_id),
|
||||
distanceSq(distSq)
|
||||
distanceSq(distSq),
|
||||
pointability(pointab)
|
||||
{}
|
||||
|
||||
PointedThing::PointedThing(u16 id, const v3f &point,
|
||||
const v3f &normal, const v3f &raw_normal, f32 distSq) :
|
||||
PointedThing::PointedThing(u16 id, const v3f &point, const v3f &normal,
|
||||
const v3f &raw_normal, f32 distSq, PointabilityType pointab) :
|
||||
type(POINTEDTHING_OBJECT),
|
||||
object_id(id),
|
||||
intersection_point(point),
|
||||
intersection_normal(normal),
|
||||
raw_intersection_normal(raw_normal),
|
||||
distanceSq(distSq)
|
||||
distanceSq(distSq),
|
||||
pointability(pointab)
|
||||
{}
|
||||
|
||||
std::string PointedThing::dump() const
|
||||
@ -118,12 +120,13 @@ bool PointedThing::operator==(const PointedThing &pt2) const
|
||||
{
|
||||
if ((node_undersurface != pt2.node_undersurface)
|
||||
|| (node_abovesurface != pt2.node_abovesurface)
|
||||
|| (node_real_undersurface != pt2.node_real_undersurface))
|
||||
|| (node_real_undersurface != pt2.node_real_undersurface)
|
||||
|| (pointability != pt2.pointability))
|
||||
return false;
|
||||
}
|
||||
else if (type == POINTEDTHING_OBJECT)
|
||||
{
|
||||
if (object_id != pt2.object_id)
|
||||
if (object_id != pt2.object_id || pointability != pt2.pointability)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "irr_v3d.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "pointabilities.h"
|
||||
|
||||
enum PointedThingType :u8
|
||||
{
|
||||
@ -90,15 +91,20 @@ struct PointedThing
|
||||
* ray's start point and the intersection point in irrlicht coordinates.
|
||||
*/
|
||||
f32 distanceSq = 0;
|
||||
/*!
|
||||
* How the object or node has been pointed at.
|
||||
*/
|
||||
PointabilityType pointability = PointabilityType::POINTABLE_NOT;
|
||||
|
||||
//! Constructor for POINTEDTHING_NOTHING
|
||||
PointedThing() = default;
|
||||
//! Constructor for POINTEDTHING_NODE
|
||||
PointedThing(const v3s16 &under, const v3s16 &above,
|
||||
const v3s16 &real_under, const v3f &point, const v3f &normal,
|
||||
u16 box_id, f32 distSq);
|
||||
u16 box_id, f32 distSq, PointabilityType pointability);
|
||||
//! Constructor for POINTEDTHING_OBJECT
|
||||
PointedThing(u16 id, const v3f &point, const v3f &normal, const v3f &raw_normal, f32 distSq);
|
||||
PointedThing(u16 id, const v3f &point, const v3f &normal, const v3f &raw_normal, f32 distSq,
|
||||
PointabilityType pointability);
|
||||
std::string dump() const;
|
||||
void serialize(std::ostream &os) const;
|
||||
void deSerialize(std::istream &is);
|
||||
|
Loading…
Reference in New Issue
Block a user