Sokomine
Member
Posts: 4184
Joined: Sun Sep 09, 2012 17:31
GitHub: Sokomine

sorcerykid wrote: A player on my sever recently notified me that the screwdriver can be used to rotate chests sideways. So I wrote a command-line Lua script to locate all such incorrectly oriented chests, furnaces, bookshelves, and vessels shelves within the world.
Don't change these things! There's got to be enough intresting stuff for lga's intresting museums :-)
A list of my mods can be found here.

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

I developed a raycast function for efficiently computing line of sight between two points in 3d space. It is loosely based on the nearest neighbor line-drawing algorithm, and thus focuses on speed rather than accuracy.

raytrace_simple( pos1, pos2, on_plot )
• pos1 - the starting position of the ray as a vector
• pos2 - the ending position of the ray as a vector
• on_plot - the callback function for traversing the ray
The callback function will receive both the 1-based index and position of each successive node along the ray from pos1 through pos2. When an obstacle is encountered, the function should return false or nil to abort the raytrace.

Code: Select all

``````local function raytrace_simple( pos1, pos2, on_plot )
local p1 = vector.round( pos1 )
local p2 = vector.round( pos2 )
local ax = abs( p2.x - p1.x )
local ay = abs( p2.y - p1.y )
local az = abs( p2.z - p1.z )
local step = max( ax, ay, az )
local dx = ( p2.x - p1.x ) / step;
local dy = ( p2.y - p1.y ) / step;
local dz = ( p2.z - p1.z ) / step;
local x = p1.x
local y = p1.y
local z = p1.z

for i = 1, step + 1 do
if not on_plot( i, { x = floor( x + 0.5 ), y = floor( y + 0.5 ), z = floor( z + 0.5 ) } ) then
return false
end

x = x + dx
y = y + dy
z = z + dz
end

return true
end``````
Using the function above, a more flexible alternative to minetest.line_of_sight() can be devised:

Code: Select all

``````line_of_sight = function ( source_pos, target_pos )
local unknown_ndef = { groups = { }, walkable = false }

return raytrace_simple( source_pos, target_pos, function ( idx, pos )
local node = minetest.get_node( pos )
local ndef = core.registered_nodes[ node.name ] or unknown_ndef     -- account for unknown nodes
local is_airlike = not ndef.walkable

return is_airlike
end )
end
``````
Notice that the return value of raytrace_simple() reflects whether the callback succeeded or failed while traversing the ray.

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

This is a very simple Auth Redux ruleset for limiting new accounts to certain times of day, unless the server operator is online. Of course the range of hours can be changed by editing the pattern /8^19:?/t accordingly.

Code: Select all

``````try "Our server is only open to new players between 8:00-19:59 or when \$owner is online"
fail all
if \$is_new eq \$true
unless \$clock is /8^19:?/t
unless \$owner in \$users_list
continue
``````

Linuxdirk
Member
Posts: 2711
Joined: Wed Sep 17, 2014 11:21
In-game: Linuxdirk
Location: Germany
Contact:

A function to get a configuration value as string from either ./minetest.conf, a world-specific ./worlds/worldname/modname.conf or a given default value.

It is also possible to mark values as not changeable via configuration options (which could be done simply by not using the function then, but it’s all about options, right?).

Simply add this to your configuration Lua file or add it to your mod’s global table’s function section (fits within the 80 characters rule, of course).

Code: Select all

``````local get_config_option = function (key_name, default_value, changeable)
local mod = minetest.get_current_modname()
local config_option = mod..'_'..key_name
local value = default_value

if changeable ~= false then
local wc = Settings(minetest.get_worldpath()..DIR_DELIM..mod..'.conf')
local global_setting = minetest.settings:get(config_option)
local world_setting = wc:get(config_option)
value = world_setting or global_setting or default_value or ''
end

return value
end``````
And use it in your code like this:

Code: Select all

``````local my_option = get_config_option('my_option', 'foo')
local my_other_option = get_config_option('my_other_option', 'bar')
local and_so_on = get_config_option('and_so_on', 'baz', false)``````
This automatically allows users to configure things to their liking using the following parameters (assuming mymod is your mod’s name).

Code: Select all

``````mymod_my_option = foo
mymod_my_other_option = bar``````
If you later decide to have the third option also being configurable, simply remove the false parameter and players can set mymod_and_so_on, too.

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

Here is a new Minetest API function to make including libraries and submodules easier at long last.

Before:
local helpers = dofile( minetest.get_modpath( "othermod" ) .. "/helpers.lua" )

After:
local helpers = minetest.include( "/othermod/helpers.lua" )

Before:
loadfile( minetest.get_modpath( "thismod" ) .. "/gui.lua" )( config, player_list )

After:
minetest.include( "gui.lua", config, player_list )

The minetest.include() function includes a file. It accepts a file specifier, which may be either a path relative to the currently loading mod or else relative to another mod with a leading slash. Any additional parameters are passed directly to the loaded script, which may be retrieved via local var1, var2, var3 = ... at the head of the included file.

Code: Select all

``````function minetest.include( filespec, ... )
local mod_name, file_name = string.match( filespec, "^[/\](.-)[/\](.+)" )
if not mod_name then
mod_name = minetest.get_current_modname( )
file_name = filespec
end
return loadfile( minetest.get_modpath( mod_name ) .. "/" .. file_name )( ... )
end
``````

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

This is a handy command-line script for locating all "broken" beds in the world. It will output a list of bed parts that either
• consist of only a top but no bottom,
• consist of only a bottom but no top, or
• have incongruent orientation of bottom and top
At the head of the script are two variables that must be set accordingly:
• source_path = full path of the map.sqlite database to be opened in read-only mode
• search_area = the mapblock boundaries in which to limit the search (comment out to search the entire map)

