347 lines
14 KiB
Lua
347 lines
14 KiB
Lua
local os_execute = ...
|
|
|
|
local vector, round = modlib.vector, modlib.math.round
|
|
|
|
local function format_pos(v)
|
|
return table.concat(vector.apply(v, function(c) return round(c, 100) end), ", ")
|
|
end
|
|
|
|
local defaults = config.defaults
|
|
|
|
minetest.register_privilege("protection_bypass", {
|
|
description = "Can bypass protection",
|
|
give_to_admin = true,
|
|
give_to_singleplayer = true
|
|
})
|
|
|
|
minetest.register_privilege("voxelizer", {
|
|
description = "Can use the voxelizer mod",
|
|
give_to_admin = true,
|
|
give_to_singleplayer = true
|
|
})
|
|
|
|
cmdlib.register_chatcommand("vox", {
|
|
description = "Voxelizer",
|
|
privs = {voxelizer = true},
|
|
func = function(sendername, params)
|
|
return false, "Use the commands of the voxelizer mod using /vox <command> {params} - for a list of commands do /help vox."
|
|
end
|
|
})
|
|
|
|
function get_setting_int(playername, settingname)
|
|
local setting = minetest.get_player_by_name(playername):get_meta():get_int("voxelizer_"..settingname)
|
|
return setting ~= 0 and setting
|
|
end
|
|
|
|
function set_setting_int(playername, settingname, value)
|
|
return minetest.get_player_by_name(playername):get_meta():set_int("voxelizer_"..settingname, value)
|
|
end
|
|
|
|
function get_setting_float(playername, settingname)
|
|
local setting = minetest.get_player_by_name(playername):get_meta():get_float("voxelizer_"..settingname)
|
|
return setting ~= 0 and setting
|
|
end
|
|
|
|
function set_setting_float(playername, settingname, value)
|
|
return minetest.get_player_by_name(playername):get_meta():set_float("voxelizer_"..settingname, value)
|
|
end
|
|
|
|
function get_setting(playername, settingname)
|
|
local setting = minetest.get_player_by_name(playername):get_meta():get_string("voxelizer_"..settingname)
|
|
return setting ~= "" and setting
|
|
end
|
|
|
|
function set_setting(playername, settingname, value)
|
|
return minetest.get_player_by_name(playername):get_meta():set_string("voxelizer_"..settingname, value)
|
|
end
|
|
|
|
function register_setting_command(commandname, values, settingname)
|
|
settingname = settingname or commandname
|
|
local root = modlib.number.round(math.sqrt(#values))
|
|
local display_vals = {}
|
|
for index, val in ipairs(values) do
|
|
table.insert(display_vals, index..". "..val)
|
|
end
|
|
cmdlib.register_chatcommand("vox "..commandname, {
|
|
description = "Get and list or set player-specific setting "..settingname,
|
|
params = "[index]",
|
|
func = function(sendername, params)
|
|
if params.index then
|
|
params.index = tonumber(params.index)
|
|
if not params.index or params.index < 1 or params.index > #values or params.index % 1 > 0 then
|
|
return false, "Index out of range : Needs to be an integer between 1 and "..#values
|
|
end
|
|
set_setting_int(sendername, settingname, params.index)
|
|
return true, string.format('Setting "%s" was set to %d - "%s"', settingname, params.index, values[params.index])
|
|
end
|
|
local display_vals = {unpack(display_vals)}
|
|
local setting = get_setting_int(sendername, settingname, params.index) or defaults[settingname]
|
|
if display_vals[setting] then
|
|
display_vals[setting] = minetest.get_color_escape_sequence("#FFFF66")..display_vals[setting].." (active)"..minetest.get_color_escape_sequence("#FFFFFF")
|
|
end
|
|
local options = {}
|
|
for i=1, #values, root do
|
|
local row = {unpack(display_vals, i, i+root-1)}
|
|
table.insert(options, table.concat(row, ", "))
|
|
end
|
|
return nil, table.concat(options, "\n")
|
|
end
|
|
})
|
|
end
|
|
|
|
function register_file_command(commandname, settingname)
|
|
settingname = settingname or commandname
|
|
cmdlib.register_chatcommand("vox "..commandname, {
|
|
description = "Get or set player-specific file "..settingname,
|
|
params = "[filename]",
|
|
func = function(sendername, params)
|
|
if params.filename then
|
|
local path = get_media(params.filename)
|
|
if not modlib.file.exists(path) then return false, "File doesn't exist" end
|
|
set_setting(sendername, settingname, params.filename)
|
|
return true, string.format('File "%s" was set to "%s"', settingname, params.filename)
|
|
end
|
|
local value = get_setting(sendername, settingname)
|
|
if value then
|
|
return true, string.format('File "%s" is currently set to "%s"', settingname, value)
|
|
end
|
|
return true, string.format('File "%s" is currently not set, using default', settingname)
|
|
end
|
|
})
|
|
end
|
|
|
|
local algorithm_names = {}
|
|
for index, matrix in ipairs(dithering_matrices) do
|
|
algorithm_names[index] = matrix.name
|
|
end
|
|
table.insert(algorithm_names, "No preprocessing")
|
|
|
|
register_setting_command("dithering", algorithm_names)
|
|
|
|
local color_choosing = {"best", "average"}
|
|
register_setting_command("color_choosing", {"Best", "Average"})
|
|
|
|
local merge_mode = {"overwrite", "add", "intersection"}
|
|
register_setting_command("placement", {"Overwrite", "Add", "Intersection"})
|
|
|
|
local filtering = {"nearest", "bilinear"}
|
|
register_setting_command("filtering", {"Nearest neighbor", "Bilinear"})
|
|
|
|
register_file_command("model")
|
|
register_file_command("texture")
|
|
register_file_command("nodemap")
|
|
|
|
function register_bool_setting_command(name)
|
|
cmdlib.register_chatcommand("vox "..name, {
|
|
description = "Check whether "..name.." is enabled",
|
|
func = function(sendername)
|
|
local enabled = get_setting_int(sendername, name) == 1
|
|
return true, string.format("Setting %s is %s", name, (enabled and "enabled") or "disabled")
|
|
end
|
|
})
|
|
|
|
cmdlib.register_chatcommand("vox "..name.." enable", {
|
|
description = "Enable "..name,
|
|
privs = {protection_bypass = true},
|
|
func = function(sendername)
|
|
set_setting_int(sendername, name, 1)
|
|
return true, name.." was enabled."
|
|
end
|
|
})
|
|
|
|
cmdlib.register_chatcommand("vox "..name.." disable", {
|
|
description = "Disable "..name,
|
|
privs = {protection_bypass = true},
|
|
func = function(sendername)
|
|
set_setting_int(sendername, name, 2)
|
|
return true, name.." was disabled."
|
|
end
|
|
})
|
|
end
|
|
|
|
register_bool_setting_command("protection_bypass")
|
|
|
|
register_bool_setting_command("alpha_weighing")
|
|
|
|
local max_precision = config.max_precision
|
|
cmdlib.register_chatcommand("vox precision", {
|
|
description = "Set/get current precision",
|
|
params = "[number]",
|
|
func = function(sendername, params)
|
|
if params.number then
|
|
params.number = tonumber(params.number)
|
|
if params.number % 1 ~= 0 or params.number < 1 or params.number > max_precision then
|
|
return false, "Number needs to be an integer between 1 and "..max_precision
|
|
end
|
|
set_setting_int(sendername, "precision", params.number)
|
|
return true, "Precision was set to "..params.number
|
|
end
|
|
return true, "Precision currently is "..(get_setting_int(sendername, "precision") or defaults.precision)
|
|
end
|
|
})
|
|
|
|
cmdlib.register_chatcommand("vox min_density", {
|
|
description = "Set/get minimum density",
|
|
params = "[number]",
|
|
func = function(sendername, params)
|
|
if params.number then
|
|
params.number = tonumber(params.number)
|
|
if params.number < 0 or params.number > 1 then
|
|
return false, "Number needs to be a floating-point number between 0 and 1"
|
|
end
|
|
set_setting_float(sendername, "min_density", params.number)
|
|
return true, "Precision was set to "..params.number
|
|
end
|
|
return true, "Precision currently is "..(get_setting_int(sendername, "min_density") or defaults.min_density)
|
|
end
|
|
})
|
|
|
|
local function substitute_coords(pos, playername)
|
|
local player_pos = minetest.get_player_by_name(playername):get_pos()
|
|
local x, y, z = unpack(pos)
|
|
local pos = {x or player_pos.x, y or player_pos.y, z or player_pos.z}
|
|
return pos
|
|
end
|
|
|
|
local function place(sendername, additional)
|
|
local function setting(name) return get_setting(sendername, name) end
|
|
local function setting_int(name) return get_setting_int(sendername, name) end
|
|
local function setting_float(name) return get_setting_float(sendername, name) end
|
|
local model, texture, nodemap = setting("model"), setting("texture"), setting("nodemap")
|
|
local params = {
|
|
playername = sendername,
|
|
model = (model and get_media(model)) or defaults.model,
|
|
texture = (texture and get_media(texture)) or defaults.texture,
|
|
nodemap = (nodemap and get_media(nodemap)) or defaults.nodemap,
|
|
min_density = setting_float("min_density") or defaults.min_density,
|
|
precision = setting_int("precision") or defaults.precision,
|
|
dithering = dithering_matrices[setting_int("dithering")],
|
|
protection_bypass = setting_int("protection_bypass") == 1,
|
|
weighed = setting_int("alpha_weighing") == 1,
|
|
filtering = filtering[setting_int("filtering")],
|
|
color_choosing = color_choosing[setting_int("color_choosing")],
|
|
merge_mode = merge_mode[setting_int("placement")],
|
|
}
|
|
modlib.table.add_all(params, additional)
|
|
return place_obj(params)
|
|
end
|
|
|
|
cmdlib.register_chatcommand("vox place", {
|
|
description = "Place model at position with given size. Missing coordinates will be replaced by player coordinates.",
|
|
params = "[scale] {position}",
|
|
func = function(sendername, params)
|
|
if params.scale then
|
|
params.scale = tonumber(params.scale)
|
|
if not params.scale then return false, "Scale needs to be a valid number" end
|
|
if params.position and #params.position > 3 then return false, "Only 3 coordinates (x, y, z) are allowed" end
|
|
end
|
|
local pos = substitute_coords(params.position or {}, sendername)
|
|
local error = place(sendername, { pos1 = pos, scale = params.scale })
|
|
if error then return false, "Failed to place model : "..error end
|
|
return true, "Placed model at "..format_pos(pos).." with the scale "..(params.scale or 1)
|
|
end
|
|
})
|
|
|
|
cmdlib.register_chatcommand("vox 1", {
|
|
description = "Set first corner position of model to be placed. Missing coordinates will be replaced by player coordinates.",
|
|
params = "{position}",
|
|
func = function(sendername, params)
|
|
if params.position and #params.position > 3 then return false, "Only 3 coordinates (x, y, z) are allowed" end
|
|
local pos = substitute_coords(params.position or {}, sendername)
|
|
set_setting(sendername, "1", minetest.write_json(pos))
|
|
local old_id = get_setting_int(sendername, "pos1_waypoint")
|
|
if old_id then minetest.get_player_by_name(sendername):hud_remove(old_id) end
|
|
local id = minetest.get_player_by_name(sendername):hud_add({hud_elem_type="waypoint",
|
|
name="Voxelizer Position 1",
|
|
number=0xFFFF00,
|
|
world_pos = vector.to_minetest(pos)})
|
|
minetest.add_particle({
|
|
pos = vector.to_minetest(pos),
|
|
velocity = {x=0, y=0, z=0},
|
|
acceleration = {x=0, y=0, z=0},
|
|
expirationtime = 6,
|
|
size = 16,
|
|
collisiondetection = false,
|
|
collision_removal = false,
|
|
object_collision = false,
|
|
vertical = false,
|
|
texture = "voxelizer_marker.png",
|
|
playername = sendername,
|
|
animation = { type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 2.0 },
|
|
glow = 14
|
|
})
|
|
set_setting_int(sendername, "pos1_waypoint", id)
|
|
end
|
|
})
|
|
|
|
cmdlib.register_chatcommand("vox 2", {
|
|
description = "Set second corner position of model & place it. Missing coordinates will be replaced by player coordinates.",
|
|
params = "{position}",
|
|
func = function(sendername, params)
|
|
if params.position and #params.position > 3 then return false, "Only 3 coordinates (x, y, z) are allowed" end
|
|
local pos1, pos2 = minetest.parse_json(get_setting(sendername, "1")), substitute_coords(params.position or {}, sendername)
|
|
if not pos1 then
|
|
return false, "First corner position not set. Do \"/vox 1\" first to set it."
|
|
end
|
|
local old_id = get_setting_int(sendername, "pos1_waypoint")
|
|
if old_id then minetest.get_player_by_name(sendername):hud_remove(old_id) end
|
|
local error = place(sendername, { pos1 = pos1, pos2 = pos2 })
|
|
if error then return false, "Failed to place model : "..error end
|
|
return true, "Placed model from "..format_pos(pos1).." to "..format_pos(pos2)
|
|
end
|
|
})
|
|
|
|
cmdlib.register_chatcommand("vox reset", {
|
|
description = "Reset settings",
|
|
func = function(sendername)
|
|
for setting, _ in pairs(defaults) do
|
|
set_setting(sendername, setting, "")
|
|
end
|
|
return true, "Settings resetted."
|
|
end
|
|
})
|
|
|
|
if config.download then
|
|
minetest.register_privilege("voxelizer:download", {
|
|
description = "Can download files from the internet using the voxelizer mod",
|
|
give_to_admin = true,
|
|
give_to_singleplayer = true
|
|
})
|
|
|
|
local errors = {
|
|
"URL and output path need to be given",
|
|
"Couldn't create file",
|
|
"Output file doesn't exist or can't be written",
|
|
"Couldn't download file",
|
|
"Couldn't write to file",
|
|
"Malformed URL"
|
|
}
|
|
|
|
cmdlib.register_chatcommand("vox download", {
|
|
description = "Download a file from the internet",
|
|
params = "<url> [filename]",
|
|
privs = {["voxelizer:download"]=true},
|
|
func = function(_, params)
|
|
if not params.filename then
|
|
local last_slash
|
|
for i = params.url:len(), 1, -1 do
|
|
if params.url:sub(i, i) == "/" then
|
|
last_slash = i
|
|
break
|
|
end
|
|
end
|
|
params.filename = params.url:sub(last_slash+1)
|
|
end
|
|
|
|
local path = voxelizer.get_media(params.filename)
|
|
local response_code = os_execute("java", "-classpath", minetest.get_modpath("voxelizer").."/production", "FileDownloader", params.url, path)
|
|
if response_code ~= 0 then
|
|
local error = errors[response_code]
|
|
if error then return false, "Download failed : "..error end
|
|
return false, "Download failed"
|
|
end
|
|
|
|
return true, "Download successful"
|
|
end
|
|
})
|
|
end |