Compare commits

...

7 Commits

Author SHA1 Message Date
loosewheel
36aaf42d9a Add files via upload 2022-02-15 07:14:40 +10:00
loosewheel
c879735c84 Add files via upload 2022-02-15 07:06:04 +10:00
loosewheel
76a8d37edb Add files via upload 2022-02-15 06:31:00 +10:00
loosewheel
1a450bdc2a Add files via upload 2022-02-15 06:28:44 +10:00
loosewheel
c11eb22f31 Add files via upload 2022-02-15 06:26:14 +10:00
loosewheel
e4aabe5ebe Add files via upload 2022-02-15 06:25:24 +10:00
loosewheel
3cfd9adb1f Add files via upload 2022-02-15 06:24:40 +10:00
10 changed files with 523 additions and 3 deletions

452
camera.lua Normal file
View File

@@ -0,0 +1,452 @@
local utils = ...
local S = utils.S
if utils.digilines_supported then
local function is_drop (obj)
if obj then
local entity = obj.get_luaentity and obj:get_luaentity ()
return (entity and entity.name and entity.name == "__builtin:item")
end
return false
end
local function get_entity_dims (obj)
local dims = { -0.5, 0, -0.5, 0.5, 2, 0.5 }
local found = false
if obj.get_luaentity then
local entity = obj:get_luaentity ()
if entity and entity.name then
local def = minetest.registered_entities[entity.name]
if def and type (def.collisionbox) == "table" then
dims = { def.collisionbox[1] or -0.5,
def.collisionbox[2] or -0.5,
def.collisionbox[3] or -0.5,
def.collisionbox[4] or 0.5,
def.collisionbox[5] or 0.5,
def.collisionbox[6] or 0.5 }
found = true
end
end
end
if not found then
local props = obj:get_properties ()
if props and props.collisionbox and type (props.collisionbox) == "table" then
dims = { props.collisionbox[1] or -0.5,
props.collisionbox[2] or -0.5,
props.collisionbox[3] or -0.5,
props.collisionbox[4] or 0.5,
props.collisionbox[5] or 0.5,
props.collisionbox[6] or 0.5 }
end
end
dims[1] = math.min (dims[1], dims[3])
dims[3] = dims[1]
dims[4] = math.max (dims[4], dims[6])
dims[6] = dims[4]
if (dims[3] - dims[1]) < 1 then
dims[1] = -0.5
dims[3] = -0.5
dims[4] = 0.5
dims[6] = 0.5
end
return dims
end
local function get_entity (pos)
local objects = minetest.get_objects_inside_radius (pos, 2.0)
if #objects > 0 then
for _, obj in ipairs (objects) do
if obj.get_pos then
if obj:is_player () then
local epos = vector.round (obj:get_pos ())
if epos.x == pos.x and epos.z == pos.z and
(epos.y == pos.y or epos.y == pos.y - 1) then
return 1
end
end
if not is_drop (obj) then
local epos = vector.new (obj:get_pos ())
local dims = get_entity_dims (obj)
if pos.x >= (epos.x + dims[1]) and pos.x <= (epos.x + dims[4]) and
pos.y >= (epos.y + dims[2]) and pos.y <= (epos.y + dims[5]) and
pos.z >= (epos.z + dims[3]) and pos.z <= (epos.z + dims[6]) then
return 2
end
end
end
end
end
return nil
end
local function camera_scan (pos, resolution, distance)
local node = utils.get_far_node (pos)
local image = { }
for y = 1, resolution, 1 do
image[y] = { }
for x = 1, resolution, 1 do
image[y][x] = "000000"
end
end
if node then
local dir = vector.multiply (minetest.facedir_to_dir (node.param2), -1)
local last_pos = nil
local last_color = "000000"
local view = (distance * 1.414213562) / resolution
for dist = distance, 1, -1 do
local scale = dist / distance
for y = 1, resolution, 1 do
for x = 1, resolution, 1 do
local horz = (x - (resolution / 2)) * scale * view
local vert = (y - (resolution / 2)) * scale * view
local tpos = nil
if dir.x ~= 0 then
tpos = vector.round ({ x = (dist * dir.x) + pos.x, y = pos.y - vert, z = horz + pos.z })
else
tpos = vector.round ({ x = horz + pos.x, y = pos.y - vert, z = (dist * dir.z) + pos.z })
end
if last_pos and vector.equals (last_pos, tpos) then
image[y][x] = last_color
else
local entity = get_entity (tpos)
if entity == 1 then
local color = (((distance - dist) / distance) * 98) + 30
last_color = string.format ("00%02X00", color)
image[y][x] = last_color
last_pos = tpos
elseif entity == 2 then
local color = (((distance - dist) / distance) * 98) + 30
last_color = string.format ("0000%02X", color)
image[y][x] = last_color
last_pos = tpos
else
local node = utils.get_far_node (tpos)
if node and node.name ~= "air" then
local color = (((distance - dist) / distance) * 98) + 30
last_color = string.format ("%02X%02X%02X", color, color, color)
image[y][x] = last_color
last_pos = tpos
else
last_pos = nil
end
end
end
end
end
end
end
return image
end
local function send_scan (pos)
local meta = minetest.get_meta (pos)
if meta then
local channel = meta:get_string ("channel")
if channel:len () > 0 then
local image = camera_scan (pos,
tonumber (meta:get_string ("resolution")),
tonumber (meta:get_string ("distance")))
utils.digilines_receptor_send (pos,
utils.digilines_default_rules,
channel,
image)
end
end
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]\n"..
"size[8.5,5.5;true]\n"..
"field[1.0,1.0;4.0,0.8;channel;Channel;${channel}]\n"..
"button[5.5,1.0;2.0,0.8;setchannel;Set]\n"..
"field[1.0,2.5;4.0,0.8;distance;Distance;${distance}]\n"..
"button[5.5,2.5;2.0,0.8;setdistance;Set]\n"..
"field[1.0,4.0;4.0,0.8;resolution;Resolution;${resolution}]\n"..
"button[5.5,4.0;2.0,0.8;setresolution;Set]\n"
meta:set_string ("formspec", spec)
meta:set_string ("distance", "5")
meta:set_string ("resolution", "16")
-- If return true no item is taken from itemstack
return false
end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_node (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Camera (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack
return false
end
local function on_receive_fields (pos, formname, fields, sender)
if not utils.can_interact_with_node (pos, sender) then
return
end
if fields.setchannel then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("channel", fields.channel)
end
end
if fields.setdistance then
local meta = minetest.get_meta (pos)
if meta then
local distance = math.min (math.max (tonumber (fields.distance) or 1, 1), 16)
fields.distance = tostring (distance)
meta:set_string ("distance", tostring (distance))
end
end
if fields.setresolution then
local meta = minetest.get_meta (pos)
if meta then
local resolution = math.max (tonumber (fields.resolution) or 1, 1)
fields.resolution = tostring (resolution)
meta:set_string ("resolution", tostring (resolution))
end
end
end
local function can_dig (pos, player)
if not utils.can_interact_with_node (pos, player) then
return false
end
return true
end
local function on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
minetest.remove_node (pos)
else -- intensity < 1.0
local node = minetest.get_node_or_nil (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items and #items > 0 then
local stack = ItemStack (items[1])
if stack then
preserve_metadata (pos, node, meta, { stack })
utils.item_drop (stack, nil, pos)
minetest.remove_node (pos)
end
end
end
end
end
end
local function on_rightclick (pos, node, clicker, itemstack, pointed_thing)
if not utils.can_interact_with_node (pos, clicker) then
if clicker and clicker:is_player () then
local owner = "<unknown>"
local meta = minetest.get_meta (pos)
if meta then
owner = meta:get_string ("owner")
end
local spec =
"formspec_version[3]"..
"size[8.0,4.0,false]"..
"label[1.0,1.0;Owned by "..minetest.formspec_escape (owner).."]"..
"button_exit[3.0,2.0;2.0,1.0;close;Close]"
minetest.show_formspec (clicker:get_player_name (),
"lwcomponents:component_privately_owned",
spec)
end
end
return itemstack
end
local function digilines_support ()
if utils.digilines_supported then
return
{
wire =
{
rules = utils.digilines_default_rules,
},
effector =
{
action = function (pos, node, channel, msg)
local meta = minetest.get_meta(pos)
if meta then
local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { }
for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w
end
if m[1] == "scan" then
send_scan (pos)
elseif m[1] == "distance" then
meta:set_string ("distance", tostring (tonumber (m[2] or 5) or 5))
elseif m[1] == "resolution" then
meta:set_string ("resolution", tostring (tonumber (m[2] or 16) or 16))
end
end
end
end,
}
}
end
return nil
end
minetest.register_node("lwcomponents:camera", {
description = S("Camera"),
tiles = { "lwcamera.png", "lwcamera.png", "lwcamera.png",
"lwcamera.png", "lwcamera.png", "lwcamera_lens.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:camera",
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:camera_locked", {
description = S("Camera (locked)"),
tiles = { "lwcamera.png", "lwcamera.png", "lwcamera.png",
"lwcamera.png", "lwcamera.png", "lwcamera_lens.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:camera_locked",
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_rightclick = on_rightclick
})
end -- utils.digilines_supported
--

View File

@@ -98,3 +98,7 @@ v0.1.17
v0.1.18 v0.1.18
* Added mesecons through wire. * Added mesecons through wire.
v0.1.19
* Added camera.

View File

@@ -295,6 +295,24 @@ minetest.register_craft( {
}, },
}) })
minetest.register_craft( {
output = "lwcomponents:camera",
recipe = {
{ "default:copper_ingot", "default:iron_lump" },
{ "default:chest", "default:stone" },
},
})
minetest.register_craft( {
output = "lwcomponents:camera_locked",
recipe = {
{ "default:copper_ingot", "default:iron_lump" },
{ "default:chest_locked", "default:stone" },
},
})
end -- utils.digilines_supported end -- utils.digilines_supported

View File

@@ -165,7 +165,7 @@ local function detect (pos)
local object = minetest.get_objects_inside_radius (pos, radius + 0.5) local object = minetest.get_objects_inside_radius (pos, radius + 0.5)
local detected_list = { } local detected_list = { }
for i = 1, #object do for i = 1, #object, 1 do
if object[i]:is_player () then if object[i]:is_player () then
-- player -- player

41
docs/camera.txt Normal file
View File

@@ -0,0 +1,41 @@
Camera
------
* This block is only available if digilines is loaded.
Cameras take an image in the direction they are facing. The colors in the
image represent what is being viewed. Nodes are gray, entities are blue and
players are green. The closer they are to the camera the brighter the color.
The viewing distance of the camera is 1 to 16 nodes. Also acts as a
digilines conductor.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of camera.
Distance - the viewing distance forward from the camera (1 t0 16).
Resolution - the image resolution (for both width and height).
Digilines messages
"scan"
Sends a digilines message with the camera's channel and a table of the
image as the message (see below).
"distance n"
Sets the viewing distance of the camera. Will be clipped between 1 and
16.
"resolution n"
Sets the image resolution of the camera.
The image is an indexed table of indexed tables. Each inner table is one
line of the image ordered top to bottom. There are resolution number of
lines. Each line has a string value for each pixel of that line left to
right. The string is a hex color string eg. "00FF00". There are resolution
number of pixels per line.
The image format is compatible with digistuff's digiscreens and lwcomputers'
digiscreens and digipanels. It is best to set the resolution of the camera
to the resolution of the display, then the image from the camera can be sent
straight to the display device.

View File

@@ -1,4 +1,4 @@
local version = "0.1.18" local version = "0.1.19"
local mod_storage = minetest.get_mod_storage () local mod_storage = minetest.get_mod_storage ()
@@ -36,6 +36,7 @@ loadfile (modpath.."/cannon.lua") (utils)
loadfile (modpath.."/cannon_shell.lua") (utils) loadfile (modpath.."/cannon_shell.lua") (utils)
loadfile (modpath.."/pistons.lua") (utils) loadfile (modpath.."/pistons.lua") (utils)
loadfile (modpath.."/through_wire.lua") (utils) loadfile (modpath.."/through_wire.lua") (utils)
loadfile (modpath.."/camera.lua") (utils)
loadfile (modpath.."/extras.lua") (utils) loadfile (modpath.."/extras.lua") (utils)
loadfile (modpath.."/digiswitch.lua") (utils) loadfile (modpath.."/digiswitch.lua") (utils)
loadfile (modpath.."/movefloor.lua") (utils) loadfile (modpath.."/movefloor.lua") (utils)

View File

@@ -69,6 +69,9 @@ public domain.
fan images derived from images from https://openclipart.org, which is fan images derived from images from https://openclipart.org, which is
public domain. public domain.
camera lens images derived from images from https://openclipart.org, which
is public domain.
player button images derived from mesecons button image. player button images derived from mesecons button image.
cannon firing and explosion sound from tnt (TumeniNodes/steveygos93), cannon firing and explosion sound from tnt (TumeniNodes/steveygos93),

View File

@@ -13,7 +13,7 @@ CC BY-SA 3.0
Version Version
======= =======
0.1.18 0.1.19
Minetest Version Minetest Version
@@ -66,6 +66,7 @@ Various components for mesecons and digilines.
* Double (optionally single) reach pistons and sticky pistons. * Double (optionally single) reach pistons and sticky pistons.
* Digiswitch, digilines controlled mesecons power. * Digiswitch, digilines controlled mesecons power.
* Movefloor, similar to vertical mesecons movestone. * Movefloor, similar to vertical mesecons movestone.
* Camera, takes a representative image.
* Mesecons Through Wire, transmits through 1 to 2 solid blocks. * Mesecons Through Wire, transmits through 1 to 2 solid blocks.
* Solid color conductor blocks, same as Solid Color Block but also mesecons * Solid color conductor blocks, same as Solid Color Block but also mesecons
and digilines conductor. and digilines conductor.

BIN
textures/lwcamera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

BIN
textures/lwcamera_lens.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB