2022-04-09 20:42:52 +02:00
-- If true, the Perlin test nodes will support color
-- (set to false in case of performance problems)
local COLORIZE_NODES = true
2022-04-15 21:43:23 +02:00
-- The number of available test node colors is divided by this number.
-- A number between 1 to 256
-- * 1 = Full 256 palette.
-- * 2 = 128 colors.
-- * 4 = 64 colors.
-- etc.
-- Higher values lead to less colors but increased performance.
-- This value is only used for performance reason, because Minetest
-- has a sharp performance drop when there are many different node colors on screen.
-- Consider removing this one when Minetest's performance problem has been solved.
local COLOR_PRECISION = 4
2022-04-09 20:42:52 +02:00
2022-04-15 22:30:02 +02:00
-- Time to wait in seconds before checking and generating new nodes in autobuild mode.
2022-04-16 15:10:49 +02:00
local AUTOBUILD_UPDATE_TIME = 0.1
2022-04-15 22:30:02 +02:00
2022-04-16 15:36:54 +02:00
-- x/y/z size of "noisechunks" (like chunks in the Minetest mapgen, but specific to this
-- mod) to generate in autobuild mode.
2022-04-19 11:37:05 +02:00
local AUTOBUILD_SIZE = 16
2022-04-16 15:36:54 +02:00
-- Amount of noisechunks to generate around player
2022-04-16 01:33:59 +02:00
local AUTOBUILD_CHUNKDIST = 2
2022-04-15 22:30:02 +02:00
2022-04-15 05:55:17 +02:00
-- Color of the formspec box[] element
local FORMSPEC_BOX_COLOR = " #00000080 "
2022-04-16 00:25:00 +02:00
-- Color for the section titles in the formspec
local FORMSPEC_HEADER_COLOR = " #000000FF "
2022-04-15 05:55:17 +02:00
2022-04-17 01:21:21 +02:00
-- Buckets to use for the histogram
2022-04-16 23:48:35 +02:00
local HISTOGRAM_BUCKETS = 10
2022-04-17 01:21:21 +02:00
-- Length of side (XZ) of the square to calculate in the Deep Analyze mode.
-- Number of values calculated is this to the power of 2.
local DEEP_ANALYSIS_SIZE_2D = 2048
-- Length of side (XZZ) of the cube to calculate in the Deep Analyze mode.
-- Number of values calculated is this to the power of 3.
local DEEP_ANALYSIS_SIZE_3D = 162 -- 163^3 is roughly equal to 2048
2022-04-09 18:25:27 +02:00
local S = minetest.get_translator ( " perlin_explorer " )
2022-04-10 01:45:19 +02:00
local F = minetest.formspec_escape
2022-04-09 18:23:01 +02:00
2022-04-15 05:55:17 +02:00
-- Per-player formspec states (mostly for remembering checkbox states)
2022-04-14 04:47:05 +02:00
local formspec_states = { }
2022-04-15 05:55:17 +02:00
-- List of noise parameters profiles
local np_profiles = { }
local default_noiseparams = {
2022-04-10 01:54:20 +02:00
offset = 0.0 ,
scale = 1.0 ,
spread = vector.new ( 10 , 10 , 10 ) ,
seed = 0 ,
octaves = 2 ,
2022-04-14 05:14:00 +02:00
persistence = 0.5 ,
2022-04-10 01:54:20 +02:00
lacunarity = 2.0 ,
2022-04-14 04:47:05 +02:00
flags = " noeased,noabsvalue " ,
2022-04-10 01:54:20 +02:00
}
2022-04-15 05:55:17 +02:00
-- Holds the currently used Perlin noise
local current_perlin = { }
-- holds the current PerlinNoise object
current_perlin.noise = nil
current_perlin.noiseparams = table.copy ( default_noiseparams )
2022-04-16 18:08:49 +02:00
local noise_settings = dofile ( minetest.get_modpath ( minetest.get_current_modname ( ) ) .. " /noise_settings_list.lua " )
for n = 1 , # noise_settings do
local np = minetest.get_mapgen_setting_noiseparams ( noise_settings [ n ] )
-- TODO/FIXME: Make sure that ALL noise settings are gettable (not just those of the active mapgen)
if np then
table.insert ( np_profiles , { noiseparams = np , name = noise_settings [ n ] , can_delete = false } )
end
end
table.insert ( np_profiles , { noiseparams = current_perlin.noiseparams } )
2022-04-10 00:33:16 +02:00
-- Side length of calculated perlin area
2022-04-11 02:21:07 +02:00
current_perlin.size = 64
2022-04-09 18:23:01 +02:00
-- Theoretical min and max values for Perlin noise (for colorization)
current_perlin.min = - 1
2022-04-11 02:21:07 +02:00
current_perlin.max = 1
2022-04-16 03:24:41 +02:00
current_perlin.nodetype = 1
2022-04-09 18:23:01 +02:00
2022-04-09 21:43:33 +02:00
-- dimensions of current Perlin noise (2 or 3)
current_perlin.dimensions = 2
-- If greater than 1, the Perlin noise values are "pixelized". Noise values at
-- coordinates not divisible by sidelen will be set equal to the noise value
-- of the nearest number (counting downwards) that is divisible by sidelen.
-- This is (kind of) analogous to the "sidelen" parameter of mapgen decorations.
current_perlin.sidelen = 1
2022-04-16 04:44:05 +02:00
-- Place position of current perlin (relevant for single placing)
2022-04-16 13:25:21 +02:00
current_perlin.pos = nil
2022-04-09 20:42:52 +02:00
2022-04-16 04:44:05 +02:00
-- If enabled, automatically generate nodes around player
current_perlin.autogen = false
-- Remember which areas have been loaded by the autogen so far
-- Index: Hash of node position, value: true if loaded
2022-04-16 13:01:48 +02:00
local loaded_areas = { }
2022-04-14 03:07:42 +02:00
2022-04-09 20:42:52 +02:00
------------
2022-04-09 21:43:33 +02:00
-- Helper functions
-- Reduce the pos coordinates down to the closest numbers divisible by sidelen
local sidelen_pos = function ( pos , sidelen )
2022-04-17 14:15:27 +02:00
local newpos = { x = pos.x , y = pos.y , z = pos.z }
2022-04-09 21:43:33 +02:00
if sidelen <= 1 then
return newpos
end
2022-04-09 23:11:58 +02:00
newpos.x = newpos.x - newpos.x % sidelen
newpos.y = newpos.y - newpos.y % sidelen
newpos.z = newpos.z - newpos.z % sidelen
2022-04-09 21:43:33 +02:00
return newpos
end
2022-04-16 06:20:08 +02:00
local build_flags_string = function ( eased , absvalue )
local flags = " "
if eased then
flags = " eased "
else
flags = " noeased "
end
if absvalue then
flags = flags .. " ,absvalue "
else
flags = flags .. " ,noabsvalue "
end
return flags
end
local parse_flags_string = function ( flags )
local ftable = string.split ( flags , " , " )
local eased , absvalue = false , false
for f = 1 , # ftable do
local s = string.trim ( ftable [ f ] )
if s == " eased " then
eased = true
elseif s == " absvalue " then
absvalue = true
end
end
return { eased = eased , absvalue = absvalue }
end
2022-04-15 22:11:32 +02:00
-- Sets the currently active Perlin noise.
-- * noiseparams: NoiseParams table (see Minetest's Lua API documentation)
local set_perlin_noise = function ( noiseparams )
current_perlin.noise = PerlinNoise ( noiseparams )
current_perlin.noiseparams = noiseparams
end
2022-04-09 18:23:01 +02:00
-- Test nodes to generate a map based on a perlin noise
2022-04-09 20:42:52 +02:00
local paramtype2
if COLORIZE_NODES then
paramtype2 = " color "
end
2022-04-16 03:24:41 +02:00
2022-04-16 03:37:31 +02:00
-- Register list of node types for test mapgen
2022-04-16 03:24:41 +02:00
local nodetypes = {
2022-04-16 03:37:31 +02:00
-- { Entry name for sformspec, positive node, negative node, supports color? }
{ S ( " Solid Nodes " ) , " perlin_explorer:node " , " perlin_explorer:node_negative " , true } ,
{ S ( " Grid Nodes " ) , " perlin_explorer:grid " , " perlin_explorer:grid_negative " , true } ,
{ S ( " Minibox Nodes " ) , " perlin_explorer:mini " , " perlin_explorer:mini_negative " , true } ,
2022-04-16 03:24:41 +02:00
}
2022-04-16 06:20:08 +02:00
-- Analyze the given noiseparams for interesting properties.
2022-04-19 12:43:19 +02:00
-- Returns: <min>, <max>, <waves>, <bad_wavelength>
2022-04-16 06:20:08 +02:00
-- min = minimum possible value
-- max = maximum possible value
-- waves = table with x/y/z indices, each containing a list of effective "wavelengths" for each of the axes
2022-04-19 12:43:19 +02:00
-- bad_wavelength = true if any wavelength is lower than 1
2022-04-16 06:20:08 +02:00
local analyze_noiseparams = function ( noiseparams )
local np = noiseparams
local flags = parse_flags_string ( noiseparams.flags )
local is_absolute = flags.absvalue == true
-- Calculate min. and max. possible values
-- Octaves
local o_min , o_max = 0 , 0
for o = 1 , np.octaves do
local exp = o - 1
o_max = o_max + ( 1 * np.persistence ^ exp )
if not is_absolute then
o_min = o_min + ( - 1 * np.persistence ^ exp )
-- Note: If absvalue flag is set, the sum of the octaves
-- is always 0, so we don't need to calculate it
end
end
2022-04-17 12:43:14 +02:00
-- Add offset and scale to min/max value (final step)
2022-04-16 06:20:08 +02:00
local min_value = np.offset + np.scale * o_min
local max_value = np.offset + np.scale * o_max
2022-04-17 12:43:14 +02:00
-- Bring the 2 values in the correct order
-- (min_value might be bigger for negative scale)
if min_value > max_value then
min_value , max_value = max_value , min_value
end
2022-04-19 12:43:19 +02:00
local bad_wavelength = false
2022-04-16 06:20:08 +02:00
-- Calculate "wavelengths"
local axes = { " x " , " y " , " z " }
local waves = { }
for a = 1 , # axes do
local w = axes [ a ]
waves [ w ] = { }
local wave = np.spread [ w ]
for o = 1 , np.octaves do
2022-04-19 12:43:19 +02:00
if wave < 1 then
bad_wavelength = true
end
2022-04-16 06:20:08 +02:00
table.insert ( waves [ w ] , wave )
wave = wave * ( 1 / np.lacunarity )
end
end
2022-04-19 12:43:19 +02:00
return min_value , max_value , waves , bad_wavelength
2022-04-16 06:20:08 +02:00
end
2022-04-16 03:37:31 +02:00
-- Add stone node to nodetypes, if present
minetest.register_on_mods_loaded ( function ( )
local stone = minetest.registered_aliases [ " mapgen_stone " ]
if stone then
local desc = minetest.registered_nodes [ stone ] . description
if not desc then
desc = stone
end
table.insert ( nodetypes , { desc , stone , " air " , false } )
end
end )
2022-04-09 18:25:27 +02:00
minetest.register_node ( " perlin_explorer:node " , {
2022-04-16 02:55:36 +02:00
description = S ( " Solid Perlin Test Node " ) ,
2022-04-10 01:54:20 +02:00
paramtype = " light " ,
sunlight_propagates = true ,
2022-04-09 20:42:52 +02:00
paramtype2 = paramtype2 ,
2022-04-09 18:25:27 +02:00
tiles = { " perlin_explorer_node.png " } ,
palette = " perlin_explorer_node_palette.png " ,
2022-04-09 18:23:01 +02:00
groups = { dig_immediate = 3 } ,
-- Force-drop without metadata to avoid spamming the inventory
2022-04-09 18:25:27 +02:00
drop = " perlin_explorer:node " ,
2022-04-09 18:23:01 +02:00
} )
2022-04-09 18:25:27 +02:00
minetest.register_node ( " perlin_explorer:node_negative " , {
2022-04-16 02:55:36 +02:00
description = S ( " Solid Negative Perlin Test Node " ) ,
2022-04-10 01:54:20 +02:00
paramtype = " light " ,
sunlight_propagates = true ,
2022-04-09 20:42:52 +02:00
paramtype2 = paramtype2 ,
2022-04-09 18:25:27 +02:00
tiles = { " perlin_explorer_node_neg.png " } ,
palette = " perlin_explorer_node_palette_neg.png " ,
2022-04-09 18:23:01 +02:00
groups = { dig_immediate = 3 } ,
-- Force-drop without metadata to avoid spamming the inventory
2022-04-09 18:25:27 +02:00
drop = " perlin_explorer:node_negative " ,
2022-04-09 18:23:01 +02:00
} )
2022-04-16 02:20:53 +02:00
2022-04-16 02:55:36 +02:00
minetest.register_node ( " perlin_explorer:grid " , {
description = S ( " Grid Perlin Test Node " ) ,
2022-04-16 02:20:53 +02:00
paramtype = " light " ,
drawtype = " allfaces " ,
2022-04-16 02:55:36 +02:00
use_texture_alpha = " clip " ,
2022-04-16 02:20:53 +02:00
sunlight_propagates = true ,
paramtype2 = paramtype2 ,
2022-04-16 02:55:36 +02:00
tiles = { " perlin_explorer_grid.png " } ,
2022-04-16 02:20:53 +02:00
palette = " perlin_explorer_node_palette.png " ,
groups = { dig_immediate = 3 } ,
2022-04-16 02:55:36 +02:00
drop = " perlin_explorer:grid " ,
2022-04-16 02:20:53 +02:00
} )
2022-04-16 02:55:36 +02:00
minetest.register_node ( " perlin_explorer:grid_negative " , {
description = S ( " Grid Negative Perlin Test Node " ) ,
2022-04-16 02:20:53 +02:00
paramtype = " light " ,
sunlight_propagates = true ,
paramtype2 = paramtype2 ,
2022-04-16 02:55:36 +02:00
tiles = { " perlin_explorer_grid_neg.png " } ,
use_texture_alpha = " clip " ,
palette = " perlin_explorer_node_palette_neg.png " ,
groups = { dig_immediate = 3 } ,
drop = " perlin_explorer:grid_negative " ,
} )
minetest.register_node ( " perlin_explorer:mini " , {
description = S ( " Minibox Perlin Test Node " ) ,
paramtype = " light " ,
drawtype = " nodebox " ,
climbable = true ,
walkable = false ,
node_box = {
type = " fixed " ,
fixed = { - 2 / 16 , - 2 / 16 , - 2 / 16 , 2 / 16 , 2 / 16 , 2 / 16 } ,
} ,
use_texture_alpha = " clip " ,
sunlight_propagates = true ,
paramtype2 = paramtype2 ,
tiles = { " perlin_explorer_mini.png " } ,
palette = " perlin_explorer_node_palette.png " ,
groups = { dig_immediate = 3 } ,
drop = " perlin_explorer:mini " ,
} )
minetest.register_node ( " perlin_explorer:mini_negative " , {
description = S ( " Minibox Negative Perlin Test Node " ) ,
paramtype = " light " ,
drawtype = " nodebox " ,
climbable = true ,
walkable = false ,
node_box = {
type = " fixed " ,
fixed = { - 2 / 16 , - 2 / 16 , - 2 / 16 , 2 / 16 , 2 / 16 , 2 / 16 } ,
} ,
sunlight_propagates = true ,
paramtype2 = paramtype2 ,
tiles = { " perlin_explorer_mini_neg.png " } ,
use_texture_alpha = " clip " ,
2022-04-16 02:20:53 +02:00
palette = " perlin_explorer_node_palette_neg.png " ,
groups = { dig_immediate = 3 } ,
2022-04-16 02:55:36 +02:00
drop = " perlin_explorer:mini_negative " ,
2022-04-16 02:20:53 +02:00
} )
2022-04-16 18:53:06 +02:00
local print_value = function ( pos , user , precision , ptype )
local val
local getpos = sidelen_pos ( pos , current_perlin.sidelen )
if current_perlin.dimensions == 2 then
val = current_perlin.noise : get_2d ( { x = getpos.x , y = getpos.z } )
elseif current_perlin.dimensions == 3 then
val = current_perlin.noise : get_3d ( getpos )
else
2022-04-17 12:09:13 +02:00
error ( " [perlin_explorer] Unknown/invalid number of Perlin noise dimensions! " )
return
2022-04-16 18:53:06 +02:00
end
local msg
2022-04-17 12:05:13 +02:00
local color_node = minetest.get_color_escape_sequence ( " #FFD47CFF " )
local color_player = minetest.get_color_escape_sequence ( " #87FF87FF " )
local color_end = minetest.get_color_escape_sequence ( " #FFFFFFFF " )
2022-04-16 18:53:06 +02:00
if ptype == " node " then
2022-04-17 12:05:13 +02:00
msg = S ( " Value at @1node@2 pos @3: @4 " , color_node , color_end , minetest.pos_to_string ( pos , precision ) , val )
2022-04-16 18:53:06 +02:00
elseif ptype == " player " then
2022-04-17 12:05:13 +02:00
msg = S ( " Value at @1player@2 pos @3: @4 " , color_player , color_end , minetest.pos_to_string ( pos , precision ) , val )
2022-04-16 18:53:06 +02:00
else
error ( " [perlin_explorer] Invalid ptype in print_value()! " )
end
minetest.chat_send_player ( user : get_player_name ( ) , msg )
end
-- Get Perlin value of player pos
local use_getter = function ( itemstack , user , pointed_thing )
if not user then
return
end
local privs = minetest.get_player_privs ( user : get_player_name ( ) )
if not privs.server then
minetest.chat_send_player ( user : get_player_name ( ) , S ( " Insufficient privileges! You need the @1 privilege to use this tool. " , " server " ) )
return
end
if current_perlin.noise then
local pos = user : get_pos ( )
local ctrl = user : get_player_control ( )
local precision = 1
if not ctrl.sneak then
pos = vector.round ( pos )
precision = 0
end
print_value ( pos , user , precision , " player " )
else
local msg = S ( " No Perlin noise set. Set one first! " )
minetest.chat_send_player ( user : get_player_name ( ) , msg )
end
end
-- Get Perlin value of pointed node
local place_getter = function ( itemstack , user , pointed_thing )
if not user then
return
end
local privs = minetest.get_player_privs ( user : get_player_name ( ) )
if not privs.server then
minetest.chat_send_player ( user : get_player_name ( ) , S ( " Insufficient privileges! You need the @1 privilege to use this tool. " , " server " ) )
return
end
if current_perlin.noise then
if pointed_thing.type ~= " node " then
-- No-op for non-nodes
return
end
local pos = pointed_thing.under
print_value ( pos , user , 0 , " node " )
else
local msg = S ( " No Perlin noise set. Set one first! " )
minetest.chat_send_player ( user : get_player_name ( ) , msg )
end
end
2022-04-09 20:39:15 +02:00
minetest.register_tool ( " perlin_explorer:getter " , {
description = S ( " Perlin Value Getter " ) ,
2022-04-16 18:53:06 +02:00
_tt_help = S ( " Place: Display Perlin noise value of the pointed node position " ) .. " \n " ..
S ( " Punch: Display Perlin noise value of player position (+Sneak: precise position) " ) ,
2022-04-09 20:39:15 +02:00
inventory_image = " perlin_explorer_getter.png " ,
wield_image = " perlin_explorer_getter.png " ,
groups = { disable_repair = 1 } ,
2022-04-16 18:53:06 +02:00
on_use = use_getter ,
on_place = place_getter ,
2022-04-09 20:39:15 +02:00
} )
2022-04-09 23:17:35 +02:00
local update_map = function ( pos , set_nodes )
2022-04-09 18:23:01 +02:00
local stats
if not current_perlin.noise then
return
end
2022-04-17 14:15:27 +02:00
local time1 = minetest.get_us_time ( )
local size_v = {
x = current_perlin.size ,
y = current_perlin.size ,
z = current_perlin.size ,
}
2022-04-09 18:23:01 +02:00
local startpos = pos
2022-04-10 00:33:16 +02:00
local endpos = vector.add ( startpos , current_perlin.size - 1 )
2022-04-09 18:23:01 +02:00
local y_max = endpos.y - startpos.y
if current_perlin.dimensions == 2 then
y_max = 0
startpos.y = pos.y
endpos.y = pos.y
2022-04-17 14:15:27 +02:00
size_v.z = nil
2022-04-09 18:23:01 +02:00
end
2022-04-09 23:17:35 +02:00
local vmanip , emin , emax , vdata , vdata2 , varea
if set_nodes then
vmanip = VoxelManip ( startpos , endpos )
emin , emax = vmanip : get_emerged_area ( )
vdata = vmanip : get_data ( )
vdata2 = vmanip : get_param2_data ( )
varea = VoxelArea : new ( { MinEdge = emin , MaxEdge = emax } )
end
2022-04-09 21:43:33 +02:00
2022-04-16 03:24:41 +02:00
local content_test_node = minetest.get_content_id ( nodetypes [ current_perlin.nodetype ] [ 2 ] )
local content_test_node_negative = minetest.get_content_id ( nodetypes [ current_perlin.nodetype ] [ 3 ] )
2022-04-16 03:37:31 +02:00
local needs_color = nodetypes [ current_perlin.nodetype ] [ 4 ]
2022-04-16 03:24:41 +02:00
2022-04-09 18:23:01 +02:00
stats = { }
stats.avg = 0
local sum_of_values = 0
2022-04-16 23:48:35 +02:00
stats.value_count = 0
stats.histogram = { }
local min_possible , max_possible = analyze_noiseparams ( current_perlin.noiseparams )
local cutoff_points = { }
for d = 1 , HISTOGRAM_BUCKETS do
cutoff_points [ d ] = min_possible + ( ( max_possible - min_possible ) / HISTOGRAM_BUCKETS ) * d
stats.histogram [ d ] = 0
end
2022-04-17 14:15:27 +02:00
-- Initialize Perlin map
local perlin_map_object = PerlinNoiseMap ( current_perlin.noiseparams , size_v )
local perlin_map
if current_perlin.dimensions == 2 then
perlin_map = perlin_map_object : get_2d_map ( { x = startpos.x , y = startpos.z } )
else
perlin_map = perlin_map_object : get_3d_map ( startpos )
end
2022-04-09 18:23:01 +02:00
for x = 0 , endpos.x - startpos.x do
for y = 0 , y_max do
for z = 0 , endpos.z - startpos.z do
-- Get Perlin value at current pos
2022-04-17 14:44:41 +02:00
-- Note: This section has been optimized. Don’ t introduce stuff like
-- vectors.new() here.
2022-04-17 14:15:27 +02:00
local relpos = { x = x , y = y , z = z }
local abspos = {
x = startpos.x + relpos.x ,
y = startpos.y + relpos.y ,
z = startpos.z + relpos.z ,
}
2022-04-17 14:44:41 +02:00
-- Apply sidelen transformation (pixelize)
local abspos_get = sidelen_pos ( abspos , current_perlin.sidelen )
local indexpos = {
x = abspos_get.x - startpos.x + 1 ,
y = abspos_get.y - startpos.y + 1 ,
z = abspos_get.z - startpos.z + 1 ,
}
2022-04-09 18:23:01 +02:00
local perlin_value
if current_perlin.dimensions == 2 then
2022-04-17 14:44:41 +02:00
if indexpos.x < 1 or indexpos.z < 1 then
-- The pixelization can move indexpos below 1, in this case
-- we get the perlin value directly because it is outside
-- the precalculated map. Performance impact is hopefully
-- not too bad because this will only occur at the low
-- edges.
-- Ideally, for cleaner code, the precalculated map would
-- take this into account as well but this has not
-- been done yet.
perlin_value = current_perlin.noise : get_2d ( { x = abspos_get.x , y = abspos_get.z } )
else
-- Normal case: Get value from perlin map
perlin_value = perlin_map [ indexpos.z ] [ indexpos.x ]
end
2022-04-09 18:23:01 +02:00
elseif current_perlin.dimensions == 3 then
2022-04-17 14:44:41 +02:00
if indexpos.x < 1 or indexpos.y < 1 or indexpos.z < 1 then
-- See above
perlin_value = current_perlin.noise : get_3d ( abspos_get )
else
-- See above
perlin_value = perlin_map [ indexpos.z ] [ indexpos.y ] [ indexpos.x ]
end
2022-04-09 18:23:01 +02:00
else
2022-04-09 18:25:27 +02:00
error ( " [perlin_explorer] Unknown/invalid number of Perlin noise dimensions! " )
2022-04-09 18:23:01 +02:00
return
end
-- Statistics
if not stats.min then
stats.min = perlin_value
elseif perlin_value < stats.min then
stats.min = perlin_value
end
if not stats.max then
stats.max = perlin_value
elseif perlin_value > stats.max then
stats.max = perlin_value
end
2022-04-16 23:48:35 +02:00
-- Histogram
for c = 1 , HISTOGRAM_BUCKETS do
if perlin_value < cutoff_points [ c ] or c >= HISTOGRAM_BUCKETS then
stats.histogram [ c ] = stats.histogram [ c ] + 1
break
end
end
2022-04-09 18:23:01 +02:00
sum_of_values = sum_of_values + perlin_value
2022-04-16 23:48:35 +02:00
stats.value_count = stats.value_count + 1
2022-04-09 18:23:01 +02:00
2022-04-17 14:15:27 +02:00
if set_nodes then
-- Calculate color (param2) for node
local zeropoint = 0
local min_size = zeropoint - current_perlin.min
local max_size = current_perlin.max - zeropoint
local node_param2 = 0
if needs_color then
if perlin_value >= zeropoint then
node_param2 = ( math.abs ( perlin_value ) / max_size ) * 255
else
node_param2 = ( math.abs ( perlin_value ) / min_size ) * 255
end
node_param2 = math.floor ( math.abs ( node_param2 ) )
node_param2 = math.max ( 0 , math.min ( 255 , node_param2 ) )
if node_param2 < 255 then
node_param2 = node_param2 - ( node_param2 % COLOR_PRECISION )
end
2022-04-16 03:37:31 +02:00
end
2022-04-09 18:23:01 +02:00
2022-04-09 23:17:35 +02:00
-- Get vmanip index
local index = varea : indexp ( abspos )
if not index then
return
end
2022-04-09 18:23:01 +02:00
2022-04-09 23:17:35 +02:00
-- Set node and param2
if perlin_value >= zeropoint then
2022-04-16 03:24:41 +02:00
vdata [ index ] = content_test_node
2022-04-09 18:23:01 +02:00
vdata2 [ index ] = node_param2
else
2022-04-09 23:17:35 +02:00
if current_perlin.show_negative == true then
2022-04-16 03:24:41 +02:00
vdata [ index ] = content_test_node_negative
2022-04-09 23:17:35 +02:00
vdata2 [ index ] = node_param2
else
vdata [ index ] = minetest.CONTENT_AIR
vdata2 [ index ] = 0
end
2022-04-09 18:23:01 +02:00
end
end
end
end
end
2022-04-16 23:48:35 +02:00
stats.avg = sum_of_values / stats.value_count
stats.histogram_points = cutoff_points
2022-04-09 18:23:01 +02:00
2022-04-09 23:17:35 +02:00
if set_nodes then
-- Set vmanip, return stats
vmanip : set_data ( vdata )
vmanip : set_param2_data ( vdata2 )
vmanip : write_to_map ( )
end
2022-04-17 14:15:27 +02:00
local time2 = minetest.get_us_time ( )
local timediff = time2 - time1
minetest.log ( " verbose " , " [perlin_explorer] Noisechunk calculated/generated in " .. timediff .. " µs " )
2022-04-09 18:23:01 +02:00
return stats
end
-- Creates and demonstrates a Perlin noise.
-- * pos: Where the Perlin noise starts
-- * options: table with:
-- * dimensions: number of Perlin noise dimensions (2 or 3)
2022-04-10 00:33:16 +02:00
-- * size: side length of area/volume to calculate)
2022-04-09 19:44:15 +02:00
-- * show_negative: if true, places nodes for negative Perlin values (default: true for 2 dimensions and false for 3 dimensions)
2022-04-09 23:17:35 +02:00
-- * set_nodes: if true, will set nodes, otherwise it's a "dry run"
local create_perlin = function ( pos , options )
2022-04-09 19:44:15 +02:00
if not current_perlin.noise then
return false
end
2022-04-09 18:23:01 +02:00
current_perlin.dimensions = options.dimensions
2022-04-10 00:33:16 +02:00
current_perlin.size = options.size
2022-04-09 18:23:01 +02:00
current_perlin.show_negative = options.show_negative
if current_perlin.show_negative == nil then
2022-04-09 19:44:15 +02:00
if current_perlin.dimensions == 2 then
2022-04-09 20:39:15 +02:00
current_perlin.show_negative = true
2022-04-09 19:44:15 +02:00
elseif current_perlin.dimensions == 3 then
2022-04-09 20:39:15 +02:00
current_perlin.show_negative = false
2022-04-09 19:44:15 +02:00
end
2022-04-09 18:23:01 +02:00
end
2022-04-15 22:41:31 +02:00
local cpos = table.copy ( pos )
local mpos = vector.round ( cpos )
2022-04-11 02:21:07 +02:00
current_perlin.pos = mpos
2022-04-09 23:17:35 +02:00
local set_nodes = options.set_nodes ~= false
local stats = update_map ( mpos , set_nodes )
2022-04-16 02:05:51 +02:00
2022-04-16 23:48:35 +02:00
if set_nodes then
-- Show a particle in the center of the newly generated area
local center = vector.new ( )
center.x = mpos.x + options.size / 2
if current_perlin.dimensions == 2 then
center.y = mpos.y + 3
else
center.y = mpos.y + options.size / 2
end
center.z = mpos.z + options.size / 2
minetest.add_particle ( {
pos = center ,
expirationtime = 4 ,
size = 16 ,
texture = " perlin_explorer_new_noisechunk.png " ,
glow = minetest.LIGHT_MAX ,
} )
end
2022-04-09 18:23:01 +02:00
if stats then
2022-04-16 04:52:29 +02:00
minetest.log ( " info " , " [perlin_explorer] Perlin noise generated at %s! Stats: min. value=%.3f, max. value=%.3f, avg. value=%.3f " , minetest.pos_to_string ( mpos ) , stats.min , stats.max , stats.avg )
2022-04-16 23:48:35 +02:00
return S ( " Perlin noise generated at @1! " , minetest.pos_to_string ( mpos ) ) , stats
2022-04-16 04:52:29 +02:00
else
minetest.log ( " error " , " [perlin_explorer] Could not get stats! " )
return false
2022-04-09 18:23:01 +02:00
end
end
2022-04-16 13:25:21 +02:00
local seeder_reseed = function ( player , regen )
local msg
if regen and ( not current_perlin.autogen and current_perlin.pos ) then
msg = S ( " New random seed set, starting to regenerate nodes ... " )
minetest.chat_send_player ( player : get_player_name ( ) , msg )
msg = create_perlin ( current_perlin.pos , { dimensions = current_perlin.dimensions , size = current_perlin.size } )
if msg ~= false then
minetest.chat_send_player ( player : get_player_name ( ) , msg )
end
else
msg = S ( " New random seed set! " )
minetest.chat_send_player ( player : get_player_name ( ) , msg )
end
end
local function seeder_use ( reseed )
return function ( itemstack , user , pointed_thing )
if not user then
return
end
local privs = minetest.get_player_privs ( user : get_player_name ( ) )
if not privs.server then
minetest.chat_send_player ( user : get_player_name ( ) , S ( " Insufficient privileges! You need the @1 privilege to use this tool. " , " server " ) )
return
end
if current_perlin.noise then
local noiseparams = table.copy ( current_perlin.noiseparams )
noiseparams.seed = math.random ( 0 , 2 ^ 32 - 1 )
set_perlin_noise ( noiseparams )
loaded_areas = { }
seeder_reseed ( user , reseed )
else
local msg = S ( " No Perlin noise set. Set one first! " )
minetest.chat_send_player ( user : get_player_name ( ) , msg )
end
end
end
minetest.register_tool ( " perlin_explorer:seeder " , {
description = S ( " Random Perlin seed setter " ) ,
_tt_help = S ( " Punch: Set a random seed for the current Perlin noise params " ) .. " \n " ..
S ( " Place: Set a random seed and regenerate nodes (if applicable) " ) ,
inventory_image = " perlin_explorer_seeder.png " ,
wield_image = " perlin_explorer_seeder.png " ,
groups = { disable_repair = 1 } ,
on_use = seeder_use ( false ) ,
on_secondary_use = seeder_use ( true ) ,
on_place = seeder_use ( true ) ,
} )
2022-04-09 21:43:33 +02:00
minetest.register_chatcommand ( " perlin_set_options " , {
privs = { server = true } ,
2022-04-16 13:53:00 +02:00
description = S ( " Set Perlin map generation options " ) ,
2022-04-09 22:48:27 +02:00
params = S ( " <dimensions> <sidelen> <minval> <maxval> " ) ,
2022-04-09 21:43:33 +02:00
func = function ( name , param )
2022-04-09 22:48:27 +02:00
local dimensions , sidelen , min , max = string.match ( param , " ([23]) ([0-9]+) ([0-9.-]+) ([0-9.-]+) " )
if not dimensions then
2022-04-09 21:43:33 +02:00
return false
end
dimensions = tonumber ( dimensions )
sidelen = tonumber ( sidelen )
2022-04-09 22:48:27 +02:00
min = tonumber ( min )
max = tonumber ( max )
if not dimensions or not sidelen or not min or not max then
2022-04-09 21:43:33 +02:00
return false , S ( " Invalid parameter type. " )
end
current_perlin.dimensions = dimensions
current_perlin.sidelen = sidelen
2022-04-09 22:48:27 +02:00
current_perlin.min = min
current_perlin.max = max
2022-04-16 13:01:48 +02:00
loaded_areas = { }
2022-04-16 13:53:00 +02:00
return true , S ( " Perlin map generation options set! " )
2022-04-09 21:43:33 +02:00
end ,
} )
2022-04-09 23:17:35 +02:00
2022-04-09 21:43:33 +02:00
minetest.register_chatcommand ( " perlin_set_noise " , {
2022-04-09 19:44:15 +02:00
privs = { server = true } ,
2022-04-16 13:53:00 +02:00
description = S ( " Set active Perlin noise parameters " ) ,
params = S ( " <offset> <scale> <seed> <spread_x> <spread_y> <spread_z> <octaves> <persistence> <lacunarity> [<flags>] " ) ,
2022-04-09 19:44:15 +02:00
func = function ( name , param )
2022-04-16 13:53:00 +02:00
local offset , scale , seed , sx , sy , sz , octaves , persistence , lacunarity , flags = string.match ( param , string.rep ( " ([0-9.-]+) " , 9 ) .. " ([a-zA-Z, ]+) " )
if not offset then
offset , scale , seed , sx , sy , sz , octaves , persistence , lacunarity = string.match ( param , string.rep ( " ([0-9.-]+) " , 8 ) .. " ([0-9.-]+) " )
if not offset then
return false
end
end
if not flags then
flags = " "
2022-04-09 19:44:15 +02:00
end
octaves = tonumber ( octaves )
offset = tonumber ( offset )
sx = tonumber ( sx )
sy = tonumber ( sy )
sz = tonumber ( sz )
persistence = tonumber ( persistence )
lacunarity = tonumber ( lacunarity )
seed = tonumber ( seed )
if not octaves or not offset or not sx or not sy or not sz or not persistence or not lacunarity or not seed then
2022-04-09 21:43:33 +02:00
return false , S ( " Invalid parameter type. " )
2022-04-09 19:44:15 +02:00
end
2022-04-16 16:19:58 +02:00
local noiseparams = {
2022-04-09 19:44:15 +02:00
octaves = octaves ,
offset = offset ,
scale = scale ,
spread = { x = sx , y = sy , z = sz } ,
persistence = persistence ,
lacunarity = lacunarity ,
seed = seed ,
2022-04-16 13:53:00 +02:00
flags = flags ,
2022-04-16 16:19:58 +02:00
}
noiseparams = fix_noiseparams ( noiseparams )
set_perlin_noise ( noiseparams )
2022-04-16 13:01:48 +02:00
loaded_areas = { }
2022-04-16 13:53:00 +02:00
return true , S ( " Active Perlin noise parameters set! " )
2022-04-09 19:44:15 +02:00
end ,
} )
minetest.register_chatcommand ( " perlin_generate " , {
privs = { server = true } ,
description = S ( " Generate Perlin noise " ) ,
2022-04-10 00:33:16 +02:00
params = S ( " <pos> <size> " ) ,
2022-04-09 19:44:15 +02:00
func = function ( name , param )
2022-04-10 00:33:16 +02:00
local x , y , z , size = string.match ( param , " ([0-9.-]+) ([0-9.-]+) ([0-9.-]+) ([0-9]+) " )
2022-04-09 20:39:15 +02:00
if not x then
2022-04-09 19:44:15 +02:00
return false
end
x = tonumber ( x )
y = tonumber ( y )
z = tonumber ( z )
2022-04-10 00:33:16 +02:00
size = tonumber ( size )
if not x or not y or not z or not size then
2022-04-09 19:44:15 +02:00
return false
end
2022-04-10 00:33:16 +02:00
if not x or not y or not z or not size then
2022-04-09 19:44:15 +02:00
return false , S ( " Invalid parameter type. " )
end
local pos = vector.new ( x , y , z )
minetest.chat_send_player ( name , S ( " Creating Perlin noise, please wait … " ) )
2022-04-10 00:33:16 +02:00
local msg = create_perlin ( pos , { dimensions = current_perlin.dimensions , size = size } )
2022-04-09 19:44:15 +02:00
if msg == false then
2022-04-16 04:52:29 +02:00
return false , S ( " No Perlin noise set. Set one first! " )
2022-04-09 19:44:15 +02:00
end
return true , msg
end ,
} )
2022-04-19 12:43:19 +02:00
local show_error_formspec = function ( player , message )
local form = [ [
formspec_version [ 4 ] size [ 10 , 3.5 ]
container [ 0.25 , 0.25 ]
box [ 0 , 0 ; 9.5 , 2 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
box [ 0 , 0 ; 9.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
label [ 0.25 , 0.2 ; ] ] .. F ( S ( " Error " ) ) .. [ [ ]
container [ 0.25 , 0.5 ]
textarea [ 0 , 0 ; 9 , 1.4 ; ; ] ] .. F ( message ) .. [ [ ; ]
container_end [ ]
container_end [ ]
button [ 1.5 , 2.5 ; 3 , 0.75 ; done ; ] ] .. F ( S ( " Return " ) ) .. [ [ ]
button [ 5.5 , 2.5 ; 3 , 0.75 ; analyze ; ] ] .. F ( S ( " Analyze now " ) ) .. [ [ ]
] ]
minetest.show_formspec ( player : get_player_name ( ) , " perlin_explorer:error " , form )
end
2022-04-17 00:01:32 +02:00
local show_histogram_loading_formspec = function ( player )
local form = [ [
2022-04-19 23:37:44 +02:00
formspec_version [ 4 ] size [ 11 , 2 ]
2022-04-17 00:01:32 +02:00
container [ 0.25 , 0.25 ]
2022-04-19 23:37:44 +02:00
box [ 0 , 0 ; 10.5 , 1.5 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
box [ 0 , 0 ; 10.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
2022-04-17 01:29:43 +02:00
label [ 0.25 , 0.2 ; ] ] .. F ( S ( " Statistical analysis in progress " ) ) .. [ [ ]
2022-04-17 00:01:32 +02:00
container [ 0.25 , 0.8 ]
label [ 0 , 0 ; ] ] .. F ( S ( " Collecting data, please wait … " ) ) .. [ [ ]
container_end [ ]
container_end [ ]
] ]
minetest.show_formspec ( player : get_player_name ( ) , " perlin_explorer:histogram_loading " , form )
end
2022-04-16 23:48:35 +02:00
local show_histogram_formspec = function ( player , stats )
local txt = " "
local maxh = 6.0
2022-04-19 13:30:22 +02:00
local histogram
2022-04-19 23:37:44 +02:00
histogram = " vertlabel[0.1,0.1; " .. F ( S ( " Relative frequency " ) ) .. " ] " ..
2022-04-19 13:30:22 +02:00
" label[1.1,8.15; " .. F ( S ( " Noise values " ) ) .. " ] " ..
" label[0,7.0; " .. F ( S ( " Max. " ) ) .. " \n " .. F ( S ( " Min. " ) ) .. " ] " ..
" tooltip[0,6.8;0.7,1; " .. F ( S ( " Upper (Max.) and lower (Min.) bounds of the noise value data bucketing " ) ) .. " ] " ..
" box[0.75,0;0.025,8.3;#FFFFFF80] " ..
2022-04-19 13:43:47 +02:00
" box[0,6.65;10.0,0.025;#FFFFFF80] " ..
2022-04-19 13:30:22 +02:00
" box[0,7.8;10.0,0.025;#FFFFFF80] "
2022-04-17 00:51:19 +02:00
local hstart = 1
-- Special case: If bucket sizes are equal, only show the last bucket
-- (can happen if scale=0)
if HISTOGRAM_BUCKETS > 1 and stats.histogram_points [ 1 ] == stats.histogram_points [ 2 ] then
hstart = HISTOGRAM_BUCKETS
end
-- Drawn histogram bars, tooltips and labels
for h = hstart , HISTOGRAM_BUCKETS do
2022-04-16 23:48:35 +02:00
local count = stats.histogram [ h ]
local ratio = ( stats.histogram [ h ] / stats.value_count )
local perc = ratio * 100
local perc_f = string.format ( " %.1f " , perc )
2022-04-17 00:34:29 +02:00
local x = h * 0.9
2022-04-16 23:48:35 +02:00
local height = maxh * ratio
local coords = x .. " , " .. maxh - height .. " ;0.8, " .. height
local box = " "
if count > 0 then
box = box .. " box[ " .. coords .. " ;#00FF00FF] "
box = box .. " tooltip[ " .. coords .. " ; " .. count .. " ] "
end
2022-04-17 00:34:29 +02:00
box = box .. " label[ " .. x .. " ,6.4; " .. F ( S ( " @1% " , perc_f ) ) .. " ] "
box = box .. " tooltip[ " .. x .. " ,6.2;0.9,0.3; " .. count .. " ] "
2022-04-16 23:48:35 +02:00
2022-04-17 00:34:29 +02:00
local min , max , min_v , max_v
2022-04-16 23:48:35 +02:00
if h <= 1 then
min = " "
else
2022-04-17 00:34:29 +02:00
min = F ( string.format ( " %.1f " , stats.histogram_points [ h - 1 ] ) )
2022-04-16 23:48:35 +02:00
end
if h >= HISTOGRAM_BUCKETS then
max = " "
else
2022-04-17 00:34:29 +02:00
max = F ( string.format ( " %.1f " , stats.histogram_points [ h ] ) )
2022-04-16 23:48:35 +02:00
end
2022-04-17 00:34:29 +02:00
box = box .. " label[ " .. x .. " ,7.0; " .. max .. " \n " .. min .. " ] "
local tt
if h == 1 then
tt = F ( S ( " value < @1 " , stats.histogram_points [ h ] ) )
elseif h == HISTOGRAM_BUCKETS then
tt = F ( S ( " @1 <= value " , stats.histogram_points [ h - 1 ] ) )
else
tt = F ( S ( " @1 <= value < @2 " , stats.histogram_points [ h - 1 ] , stats.histogram_points [ h ] ) )
end
box = box .. " tooltip[ " .. x .. " ,6.8;0.9,1; " .. tt .. " ] "
2022-04-16 23:48:35 +02:00
2022-04-19 12:52:11 +02:00
histogram = histogram .. box
2022-04-16 23:48:35 +02:00
end
2022-04-17 01:21:21 +02:00
local vmin , vmax
if current_perlin.dimensions == 2 then
vmin = S ( " (@1,@2) " , 0 , 0 )
vmax = S ( " (@1,@2) " , DEEP_ANALYSIS_SIZE_2D , DEEP_ANALYSIS_SIZE_2D )
else
vmin = S ( " (@1,@2,@3) " , 0 , 0 , 0 )
vmax = S ( " (@1,@2,@3) " , DEEP_ANALYSIS_SIZE_3D , DEEP_ANALYSIS_SIZE_3D , DEEP_ANALYSIS_SIZE_3D )
end
2022-04-19 13:34:49 +02:00
local labels = " textarea[0,0;10,2;;; " ..
F ( S ( " Values were picked between coordinates @1 and @2. " , vmin , vmax ) ) .. " \n " ..
F ( S ( " Values calculated: @1 " , stats.value_count ) ) .. " \n " ..
F ( S ( " Minimum calculated value: @1 " , stats.min ) ) .. " \n " ..
F ( S ( " Maximum calculated value: @1 " , stats.max ) ) .. " \n " ..
F ( S ( " Average calculated value: @1 " , stats.avg ) ) .. " ] \n "
2022-04-16 23:48:35 +02:00
local form = [ [
2022-04-19 13:30:22 +02:00
formspec_version [ 4 ] size [ 11 , 12.5 ]
2022-04-16 23:48:35 +02:00
container [ 0.25 , 0.25 ]
2022-04-19 13:30:22 +02:00
box [ 0 , 0 ; 10.5 , 2.5 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
2022-04-17 00:34:29 +02:00
box [ 0 , 0 ; 10.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
2022-04-19 13:30:22 +02:00
label [ 0.25 , 0.2 ; ] ] .. F ( S ( " Noise Value Statistics " ) ) .. [ [ ]
container [ 0.25 , 0.5 ]
2022-04-16 23:48:35 +02:00
] ] .. labels .. [ [
2022-04-19 12:52:11 +02:00
container_end [ ]
2022-04-19 13:30:22 +02:00
container [ 0 , 2.75 ]
box [ 0 , 0 ; 10.5 , 9.0 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
box [ 0 , 0 ; 10.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
label [ 0.25 , 0.2 ; ] ] .. F ( S ( " Noise Value Histogram " ) ) .. [ [ ]
container [ 0.25 , 0.6 ]
2022-04-19 12:52:11 +02:00
] ] .. histogram .. [ [
2022-04-16 23:48:35 +02:00
container_end [ ]
container_end [ ]
2022-04-19 13:30:22 +02:00
container_end [ ]
2022-04-16 23:48:35 +02:00
] ]
minetest.show_formspec ( player : get_player_name ( ) , " perlin_explorer:histogram " , form )
end
2022-04-16 06:20:08 +02:00
-- Analyzes the given noise params and shows the result in a pretty-printed formspec to player
local analyze_noiseparams_and_show_formspec = function ( player , noiseparams )
local min , max , waves = analyze_noiseparams ( noiseparams )
local print_waves = function ( waves_a )
local stringified_waves = { }
for w = 1 , # waves_a do
local strwave
local is_bad = false
if minetest.is_nan ( waves_a [ w ] ) or waves_a [ w ] == math.huge or waves_a [ w ] == - math.huge then
strwave = minetest.colorize ( " #FF0000FF " , waves_a [ w ] )
elseif waves_a [ w ] < 1 then
strwave = minetest.colorize ( " #FF0000FF " , " 0 " )
else
strwave = string.format ( " %.0f " , waves_a [ w ] )
end
table.insert ( stringified_waves , strwave )
2022-04-14 04:47:05 +02:00
end
2022-04-16 06:20:08 +02:00
return table.concat ( stringified_waves , " , " )
2022-04-14 04:47:05 +02:00
end
2022-04-16 06:20:08 +02:00
local form = [ [
formspec_version [ 4 ] size [ 10 , 5 ]
container [ 0.25 , 0.25 ]
box [ 0 , 0 ; 9.5 , 3.5 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
box [ 0 , 0 ; 9.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
label [ 0.25 , 0.2 ; ] ] .. F ( S ( " Noise Parameters Analysis " ) ) .. [ [ ]
2022-04-19 12:43:19 +02:00
label [ 0.25 , 0.75 ; ] ] .. F ( S ( " Minimum possible value: @1 " , min ) ) .. [ [ ]
label [ 0.25 , 1.25 ; ] ] .. F ( S ( " Maximum possible value: @1 " , max ) ) .. [ [ ]
2022-04-16 06:20:08 +02:00
2022-04-19 12:43:19 +02:00
label [ 0.25 , 1.75 ; ] ] .. F ( S ( " X wavelengths: @1 " , print_waves ( waves.x ) ) ) .. [ [ ]
label [ 0.25 , 2.25 ; ] ] .. F ( S ( " Y wavelengths: @1 " , print_waves ( waves.y ) ) ) .. [ [ ]
label [ 0.25 , 2.75 ; ] ] .. F ( S ( " Z wavelengths: @1 " , print_waves ( waves.z ) ) ) .. [ [ ]
2022-04-16 06:20:08 +02:00
2022-04-17 01:29:43 +02:00
button [ 3.5 , 3.75 ; 3 , 0.75 ; done ; ] ] .. F ( S ( " Done " ) ) .. [ [ ]
2022-04-16 06:20:08 +02:00
container_end [ ]
--]]
minetest.show_formspec ( player : get_player_name ( ) , " perlin_explorer:analyze " , form )
2022-04-14 04:47:05 +02:00
end
2022-04-16 15:46:37 +02:00
local show_noise_formspec = function ( player , noiseparams , profile_id )
2022-04-15 20:49:01 +02:00
local np
2022-04-15 21:00:37 +02:00
if noiseparams then
np = noiseparams
2022-04-15 20:49:01 +02:00
else
np = current_perlin.noiseparams
2022-04-15 21:00:37 +02:00
end
if not profile_id then
2022-04-15 20:49:01 +02:00
profile_id = 1
end
2022-04-15 06:55:11 +02:00
local offset = tostring ( np.offset or " " )
local scale = tostring ( np.scale or " " )
local seed = tostring ( np.seed or " " )
2022-04-10 01:45:19 +02:00
local sx , sy , sz = " " , " " , " "
2022-04-15 06:55:11 +02:00
if np.spread then
sx = tostring ( np.spread . x or " " )
sy = tostring ( np.spread . y or " " )
sz = tostring ( np.spread . z or " " )
2022-04-10 01:45:19 +02:00
end
2022-04-15 06:55:11 +02:00
local octaves = tostring ( np.octaves or " " )
local persistence = tostring ( np.persistence or " " )
local lacunarity = tostring ( np.lacunarity or " " )
2022-04-11 02:21:07 +02:00
local size = tostring ( current_perlin.size or " " )
local sidelen = tostring ( current_perlin.sidelen or " " )
2022-04-16 13:25:21 +02:00
local pos_x , pos_y , pos_z = " " , " " , " "
if current_perlin.pos then
pos_x = tostring ( current_perlin.pos . x or " " )
pos_y = tostring ( current_perlin.pos . y or " " )
pos_z = tostring ( current_perlin.pos . z or " " )
end
2022-04-11 02:21:07 +02:00
local value_min = tostring ( current_perlin.min or " " )
local value_max = tostring ( current_perlin.max or " " )
2022-04-15 06:55:11 +02:00
local flags = np.flags
2022-04-14 04:47:05 +02:00
local flags_table = parse_flags_string ( flags )
local eased = tostring ( flags_table.eased )
local absvalue = tostring ( flags_table.absvalue )
2022-04-15 05:55:17 +02:00
local noiseparams_list = { }
2022-04-16 18:08:49 +02:00
local counter = 1
2022-04-15 05:55:17 +02:00
for i = 1 , # np_profiles do
2022-04-16 18:08:49 +02:00
local npp = np_profiles [ i ]
local name = npp.name
if not name then
name = S ( " Profile @1 " , counter )
counter = counter + 1
end
table.insert ( noiseparams_list , F ( name ) )
2022-04-15 05:55:17 +02:00
end
local noiseparams_list_str = table.concat ( noiseparams_list , " , " )
2022-04-10 23:41:41 +02:00
local dimensions_index = ( current_perlin.dimensions or 2 ) - 1
2022-04-16 03:24:41 +02:00
local nodetype_index = ( current_perlin.nodetype )
local nodetypes_list = { }
for i = 1 , # nodetypes do
table.insert ( nodetypes_list , F ( nodetypes [ i ] [ 1 ] ) )
end
local nodetypes_list_str = table.concat ( nodetypes_list , " , " )
2022-04-15 20:49:01 +02:00
local delete_btn = " "
if # np_profiles > 1 then
2022-04-16 05:07:15 +02:00
delete_btn = " button[7.25,0;2.0,0.5;delete_np_profile; " .. F ( S ( " Delete " ) ) .. " ] "
2022-04-15 20:49:01 +02:00
end
2022-04-16 04:44:05 +02:00
local autogen_label
local create_btn = " "
2022-04-16 13:35:33 +02:00
local xyzsize = " "
2022-04-16 04:44:05 +02:00
if current_perlin.autogen then
autogen_label = S ( " Disable mapgen " )
else
autogen_label = S ( " Enable mapgen " )
create_btn = " button[3.5,0;3,1;create; " .. F ( S ( " Apply and create " ) ) .. " ] "
2022-04-16 13:35:33 +02:00
xyzsize = [ [
field [ 0.25 , 1.95 ; 2 , 0.75 ; pos_x ; ] ] .. F ( S ( " X " ) ) .. [[;]] .. pos_x .. [ [ ]
field [ 2.35 , 1.95 ; 2 , 0.75 ; pos_y ; ] ] .. F ( S ( " Y " ) ) .. [[;]] .. pos_y .. [ [ ]
field [ 4.45 , 1.95 ; 2 , 0.75 ; pos_z ; ] ] .. F ( S ( " Z " ) ) .. [[;]] .. pos_z .. [ [ ]
field [ 6.55 , 1.95 ; 2 , 0.75 ; size ; ] ] .. F ( S ( " Size " ) ) .. [[;]] .. size .. [ [ ]
field_close_on_enter [ pos_x ; false ]
field_close_on_enter [ pos_y ; false ]
field_close_on_enter [ pos_z ; false ]
field_close_on_enter [ value_min ; false ]
field_close_on_enter [ value_max ; false ]
] ]
2022-04-16 04:44:05 +02:00
end
2022-04-10 01:45:19 +02:00
local form = [ [
2022-04-16 00:18:50 +02:00
formspec_version [ 4 ] size [ 10 , 12.5 ]
2022-04-15 03:17:19 +02:00
container [ 0.25 , 0.25 ]
2022-04-15 05:55:17 +02:00
box [ 0 , 0 ; 9.5 , 5.5 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
2022-04-16 00:25:00 +02:00
box [ 0 , 0 ; 9.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
label [ 0.15 , 0.2 ; ] ] .. F ( S ( " Noise parameters " ) ) .. [ [ ]
2022-04-16 00:36:34 +02:00
container [ 0.0 , 0.5 ]
2022-04-16 18:08:49 +02:00
dropdown [ 0.25 , 0 ; 3 , 0.5 ; np_profiles ; ] ] .. noiseparams_list_str .. [[;]] .. profile_id .. [ [ ; true ]
2022-04-16 00:36:34 +02:00
button [ 3.25 , 0 ; 2.0 , 0.5 ; add_np_profile ; ] ] .. F ( S ( " Add " ) ) .. [ [ ]
button [ 5.25 , 0 ; 2.0 , 0.5 ; load_np_profile ; ] ] .. F ( S ( " Load " ) ) .. [ [ ]
2022-04-15 20:49:01 +02:00
] ] .. delete_btn .. [ [
2022-04-16 00:36:34 +02:00
container_end [ ]
container [ 0.0 , 1.5 ]
field [ 0.25 , 0 ; 2 , 0.75 ; offset ; ] ] .. F ( S ( " Offset " ) ) .. [[;]] .. offset .. [ [ ]
field [ 3.25 , 0 ; 2 , 0.75 ; scale ; ] ] .. F ( S ( " Scale " ) ) .. [[;]] .. scale .. [ [ ]
field [ 6.25 , 0 ; 2 , 0.75 ; seed ; ] ] .. F ( S ( " Seed " ) ) .. [[;]] .. seed .. [ [ ]
image_button [ 8.35 , 0.0 ; 0.75 , 0.75 ; perlin_explorer_seeder.png ; set_random_seed ; ]
field [ 0.25 , 1.2 ; 2 , 0.75 ; spread_x ; ] ] .. F ( S ( " X Spread " ) ) .. [[;]] .. sx .. [ [ ]
field [ 3.25 , 1.2 ; 2 , 0.75 ; spread_y ; ] ] .. F ( S ( " Y Spread " ) ) .. [[;]] .. sy .. [ [ ]
field [ 6.25 , 1.2 ; 2 , 0.75 ; spread_z ; ] ] .. F ( S ( " Z Spread " ) ) .. [[;]] .. sz .. [ [ ]
field [ 0.25 , 2.4 ; 2 , 0.75 ; octaves ; ] ] .. F ( S ( " Octaves " ) ) .. [[;]] .. octaves .. [ [ ]
field [ 3.25 , 2.4 ; 2 , 0.75 ; persistence ; ] ] .. F ( S ( " Persistence " ) ) .. [[;]] .. persistence .. [ [ ]
field [ 6.25 , 2.4 ; 2 , 0.75 ; lacunarity ; ] ] .. F ( S ( " Lacunarity " ) ) .. [[;]] .. lacunarity .. [ [ ]
checkbox [ 0.25 , 3.55 ; eased ; ] ] .. F ( S ( " eased " ) ) .. [[;]] .. eased .. [ [ ]
checkbox [ 3.25 , 3.55 ; absvalue ; ] ] .. F ( S ( " absvalue " ) ) .. [[;]] .. absvalue .. [ [ ]
2022-04-16 06:20:08 +02:00
button [ 6.25 , 3.35 ; 2.0 , 0.5 ; analyze ; ] ] .. F ( S ( " Analyze " ) ) .. [ [ ]
2022-04-16 00:36:34 +02:00
container_end [ ]
2022-04-15 22:18:53 +02:00
2022-04-10 01:45:19 +02:00
field_close_on_enter [ offset ; false ]
field_close_on_enter [ scale ; false ]
field_close_on_enter [ seed ; false ]
field_close_on_enter [ spread_x ; false ]
field_close_on_enter [ spread_y ; false ]
field_close_on_enter [ spread_z ; false ]
field_close_on_enter [ octaves ; false ]
field_close_on_enter [ persistence ; false ]
field_close_on_enter [ lacunarity ; false ]
2022-04-11 02:21:07 +02:00
field_close_on_enter [ sidelen ; false ]
2022-04-10 01:45:19 +02:00
2022-04-16 00:18:50 +02:00
tooltip [ set_random_seed ; ] ] .. F ( S ( " Random seed " ) ) .. [ [ ]
container_end [ ]
container [ 0.25 , 6.0 ]
2022-04-16 00:25:00 +02:00
box [ 0 , 0 ; 9.5 , 1.6 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
box [ 0 , 0 ; 9.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
label [ 0.15 , 0.2 ; ] ] .. F ( S ( " Noise options " ) ) .. [ [ ]
dropdown [ 0.25 , 0.7 ; 1 , 0.75 ; dimensions ; ] ] .. F ( S ( " 2D " ) ) .. [[,]] .. F ( S ( " 3D " ) ) .. [[;]] .. dimensions_index .. [ [ ; true ]
field [ 2.25 , 0.7 ; 2 , 0.75 ; sidelen ; ] ] .. F ( S ( " Pixelization " ) ) .. [[;]] .. sidelen .. [ [ ]
2022-04-17 01:29:43 +02:00
button [ 6.25 , 0.7 ; 2.0 , 0.6 ; deep_analyze ; ] ] .. F ( S ( " Statistics " ) ) .. [ [ ]
2022-04-16 00:18:50 +02:00
tooltip [ sidelen ; ] ] .. F ( S ( " If higher than 1, Perlin values will be repeated along all axes every x nodes, for a ‘ pixelized’ effect. " ) ) .. [ [ ]
container_end [ ]
2022-04-16 00:25:00 +02:00
container [ 0.25 , 7.85 ]
2022-04-16 00:18:50 +02:00
box [ 0 , 0 ; 9.5 , 2.9 ; ] ] .. FORMSPEC_BOX_COLOR .. [ [ ]
2022-04-16 00:25:00 +02:00
box [ 0 , 0 ; 9.5 , 0.4 ; ] ] .. FORMSPEC_HEADER_COLOR .. [ [ ]
2022-04-16 00:28:27 +02:00
label [ 0.15 , 0.2 ; ] ] .. F ( S ( " Node generation " ) ) .. [ [ ]
2022-04-16 00:18:50 +02:00
field [ 0.25 , 0.75 ; 2 , 0.75 ; value_min ; ] ] .. F ( S ( " Min. color at " ) ) .. [[;]] .. value_min .. [ [ ]
field [ 2.35 , 0.75 ; 2 , 0.75 ; value_max ; ] ] .. F ( S ( " Max. color at " ) ) .. [[;]] .. value_max .. [ [ ]
2022-04-16 03:24:41 +02:00
dropdown [ 6.55 , 0.75 ; 2 , 0.75 ; nodetype ; ] ] .. nodetypes_list_str .. [[;]] .. nodetype_index .. [ [ ; true ]
2022-04-16 13:35:33 +02:00
] ] .. xyzsize .. [ [
2022-04-16 00:18:50 +02:00
tooltip [ value_min ; ] ] .. F ( S ( " The Perlin value at which the node color gradient begins. Must be lower than 0. " ) ) .. [ [ ]
tooltip [ value_max ; ] ] .. F ( S ( " The Perlin value at which the node color gradient ends. Must be higher than 0. " ) ) .. [ [ ]
container_end [ ]
2022-04-16 00:25:00 +02:00
container [ 0 , 10.95 ]
2022-04-15 03:17:19 +02:00
button [ 0.5 , 0 ; 3 , 1 ; apply ; ] ] .. F ( S ( " Apply " ) ) .. [ [ ]
2022-04-16 04:44:05 +02:00
] ] .. create_btn .. [ [
button [ 6.5 , 0 ; 3 , 1 ; toggle_autogen ; ] ] .. F ( autogen_label ) .. [ [ ]
2022-04-15 03:17:19 +02:00
container_end [ ]
2022-04-10 01:45:19 +02:00
] ]
minetest.show_formspec ( player : get_player_name ( ) , " perlin_explorer:creator " , form )
end
2022-04-16 16:19:58 +02:00
-- Fix some errors in the noiseparams
local fix_noiseparams = function ( noiseparams )
noiseparams.octaves = math.floor ( math.max ( 1 , noiseparams.octaves ) )
noiseparams.lacunarity = math.max ( 1.0 , noiseparams.lacunarity )
noiseparams.spread . x = math.floor ( math.max ( 1 , noiseparams.spread . x ) )
noiseparams.spread . y = math.floor ( math.max ( 1 , noiseparams.spread . y ) )
noiseparams.spread . z = math.floor ( math.max ( 1 , noiseparams.spread . z ) )
return noiseparams
end
2022-04-10 01:45:19 +02:00
minetest.register_on_player_receive_fields ( function ( player , formname , fields )
2022-04-17 01:29:43 +02:00
-- Require 'server' priv
local privs = minetest.get_player_privs ( player : get_player_name ( ) )
if not privs.server then
return
end
2022-04-16 23:48:35 +02:00
-- Analysis window
2022-04-19 12:43:19 +02:00
if formname == " perlin_explorer:analyze " or formname == " perlin_explorer:error " then
2022-04-16 23:48:35 +02:00
if fields.done then
local noiseparams = formspec_states [ player : get_player_name ( ) ] . noiseparams
show_noise_formspec ( player , noiseparams )
2022-04-19 12:43:19 +02:00
elseif fields.analyze then
local noiseparams = formspec_states [ player : get_player_name ( ) ] . noiseparams
analyze_noiseparams_and_show_formspec ( player , noiseparams )
2022-04-16 23:48:35 +02:00
end
2022-04-19 12:43:19 +02:00
return
2022-04-16 15:46:37 +02:00
end
2022-04-16 23:48:35 +02:00
-- Creator window
2022-04-10 01:45:19 +02:00
if formname ~= " perlin_explorer:creator " then
return
end
2022-04-17 01:29:43 +02:00
-- Start deep analysis
if fields.deep_analyze then
local pos = vector.zero ( )
local size
if current_perlin.dimensions == 2 then
size = DEEP_ANALYSIS_SIZE_2D
else -- 3 dimensions
size = DEEP_ANALYSIS_SIZE_3D
end
-- Show a loading formspec
show_histogram_loading_formspec ( player )
-- This takes long
local _ , stats = create_perlin ( pos , { dimensions = current_perlin.dimensions , size = size , set_nodes = false } )
if stats then
-- Update the formspec to show the result
show_histogram_formspec ( player , stats )
else
minetest.log ( " error " , " [perlin_explorer] Error while creating stats from Perlin noise! " )
end
2022-04-10 01:46:30 +02:00
return
end
2022-04-14 04:47:05 +02:00
-- Handle checkboxes
local name = player : get_player_name ( )
2022-04-15 06:55:11 +02:00
local flags_touched = false
2022-04-14 04:47:05 +02:00
if fields.eased == " true " then
formspec_states [ name ] . eased = true
2022-04-15 21:45:32 +02:00
return
2022-04-14 04:47:05 +02:00
elseif fields.eased == " false " then
formspec_states [ name ] . eased = false
2022-04-15 21:45:32 +02:00
return
2022-04-14 04:47:05 +02:00
end
if fields.absvalue == " true " then
formspec_states [ name ] . absvalue = true
2022-04-15 21:45:32 +02:00
return
2022-04-14 04:47:05 +02:00
elseif fields.absvalue == " false " then
formspec_states [ name ] . absvalue = false
2022-04-15 21:45:32 +02:00
return
2022-04-14 04:47:05 +02:00
end
2022-04-15 05:55:17 +02:00
-- Deleting a profile does not require any other field
if fields.delete_np_profile then
if # np_profiles <= 1 then
return
end
2022-04-15 21:00:37 +02:00
local profile_to_delete = tonumber ( fields.np_profiles )
2022-04-16 18:08:49 +02:00
if np_profiles [ profile_to_delete ] . can_delete == false then
return
end
2022-04-15 21:00:37 +02:00
table.remove ( np_profiles , profile_to_delete )
local new_id = math.max ( 1 , profile_to_delete - 1 )
2022-04-16 15:46:37 +02:00
show_noise_formspec ( player , default_noiseparams , new_id )
2022-04-15 05:55:17 +02:00
return
end
2022-04-14 04:47:05 +02:00
-- Handle other fields
2022-04-16 16:38:37 +02:00
local enter_pressed = fields.key_enter_field ~= nil
2022-04-16 04:44:05 +02:00
local do_apply = fields.apply ~= nil or fields.toggle_autogen ~= nil
2022-04-16 16:38:37 +02:00
local do_create = fields.create ~= nil
if current_perlin.autogen then
do_apply = do_apply or enter_pressed
else
do_create = do_create or enter_pressed
end
2022-04-16 06:20:08 +02:00
local do_analyze = fields.analyze ~= nil
if ( do_create or do_apply or do_analyze or fields.add_np_profile or fields.np_profiles ) then
2022-04-10 01:45:19 +02:00
if fields.offset and fields.scale and fields.seed and fields.spread_x and fields.spread_y and fields.spread_z and fields.octaves and fields.persistence and fields.lacunarity then
2022-04-15 05:55:17 +02:00
2022-04-10 01:45:19 +02:00
local offset = tonumber ( fields.offset )
local scale = tonumber ( fields.scale )
local seed = tonumber ( fields.seed )
local sx = tonumber ( fields.spread_x )
local sy = tonumber ( fields.spread_y )
local sz = tonumber ( fields.spread_z )
2022-04-10 03:33:22 +02:00
if not sx or not sy or not sz then
return
end
2022-04-10 01:45:19 +02:00
local spread = vector.new ( sx , sy , sz )
local octaves = tonumber ( fields.octaves )
local persistence = tonumber ( fields.persistence )
local lacunarity = tonumber ( fields.lacunarity )
2022-04-10 23:41:41 +02:00
local dimensions = tonumber ( fields.dimensions )
2022-04-11 02:21:07 +02:00
local sidelen = tonumber ( fields.sidelen )
local px = tonumber ( fields.pos_x )
local py = tonumber ( fields.pos_y )
local pz = tonumber ( fields.pos_z )
local size = tonumber ( fields.size )
local value_min = tonumber ( fields.value_min )
local value_max = tonumber ( fields.value_max )
2022-04-16 03:24:41 +02:00
local nodetype = tonumber ( fields.nodetype )
2022-04-15 05:55:17 +02:00
if ( offset and scale and spread and octaves and persistence ) then
2022-04-14 04:47:05 +02:00
local eased = formspec_states [ name ] . eased
local absvalue = formspec_states [ name ] . absvalue
2022-04-15 05:55:17 +02:00
local noiseparams = {
2022-04-10 01:45:19 +02:00
offset = offset ,
scale = scale ,
seed = seed ,
spread = spread ,
octaves = octaves ,
persistence = persistence ,
lacunarity = lacunarity ,
2022-04-14 04:47:05 +02:00
flags = build_flags_string ( eased , absvalue ) ,
2022-04-15 05:55:17 +02:00
}
2022-04-16 16:19:58 +02:00
noiseparams = fix_noiseparams ( noiseparams )
2022-04-16 06:20:08 +02:00
-- Open analyze window
if do_analyze then
2022-04-16 15:46:37 +02:00
formspec_states [ player : get_player_name ( ) ] . noiseparams = noiseparams
2022-04-16 06:20:08 +02:00
analyze_noiseparams_and_show_formspec ( player , noiseparams )
return
2022-04-15 05:55:17 +02:00
-- Change NP profile selection
2022-04-16 06:20:08 +02:00
elseif fields.load_np_profile and fields.np_profiles then
2022-04-15 20:49:01 +02:00
local profile = tonumber ( fields.np_profiles )
2022-04-16 18:08:49 +02:00
local loaded_np = np_profiles [ profile ] . noiseparams
2022-04-15 20:49:01 +02:00
-- Load new profile
2022-04-16 15:46:37 +02:00
show_noise_formspec ( player , loaded_np , profile )
2022-04-15 20:49:01 +02:00
minetest.log ( " action " , " [perlin_explorer] Loaded perlin noise profile " .. profile )
return
2022-04-15 20:53:11 +02:00
-- Add new profile and save current noiseparams to it
2022-04-15 20:49:01 +02:00
elseif fields.add_np_profile then
2022-04-15 05:55:17 +02:00
table.insert ( np_profiles , noiseparams )
2022-04-15 20:49:01 +02:00
local new_profile = # np_profiles
minetest.log ( " action " , " [perlin_explorer] Perlin noise profile " .. new_profile .. " added! " )
2022-04-16 15:46:37 +02:00
show_noise_formspec ( player , noiseparams , new_profile )
2022-04-15 05:55:17 +02:00
return
2022-04-15 22:18:53 +02:00
elseif fields.set_random_seed then
-- Randomize seed
local profile = tonumber ( fields.np_profiles )
noiseparams.seed = math.random ( 0 , 2 ^ 32 - 1 )
2022-04-16 15:46:37 +02:00
show_noise_formspec ( player , noiseparams , profile )
2022-04-15 22:18:53 +02:00
return
2022-04-15 05:55:17 +02:00
end
2022-04-15 22:18:53 +02:00
2022-04-16 13:35:33 +02:00
if not ( dimensions and sidelen and value_min and value_max and nodetype ) then
2022-04-15 05:55:17 +02:00
return
end
-- Convert dropdown index to actual dimensions number
dimensions = dimensions + 1
-- Spread is used differently in 2D
if dimensions == 2 then
spread.y = spread.z
end
2022-04-19 12:43:19 +02:00
local _ , _ , _ , badwaves = analyze_noiseparams ( noiseparams )
if badwaves then
formspec_states [ player : get_player_name ( ) ] . noiseparams = noiseparams
show_error_formspec ( player , S ( " Bad noise parameters given. At least one of the resulting wave lengths got below 1, which is not allowed. Decrease the octaves or lacunarity to reach valid wave lengths. Analyze the noise parameters to see the current wave lengths. " ) )
return
end
2022-04-15 05:55:17 +02:00
set_perlin_noise ( noiseparams )
minetest.log ( " action " , " [perlin_explorer] Perlin noise set! " )
2022-04-11 02:21:07 +02:00
current_perlin.dimensions = dimensions
current_perlin.sidelen = sidelen
current_perlin.min = value_min
current_perlin.max = value_max
2022-04-16 03:24:41 +02:00
current_perlin.nodetype = nodetype
2022-04-16 13:35:33 +02:00
if fields.toggle_autogen then
current_perlin.autogen = not current_perlin.autogen
if current_perlin.autogen then
loaded_areas = { }
end
local profile = tonumber ( fields.np_profiles )
2022-04-16 15:46:37 +02:00
show_noise_formspec ( player , noiseparams , profile )
2022-04-16 13:35:33 +02:00
minetest.log ( " action " , " [perlin_explorer] Autogen state is now: " .. tostring ( current_perlin.autogen ) )
elseif do_create then
if not px or not py or not pz or not size then
2022-04-15 05:55:17 +02:00
return
end
2022-04-16 16:35:44 +02:00
if current_perlin.autogen then
loaded_areas = { }
end
2022-04-16 13:35:33 +02:00
current_perlin.size = size
2022-04-15 05:55:17 +02:00
local place_pos = vector.new ( px , py , pz )
2022-04-13 22:35:29 +02:00
local msg = S ( " Creating Perlin noise, please wait … " )
2022-04-14 04:47:05 +02:00
minetest.chat_send_player ( name , msg )
2022-04-13 22:35:29 +02:00
msg = create_perlin ( place_pos , { dimensions = dimensions , size = size } )
2022-04-11 02:21:07 +02:00
if msg then
2022-04-14 04:47:05 +02:00
minetest.chat_send_player ( name , msg )
2022-04-11 02:21:07 +02:00
elseif msg == false then
2022-04-10 01:45:19 +02:00
minetest.log ( " error " , " [perlin_explorer] Error generating Perlin noise nodes! " )
end
2022-04-16 16:35:44 +02:00
elseif do_apply and current_perlin.autogen then
loaded_areas = { }
2022-04-10 01:45:19 +02:00
end
end
end
end
end )
minetest.register_tool ( " perlin_explorer:creator " , {
description = S ( " Perlin Noise Creator " ) ,
_tt_help = S ( " Punch to open the Perlin noise creation menu " ) ,
inventory_image = " perlin_explorer_creator.png " ,
wield_image = " perlin_explorer_creator.png " ,
groups = { disable_repair = 1 } ,
on_use = function ( itemstack , user , pointed_thing )
if not user then
return
end
local privs = minetest.get_player_privs ( user : get_player_name ( ) )
if not privs.server then
2022-04-10 01:54:20 +02:00
minetest.chat_send_player ( user : get_player_name ( ) , S ( " Insufficient privileges! You need the @1 privilege to use this tool. " , " server " ) )
return
2022-04-10 01:45:19 +02:00
end
2022-04-16 15:46:37 +02:00
show_noise_formspec ( user )
2022-04-10 01:45:19 +02:00
end ,
} )
2022-04-14 03:07:42 +02:00
local timer = 0
minetest.register_globalstep ( function ( dtime )
timer = timer + dtime
2022-04-15 22:30:02 +02:00
if timer < AUTOBUILD_UPDATE_TIME then
2022-04-14 03:07:42 +02:00
return
end
timer = 0
2022-04-16 04:44:05 +02:00
if current_perlin.noise and current_perlin.autogen then
2022-04-14 03:07:42 +02:00
local player = minetest.get_player_by_name ( " singleplayer " )
if not player then
return
end
2022-04-16 15:31:35 +02:00
local build = function ( pos , pos_hash , player_name )
2022-04-15 22:36:25 +02:00
if not pos or not pos.x or not pos.y or not pos.z then
minetest.log ( " error " , " [perlin_explorer] build(): Invalid pos! " )
return
end
2022-04-16 15:31:35 +02:00
if not pos_hash then
minetest.log ( " error " , " [perlin_explorer] build(): Invalid pos_hash! " )
return
end
if not loaded_areas [ pos_hash ] then
2022-04-16 04:52:29 +02:00
create_perlin ( pos , {
2022-04-14 03:07:42 +02:00
dimensions = current_perlin.dimensions ,
size = AUTOBUILD_SIZE ,
} )
2022-04-16 15:31:35 +02:00
loaded_areas [ pos_hash ] = true
2022-04-14 03:07:42 +02:00
end
end
2022-04-09 19:44:15 +02:00
2022-04-14 03:07:42 +02:00
local pos = vector.round ( player : get_pos ( ) )
pos = sidelen_pos ( pos , AUTOBUILD_SIZE )
2022-04-16 01:33:59 +02:00
local neighbors = { vector.new ( 0 , 0 , 0 ) }
local c = AUTOBUILD_CHUNKDIST
local cc = c
if current_perlin.dimensions == 2 then
cc = 0
end
for cx =- c , c do
for cy =- cc , cc do
for cz =- c , c do
table.insert ( neighbors , vector.new ( cx , cy , cz ) )
end
end
end
2022-04-16 15:36:54 +02:00
local noisechunks = { }
2022-04-14 03:07:42 +02:00
for n = 1 , # neighbors do
2022-04-16 01:33:59 +02:00
local offset = vector.multiply ( neighbors [ n ] , AUTOBUILD_SIZE )
local npos = vector.add ( pos , offset )
2022-04-17 12:15:51 +02:00
-- Check of position is still within the valid map
local node = minetest.get_node_or_nil ( npos )
if node ~= nil then
local hash = minetest.hash_node_position ( npos )
if not loaded_areas [ hash ] then
table.insert ( noisechunks , { npos , hash } )
end
2022-04-16 15:31:35 +02:00
end
end
2022-04-16 15:36:54 +02:00
if # noisechunks > 0 then
minetest.log ( " verbose " , " [perlin_explorer] Started building " .. # noisechunks .. " noisechunk(s) " )
2022-04-16 15:31:35 +02:00
end
2022-04-16 15:36:54 +02:00
for c = 1 , # noisechunks do
local npos = noisechunks [ c ] [ 1 ]
local nhash = noisechunks [ c ] [ 2 ]
2022-04-16 15:31:35 +02:00
build ( npos , nhash , player : get_player_name ( ) )
end
2022-04-16 15:36:54 +02:00
if # noisechunks > 0 then
minetest.log ( " verbose " , " [perlin_explorer] Done building " .. # noisechunks .. " noisechunk(s) " )
2022-04-14 03:07:42 +02:00
end
end
end )
2022-04-14 04:47:05 +02:00
minetest.register_on_joinplayer ( function ( player )
local name = player : get_player_name ( )
formspec_states [ name ] = {
eased = false ,
}
end )
minetest.register_on_leaveplayer ( function ( player )
local name = player : get_player_name ( )
formspec_states [ name ] = nil
end )