Code: Select all

``````-- Find all mismatched bed parts (top or bottom)

package.path = "/home/minetest/maplib/?.lua;" .. package.path

local maplib = require "maplib"

local source_path = "/home/minetest/.minetest/worlds/world/map.sqlite"
--local search_area = MapArea( { x = -10, y = 0, z = -10 }, { x = 10, y = 0, z = 10 } )

---------------------------------------

local decode_node_pos = maplib.decode_node_pos
local hash_node_pos = maplib.hash_node_pos
local unhash_node_pos = maplib.unhash_node_pos
local pos_to_string = maplib.pos_to_string

local lower_parts = { }
local upper_parts = { }
local lower_count = 0
local upper_count = 0

local function analyze_block( block, index, node_list, nodename_map )
local is_found = false

for node_idx, node in ipairs( node_list ) do
local node_name = nodename_map[ node.id ]

if node_name == "beds:bed_bottom" or node_name == "beds:fancy_bed_bottom" then
local node_pos = decode_node_pos( node_idx, index )
local node_hash = hash_node_pos( node_pos )

lower_parts[ node_hash ] = node.param2
lower_count = lower_count + 1

elseif node_name == "beds:bed_top" or node_name == "beds:fancy_bed_top" then
local node_pos = decode_node_pos( node_idx, index )
local node_hash = hash_node_pos( node_pos )

upper_parts[ node_hash ] = node.param2
upper_count = upper_count + 1
end
end
end

local function compare_parts( )
for hash, param2 in pairs( lower_parts ) do
local pos2 = unhash_node_pos( hash )

if param2 == 0 then
pos2.z = pos2.z + 1
elseif param2 == 1 then
pos2.x = pos2.x + 1
elseif param2 == 2 then
pos2.z = pos2.z - 1
elseif param2 == 3 then
pos2.x = pos2.x - 1
else
pos2 = nil
end

if pos2 then
local hash2 = hash_node_pos( pos2 )

if upper_parts[ hash2 ] == param2 then
lower_parts[ hash ] = nil
upper_parts[ hash2 ] = nil
end
end
end

print( string.format( "Mismatched 'beds:bed_bottom' and 'beds:fancy_bed_bottom' (%d total):", lower_count ) )
for hash in pairs( lower_parts ) do
local pos = unhash_node_pos( hash )
print( string.format( "Found at %s", pos_to_string( pos ) ) )
end

print( string.format( "Mismatched 'beds:bed_top' and 'beds:fancy_bed_top' (%d total):", upper_count ) )
for hash in pairs( upper_parts ) do
local pos = unhash_node_pos( hash )
print( string.format( "Found at %s", pos_to_string( pos ) ) )
end
end

-----------------------------------------

local map_db = MapDatabase( source_path, false )

if search_area then
print( "Creating cache..." )
map_db.create_cache( false )
end

print( "Examining database..." )

local iterator = search_area and map_db.iterate_area( search_area ) or map_db.iterate( )

for index, block in iterator do
local nodename_map = block.nodename_map

for i, n in pairs( block.nodename_map ) do
-- if there is at least one bed, then analyze mapblock
if n == "beds:bed_bottom" or n == "beds:bed_top" or n == "beds:fancy_bed_bottom" or n == "beds:fancy_bed_top" then
local node_list = block.get_node_list( )

analyze_block( block, index, node_list, nodename_map )
break
end
end
end

compare_parts( )
``````

Termos
Member
Posts: 372
Joined: Sun Dec 16, 2018 12:50

Minetest implementation of Midpoint Circle algorithm

Code: Select all

``````local function circle(pos,r,plane,callback)
local tpos = {}
tpos[plane] = pos[plane]
local ax = {'x','y','z'}

for i,e in ipairs(ax) do
if e==plane then
table.remove(ax,i)
if #ax ~= 2 then
return
end
end
end

local dx, dy, err = r, 0, 1-r
local c1, c2 = ax[1], ax[2]
while dx >= dy do
tpos[c1], tpos[c2] = pos[c1]+dx, pos[c2]+dy
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]-dx, pos[c2]+dy
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]+dx, pos[c2]-dy
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]-dx, pos[c2]-dy
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]+dy, pos[c2]+dx
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]-dy, pos[c2]+dx
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]-dy, pos[c2]+dx
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]+dy, pos[c2]-dx
callback(tpos)
tpos[c1], tpos[c2] = pos[c1]-dy, pos[c2]-dx
callback(tpos)
dy = dy + 1
if err < 0 then
err = err + 2 * dy + 1
else
dx, err = dx-1, err + 2 * (dy - dx) + 1
end
end
end
``````
Attachments
screenshot_20210112_104151.png

AspireMint
Member
Posts: 390
Joined: Mon Jul 09, 2012 12:59
GitHub: AspireMint
IRC: AspireMint
In-game: AspireMint
Location: Stuck at spawn

Code: Select all

``````wrap = function(t)
local w = {}
setmetatable(w, { __index = t })
return w
end

unwrap = function(w)
local mt = getmetatable(w)
return mt and mt.__index or w
end``````
With this you can override global table without affecting other mods.
Example:

Code: Select all

``````local M = wrap(minetest)
M.chat_send_all("yay A")
M.chat_send_all = function(msg)
print("shhh")
minetest.chat_send_all(msg)
-- or unwrap(M).chat_send_all(msg)
end
M.chat_send_all("yay two")
minetest.chat_send_all("yay 3")``````
Probably useful (?) when you want to improve minetest table but only inside of your mod and not break any other mod.

### Who is online

Users browsing this forum: No registered users and 7 guests