Compare commits

...

10 Commits

Author SHA1 Message Date
Jude Melton-Houghton
78d60b3c70
Idle when no player has an active compass (#21) 2021-09-06 21:16:37 +02:00
nixnoxus
43b803d82d
Fix settingtypes.txt type error (#20) 2021-08-14 17:30:07 +02:00
nixnoxus
21ccde6deb
Add an alternative recipe for "ccompass:0" (#19)
The current one collides with "digtron:digtron_core"
2021-07-21 13:15:00 +02:00
Luke aka SwissalpS
4213e60d11
Add reset recipe and stack-ability (#18)
only identical compasses can be stacked
also needle needs to point in same direction
adds runtime changeable option to use a stack for calibrating and jumping
set ccompass.stack_max to 1 for previous behaviour
adds recipe to reset compass
2021-04-09 18:27:57 +02:00
Alexander Weber
9845a89ec5 hint how to disable teleporting 2020-11-30 20:59:14 +01:00
Alexander Weber
910d0cea29 fix search for safe target place.
Search is started now from planned position and is done in both directions
2020-11-30 20:51:03 +01:00
Alexander Weber
c704426e9b reverse the search order for valid target and move the range from 80 -> -80, to allow to teleport bellow the stored target 2020-11-29 13:00:25 +01:00
Alexander Weber
37713a75ad cache the node names without rereading nodes 2020-11-29 12:24:12 +01:00
Luke aka SwissalpS
629f635802
Propose multi air (#17)
* fix unsafe teleportation

If target position is in vacuum or is no longer in air,
compass would place player at 160 nodes above target no matter what is
there, including lava.
This fixes that.

* add table of node names that are allowed to be above target

* more generic handling

* allow climbables as targets

this should cover the beacon beams (when climbing is enabled),
bridger:scaffolding nodes and others.

* more checks and more configurable ones

Now checks for head, foot and under nodes.

* add config and global for damaging targets

* drop check for teleport restrict_target

1) of
https://github.com/minetest-mods/ccompass/pull/17#issuecomment-733506984

* allow walkables and climbables as target_under
2020-11-29 12:05:35 +01:00
SwissalpS
af8472eca0 fix unsafe teleportation
If target position is in vacuum or is no longer in air,
compass would place player at 160 nodes above target no matter what is
there, including lava.
This fixes that.
2020-11-18 07:49:50 +01:00
3 changed files with 241 additions and 23 deletions

View File

@ -1,4 +1,4 @@
# ccompass
# ccompass
This minetest mod adds a calibratable compass to the minetest. Original mod [here](https://forum.minetest.net/viewtopic.php?f=11&t=3785)
@ -15,6 +15,8 @@ This minetest mod adds a calibratable compass to the minetest. Original mod [her
3. Now this compass leads you allways to this location. You can give it away to allow other users to find this place.
4. Punch a teleport compatible node (by default mese block) to teleport back to the calibrated place
Depending on servers many aspects can be different, see below.
## For server owners:
The mod support the next settings:
@ -23,8 +25,15 @@ The mod support the next settings:
ccompass_restrict_target (Disabled by default): If enabled, only specific nodes are allowed for calibration (usable with any type waypoint nodes for example)
ccompass_restrict_target_nodes: List of technical node names allowed for compass calibration, separated by ','
ccompass_aliasses: If enabled the compas:* items will be aliased to the ccompass:* items for compatibility
ccompass_teleport_nodes: List of technical node names that triggers the teleport to destination, separated by ','
ccompass_teleport_nodes: List of technical node names that triggers the teleport to destination, separated by ','. Default is "default:mese". Set it to "none" to disable the teleporting feature.
ccompass_nodes_over_target_allow: List of additional node names that must be above target for teleport to be executed. (separated by ',')
ccompass_nodes_over_target_deny: List of additional node names that must NOT be above target for teleport to be executed. (separated by ',')
ccompass_nodes_over_target_allow_drawtypes: List of drawtypes to allow to be over target. Defaults are: airlike, flowingliquid, liquid, plantlike and plantlike_rooted
ccompass_deny_climbable_target: Disabled by default -> allows climbable nodes to be over target. Set to true to not allow them.
ccompass_allow_damage_target: Disabled by default -> will not teleport player into or over damaging nodes.
ccompass_stack_max: 1 by default. Sets maximum stack size, 1 to 65535
ccompass_allow_using_stacks: Disabled by default -> calibrating and teleporting only works when single compass in hand. Setting to true, allows callibrating stacks to same location.
ccompass_idle_interval: 1 by default. When no players have active compasses, the mod enters an idle state and only checks for compasses at this interval, measured in seconds. This setting is meant to reduce the load on the server.
## For developers:
1. It is possible to change compass settings from other mods by changing values in global table ccompass. So it is possible for example to add a waypoint node to the target-nodes by
@ -34,7 +43,21 @@ The mod support the next settings:
ccompass.restrict_target = true
ccompass.restrict_target_nodes["schnitzeljagd:waypoint"] = true
ccompass.teleport_nodes["default:diamondblock"] = true
ccompass.nodes_over_target_allow["vacuum:vacuum"] = true
ccompass.nodes_over_target_deny["tnt:boom"] = true
ccompass.nodes_over_target_allow_drawtypes["liquid"] = nil
ccompass.allow_climbable_target = false
ccompass.allow_damaging_target = true
ccompass.allow_using_stacks = true
ccompass.stack_max = 42
ccompass.idle_interval = 0
```
Also you can override ccompass.is_safe_target(target, nodename) for more granular checks.
By default first nodes_over_target_allow is checked, then nodes_over_target_deny
and finally nodes are checked for damaging and airlike drawtype.
Similarly you can override ccompass.is_safe_target_under(target, nodename) for
more granular checks on what is under players feet.
2. The pointed node metadata will be checked for "waypoint_name" attribute. It this attribute is set, the calibration screen take this string as proposal. This can be used for a game specific calibration node. To get it working working just set in node definition something like
@ -47,7 +70,7 @@ The mod support the next settings:
end,
```
3. It is possible to create pre-calibrated compasses trough other mods. Just write the position to the Itemstack meta:
3. It is possible to create pre-calibrated compasses through other mods. Just write the position to the Itemstack meta:
```
stack:get_meta():set_string("target_pos", minetest.pos_to_string(pos))
@ -71,3 +94,8 @@ The mod support the next settings:
return modified_compass_stack
end
```
5. Setting ccompass.stack_max to 1 restores behaviour prior to stackable feature.
Or going the other way: set ccompass.stack_max to 777 and also set ccompass.allow_using_stacks to true.
This would allow players to make a big number of copies at once.

197
init.lua
View File

@ -19,6 +19,10 @@ if nodes_setting then
ccompass.restrict_target_nodes[z] = true
end)
end
ccompass.allow_climbable_target = not minetest.settings:get_bool("ccompass_deny_climbable_target")
ccompass.allow_damaging_target = minetest.settings:get_bool("ccompass_allow_damage_target")
-- Teleport targets
ccompass.teleport_nodes = {}
local teleport_nodes_setting = minetest.settings:get("ccompass_teleport_nodes")
@ -29,6 +33,44 @@ if teleport_nodes_setting then
else
ccompass.teleport_nodes["default:mese"] = true
end
-- Permited nodes above target
ccompass.nodes_over_target_allow = {}
nodes_setting = minetest.settings:get("ccompass_nodes_over_target_allow")
if nodes_setting then
nodes_setting:gsub("[^,]+", function(z)
ccompass.nodes_over_target_allow[z] = true
end)
end
-- Not permited nodes above target
ccompass.nodes_over_target_deny = {}
nodes_setting = minetest.settings:get("ccompass_nodes_over_target_deny")
if nodes_setting then
nodes_setting:gsub("[^,]+", function(z)
ccompass.nodes_over_target_deny[z] = true
end)
end
-- Permited drawtype of nodes above target
ccompass.nodes_over_target_allow_drawtypes = {}
nodes_setting = minetest.settings:get("ccompass_nodes_over_target_allow_drawtypes")
if nodes_setting then
nodes_setting:gsub("[^,]+", function(z)
ccompass.nodes_over_target_allow_drawtypes[z] = true
end)
else
ccompass.nodes_over_target_allow_drawtypes = {
airlike = true,
flowingliquid = true,
liquid = true,
plantlike = true,
plantlike_rooted = true,
}
end
-- default to legacy behaviour
ccompass.stack_max = tonumber(minetest.settings:get("ccompass_stack_max") or 1) or 1
ccompass.allow_using_stacks = minetest.settings:get_bool("ccompass_allow_using_stacks")
ccompass.idle_interval = tonumber(minetest.settings:get("ccompass_idle_interval") or 1) or 1
if minetest.settings:get_bool("ccompass_aliasses") then
minetest.register_alias("compass:0", "ccompass:0")
@ -78,34 +120,125 @@ local function get_destination(player, stack)
end
end
function ccompass.is_safe_target(target, nodename)
local node_def = minetest.registered_nodes[nodename]
-- unknown node: not dangerous but probably best treated as one
if not node_def then return false end
-- white-list
if ccompass.nodes_over_target_allow[nodename] then return true end
-- black-list
if ccompass.nodes_over_target_deny[nodename] then return false end
-- damaging node
if not ccompass.allow_damaging_target then
if node_def.damage_per_second and 0 < node_def.damage_per_second then
return false
end
end
-- climbable nodes are ok depending on settings
if ccompass.allow_climbable_target and node_def.climbable then return true end
-- deeper checks
local is_good_draw_type = ccompass.nodes_over_target_allow_drawtypes
if is_good_draw_type[node_def.drawtype] then return true end
-- anything else is assumed dangerous
return false
end
function ccompass.is_safe_target_under(target, nodename)
local node_def = minetest.registered_nodes[nodename]
-- unknown node: not dangerous but probably best treated as one
if not node_def then return false end
-- damaging node
if not ccompass.allow_damaging_target then
if node_def.damage_per_second and 0 < node_def.damage_per_second then
return false
end
end
-- climbable nodes are ok depending on settings
if ccompass.allow_climbable_target and node_def.climbable then return true end
-- solid / walkable
if node_def.walkable then return true end
-- anything else is assumed unsafe
return false
end
local function check_target(cur_target, nodenames_cache)
--check target
local nodename = nodenames_cache[cur_target.y] or minetest.get_node(cur_target).name
if nodename == "ignore" then return false end
nodenames_cache[cur_target.y] = nodename
if ccompass.is_safe_target(cur_target, nodename) then
-- Check under
cur_target.y = cur_target.y - 1
nodename = nodenames_cache[cur_target.y] or minetest.get_node(cur_target).name
if nodename == "ignore" then return false end
nodenames_cache[cur_target.y] = nodename
if ccompass.is_safe_target_under(cur_target, nodename) then
-- Check head
cur_target.y = cur_target.y + 2
nodename = nodenames_cache[cur_target.y] or minetest.get_node(cur_target).name
if nodename == "ignore" then return false end
nodenames_cache[cur_target.y] = nodename
if ccompass.is_safe_target(cur_target, nodename) then
return true
end
end
end
end
local function teleport_above(playername, target, counter)
local player = minetest.get_player_by_name(playername)
if not player then
return
end
for i = (counter or 1), 160 do
local nodename = minetest.get_node(target).name
if nodename == "ignore" then
minetest.emerge_area(target, target)
local found_place = false
local cur_target = { x = target.x, z = target.z } -- y is handled in loop
local nodenames_cache = {}
for i = (counter or 0), 80 do
-- Search above
cur_target.y = target.y + i
found_place = check_target(cur_target, nodenames_cache)
if found_place == false then
minetest.emerge_area(cur_target, cur_target)
minetest.after(0.1, teleport_above, playername, target, i)
return
end
if nodename ~= 'air' then
target.y = target.y + 1
else
elseif found_place == true then
cur_target.y = target.y + i -- reset after check_target
break
end
if i > 0 then
-- Search bellow
cur_target.y = target.y - i
found_place = check_target(cur_target, nodenames_cache)
if found_place == false then
minetest.emerge_area(cur_target, cur_target)
minetest.after(0.1, teleport_above, playername, target, i)
return
elseif found_place == true then
cur_target.y = target.y - i -- reset after check_target
break
end
end
end
if found_place then
player:set_pos(cur_target)
else
minetest.chat_send_player(playername, "Could not find suitable surrounding at target.")
end
player:setpos(target)
return
end
-- get right image number for players compas
-- get right image number for players compass
local function get_compass_stack(player, stack)
local target = get_destination(player, stack)
local pos = player:getpos()
local pos = player:get_pos()
local dir = player:get_look_horizontal()
local angle_north = math.deg(math.atan2(target.x - pos.x, target.z - pos.z))
if angle_north < 0 then
@ -118,7 +251,7 @@ local function get_compass_stack(player, stack)
-- create new stack with metadata copied
local metadata = stack:get_meta():to_table()
local newstack = ItemStack("ccompass:"..compass_image)
local newstack = ItemStack("ccompass:"..compass_image.." "..stack:get_count())
if metadata then
newstack:get_meta():from_table(metadata)
end
@ -130,6 +263,11 @@ end
-- Calibrate compass on pointed_thing
local function on_use_function(itemstack, player, pointed_thing)
-- if using with a bunch together, need to check server preference
if 1 ~= itemstack:get_count() and not ccompass.allow_using_stacks then
minetest.chat_send_player(player:get_player_name(), "Use a single compass.")
return
end
-- possible only on nodes
if pointed_thing.type ~= "node" then --support nodes only for destination
minetest.chat_send_player(player:get_player_name(), "Calibration can be done on nodes only")
@ -174,7 +312,6 @@ local function on_use_function(itemstack, player, pointed_thing)
nodepos_string = waypoint_pos
end
if skip_namechange ~= "" then
ccompass.set_target(itemstack, {
target_pos_string = nodepos_string,
@ -209,7 +346,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end)
-- update inventory
minetest.register_globalstep(function(dtime)
local function do_update_loop()
local found_compasses = false
for i,player in ipairs(minetest.get_connected_players()) do
if player:get_inventory() then
for i,stack in ipairs(player:get_inventory():get_list("main")) do
@ -217,12 +355,17 @@ minetest.register_globalstep(function(dtime)
break
end
if string.sub(stack:get_name(), 0, 9) == "ccompass:" then
found_compasses = true
player:get_inventory():set_stack("main", i, get_compass_stack(player, stack))
end
end
end
end
end)
-- if no compasses were found, idle for a time before checking again
local interval = found_compasses and 0 or ccompass.idle_interval
minetest.after(interval, do_update_loop)
end
minetest.after(0, do_update_loop)
-- register items
for i = 0, 15 do
@ -231,13 +374,21 @@ for i = 0, 15 do
if i > 0 then
groups.not_in_creative_inventory = 1
end
minetest.register_tool("ccompass:"..i, {
local itemname = "ccompass:"..i
minetest.register_craftitem(itemname, {
description = "Compass",
inventory_image = image,
wield_image = image,
stack_max = ccompass.stack_max or 42,
groups = groups,
on_use = on_use_function,
})
-- reset recipe
minetest.register_craft({
type = "shapeless",
output = "ccompass:0",
recipe = { itemname }
})
end
minetest.register_craft({
@ -248,3 +399,13 @@ minetest.register_craft({
{'', 'default:steel_ingot', ''}
}
})
-- add an alternative recipe
minetest.register_craft({
output = 'ccompass:0',
recipe = {
{'default:steel_ingot', '', 'default:steel_ingot'},
{'', 'default:mese_crystal_fragment', ''},
{'default:steel_ingot', '', 'default:steel_ingot'}
}
})

View File

@ -4,11 +4,40 @@ ccompass_recalibrate (Allow compass recalibration) bool true
# If disabled (default) all nodes are allowed to be compass target
ccompass_restrict_target (Restrict nodes usable for calibration) bool false
# If enabled, climbable nodes above target are considered unsafe.
ccompass_deny_climbable_target (Deny climbable node above target) bool false
# List of technical node names allowed for compass calibration, separated by ','
ccompass_restrict_target_nodes (Nodes list allowed for calibration) string
# Enable aliasses to replace other compass mods
ccompass_aliasses (Enable compatibility aliasses) bool false
# Nodes able to teleport to destination on punch, separated by ','
# Nodes able to teleport to destination on punch, separated by ','. Set it to "none" to disable the teleporting feature.
ccompass_teleport_nodes (Nodes list for teleport on punch) string default:mese
# If one of these nodes is at target, skip other checks and allow teleporting.
# String list of node names separated by ','
ccompass_nodes_over_target_allow (Nodes list for additional allowed nodes) string
# If one of these nodes is at target, skip other checks and deny teleporting.
# String list of node names separated by ','
ccompass_nodes_over_target_deny (Nodes list for additional deny nodes) string
# Drawtype of nodes over target that are considered safe. This will only be checked
# checked after ccompass_nodes_over_target_allow and ccompass_nodes_over_target_deny.
# String list of node names separated by ','
ccompass_nodes_over_target_allow_drawtypes (Drawtypes of nodes allowed over target) string airlike,flowingliquid,liquid,plantlike,plantlike_rooted
# By default ccompass will not teleport players into or over damaging nodes.
# To allow this, change to true.
ccompass_allow_damage_target (Enable to allow teleporting into damaging nodes) bool false
# Maximum size of compass stacks. Only identical and same direction pointing compasses can be stacked.
# Defaults to 1
ccompass_stack_max (Sets maximum stack size) int 1 1 65535
# Requires stack_max greater than 1. When true, allows a whole stack to be calibrated at the same time.
ccompass_allow_using_stacks (Enable to allow callibrating stacks) bool false
# When no players have active compasses, the mod enters an idle state and only checks for compasses at this interval, measured in seconds. This setting is meant to reduce the load on the server.
ccompass_idle_interval (Time between checks when idling) float 1 0 10