Post your code!

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

Re: Post your code!

by Sokomine » Post

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.

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

Re: Post your code!

by sorcerykid » Post

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.

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

Re: Post your code!

by sorcerykid » Post

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

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

Re: Post your code!

by Linuxdirk » Post

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.

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

Re: Post your code!

by sorcerykid » Post

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

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

Re: Post your code!

by sorcerykid » Post

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

Re: Post your code!

by Termos » Post

Minetest implementation of Midpoint Circle algorithm

Image

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 
				minetest.log("error","circle: bad plane argument")
				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
(93.21 KiB) Not downloaded yet

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

Re: Post your code!

by AspireMint » Post

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.

Post Reply

Who is online

Users browsing this forum: No registered users and 7 guests