[Mod] Advanced Rangefinder [finder]

Post Reply
User avatar
sorcerykid
Member
Posts: 1847
Joined: Fri Aug 26, 2016 15:36
GitHub: sorcerykid
In-game: Nemo
Location: Illinois, USA

[Mod] Advanced Rangefinder [finder]

by sorcerykid » Post

Image

Advanced Rangefinder Mod v1.1
finder (by sorcerykid)

Advanced Rangefinder extends the Minetest API with more powerful search capabilities for both nodes and entities, in addition to a versatile chat command for use in testing.

The following issue on GitHub served as inspiration for developing this mod:
https://github.com/minetest/minetest/issues/9403

Repository:

https://bitbucket.org/sorcerykid/finder

Download Archive (.zip)
Download Archive (.tar.gz)

Compatability:

Minetest 0.4.15+ required

Dependencies:

ActiveFormspecs Mod (optional)

Installation Instructions:
  1. Unzip the archive into the mods directory of your game
  2. Rename the finder-master directory to "finder"
  3. Add "finder" as a dependency to any mods using the API
Source Code License:

The MIT License (MIT)

Video Demonstration:

Image
Demonstration of Rangefinder Mod
https://vimeo.com/392304134

Overview:

The following library functions are made available as an extension to the builtin Minetest API:
  • minetest.search_registered_nodes( node_globs, search_logic )
    Returns the names of all registered nodes that match the given list of globs. The output of this function may be passed to either of the wrapper functions below or to minetest.find_nodes_in_area( ) directly. Two boolean search modes are possible:
    • "any" for logical OR matching (default)
    • "all" for logical AND matching
    For more advanced searches, a matching function may be used instead. Each parameter corresponds to the respective node glob and will be assigned true or false depending on the comparison result. This function should return true for a successful match.

    For example, to locate flower or wool items that are placed inside itemframes or dropped on the ground, this can easily be done with just a few lines of code:

    Code: Select all

    local entity_globs = {":flowers:*", ":wool:*", "itemframes:visual", "__builtin:item"}
    local match_func = function (a, b, c, d) return (a or b) and (c or d) end
    
    local res = minetest.find_objects_in_sphere(pos, radius, {}, entity_globs, match_func)
    
    The "match" function is similar in concept to the "compare" function of table.sort(). This allows for corner cases where singular "any" and "or" boolean logic is insufficient.

    minetest.find_nodes_in_sphere( pos, radius, node_names )
    This is a wrapper function for minetest.find_nodes_in_area( ) that provides a means to locate nodes by name in a spherical region. The output is a table:
    • name - the name of the node
    • node - the node
    • pos - the node position
    • dist - the distance to the node
    • groups - the groups belonging to the node
    minetest.find_nodes_in_cuboid( pos, radius, height, node_names )
    This is a wrapper function for minetest.find_nodes_in_area( ) that provides a means to locate nodes by name in a cubicle region. The output is the same as above.

    minetest.find_objects_in_sphere( pos, radius, player_names, entity globs, search_logic, search_options )
    Since the builtin API of Minetest does not provide a means to locate entities by name or group, this function fulfills that purpose. It supports the same two boolean search modes as minetest.search_registered_nodes( ). The output is a table:
    • name - the name of the entity or player
    • obj - the ObjectRef of the entity or player
    • pos - the object position
    • dist - the distance to the object
    • groups - the groups belonging to the entity (nil for players)
    If either the player names or entity globs are nil, then all players or entities in the given range will match accordingly. However, supplying an empty list will match none. Currently, the only supported search option is 'is_attached' which is a boolean indicating whether attached entities should be included.

    minetest.search_registered_entities( entity_globs, search_logic )
    Returns the names of all registered entities that match the given list of globs. The output of this function may be passed to minetest.find_entities_in_sphere( ) below.

    minetest.find_entities_in_sphere( pos, radius, entity_names )
    This is a lightweight alternative to minetest.find_objects_in_sphere( ). It expects a list of entity names which may be obtained via minetest.search_registered_entities( ).
If you are already familiar with globs, then you should have no difficulties working with the functions above. The syntax is very similar, but with only a few additions:
  • ? - matches any single character
    * - matches zero or more characters
    + - matches one or more characters
A glob that is prefixed with "!" is equivalent to a logical NOT and will invert the resulting match. Hence "!default:chest*" would not match either "default:chest_locked" or "default:chest", but it would match "default:bookshelf".


For example, if I want to locate flower or wool items that are placed inside itemframes or dropped on the ground, this can easily be done with just a few lines of code:

Code: Select all

local entity_globs = {":flowers:*", ":wool:*", "itemframes:visual", "__builtin:item"}
local match_func = function (a, b, c, d) return (a or b) and (c or d) end

local res = minetest.find_objects_in_sphere(pos, radius, {}, entity_globs, match_func)
The function find_objects_in_sphere() can optionally be a "match" function, similar in concept to the "compare" function of table.sort. This allows for corner cases where singular "any" and "or" boolean logic is insufficient.

An additionally powerful feature is the ability to locate wielded and dropped items without having to examine the property tables of entities such as "__builtin:item" or "itemframes:visual". Simply prefix the registered item's name (or the name of the group) with a ":" as this example demonstrates:

Code: Select all

minetest.find_objects_in_sphere( player:get_pos( ), 10.0,
        { "__builtin:item", ":buckets:bucket_*" }, "all" )
While Minetest does not formally recognize the concept of groups for entities, I've nonetheless included support for group-searches. In order to use this feature, it will be necessary to add a "groups" property to your entity definitions.

You'll want to start by modifying "builtin/game/item_entity.lua" as follows:

Code: Select all

core.register_entity(":__builtin:item", {
        initial_properties = {
                hp_max = 1,
                physical = true,
                collide_with_objects = false,
                collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
                visual = "wielditem",
                 visual_size = {x = 0.4, y = 0.4},
                textures = {""},
                spritediv = {x = 1, y = 1},
                initial_sprite_basepos = {x = 0, y = 0},
                is_visible = false,
        },

        groups = {item = 1, dropped_item = 1},   -- add this line
        itemstring = "",
        moving_state = true,
        slippery_state = false,
Since there isn't yet a formal system of entity grouping, I'm using the following scheme currently. But you are welcome to devise your own, depending on your needs.
  • Class of entities that represent a registered item (node, craftitem, or tool):
    • group:item
  • Subclass of 'group:item' entities
    • group:dropped_item
    • group:wielded_item
    • group:falling_node
  • Class of entities that are for visualization (including signs, markers, etc.)
    • group:visual
  • Subclass of 'group:visual' entities
    • group:sign
    • group:marker
  • Class of entities that are capable of motion
    • group:mobile
  • Class of entities that have AI characteristics (including NPCs, monsters, etc.)
    • group:mob
  • Subclass of 'group:mob' entities
    • group:animal
    • group:human
    • group:monster
    • group:alien
    • group:walking
    • group:swimming
    • group:flying
The "/find" chat command offers a convenient front-end to the search functionality.
  • /finder objects sphere [radius] [player_names] [entity_globs] [search_logic]

    /finder nodes [region] [radius] [node_globs] [search_logic]
For node searches, the region can be either "sphere" or "cuboid". The player names, entity globs, and node_globs lists should be surrounded by braces. To eliminate any parameter simply specify "nil". For example, to find all nearby dirt nodes, enter this command:

Code: Select all

/finder nodes sphere 5.0 {default:dirt*} nil
I've taken great care to optimize the functions above as much as possible. However, given that they are extending the CPP interface, they can only perform as well as the inputs provided. So the most restrictive searches are always preferable.

In my benchmarking tests in which 100 entities in a radius of 50m were searched with a custom matching function, the mod performed consistently well.

Code: Select all

** series                   count       rep
** newsearch             0.272 ms        2x
** newsearch             0.228 ms        3x
** newsearch             0.232 ms        4x
** newsearch             0.231 ms        5x
** newsearch             0.279 ms        6x
** newsearch             0.232 ms        7x
** newsearch             0.208 ms        8x
** newsearch             0.335 ms        9x
Also keep in mind, if you need to perform multiple searches for the same node globs or entity globs, then be sure to cache the output of minetest.search_registered_nodes( ) or minetest.search_registered_entities( ) for efficiency. After all, the resulting node and and entity names won't change, so regenerating these lists every time is unnecessary.
Last edited by sorcerykid on Fri Feb 28, 2020 20:59, edited 1 time in total.

User avatar
texmex
Member
Posts: 1753
Joined: Mon Jul 11, 2016 21:08
GitHub: tacotexmex
In-game: tacotexmex

Re: [Mod] Advanced Rangefinder [finder]

by texmex » Post

Very cool! Should prove useful. Why the hard dependency on ActiveFormspecs though?

User avatar
sorcerykid
Member
Posts: 1847
Joined: Fri Aug 26, 2016 15:36
GitHub: sorcerykid
In-game: Nemo
Location: Illinois, USA

Re: [Mod] Advanced Rangefinder [finder]

by sorcerykid » Post

Good catch! That should be an optional dependency. There's already a check to disable the chat command if ActiveFormspecs is not installed, so I'll be sure correct the documentation and depends.txt file.

User avatar
Lone_Wolf
Member
Posts: 2578
Joined: Sun Apr 09, 2017 05:50
GitHub: LoneWolfHT
IRC: LandarVargan
In-game: LandarVargan

Re: [Mod] Advanced Rangefinder [finder]

by Lone_Wolf » Post

Neat, saving this topic for later :eyes:
My ContentDB -|- Working on CaptureTheFlag -|- Minetest Forums Dark Theme!! (You need it)

User avatar
sorcerykid
Member
Posts: 1847
Joined: Fri Aug 26, 2016 15:36
GitHub: sorcerykid
In-game: Nemo
Location: Illinois, USA

Re: [Mod] Advanced Rangefinder [finder]

by sorcerykid » Post

Great news! With the merging of PR #10668 yesterday, I can now properly implement minetest.find_objects_in_cuboid( ) within the Advanced Rangefinder API. I will try to push an update sometime next week.

Of course, I still have other other exciting plans in the works too, one of which is a spatial partitioning search. So stay tuned!

Post Reply

Who is online

Users browsing this forum: No registered users and 35 guests