smart_light = {} local storage = minetest.get_mod_storage() -- Datenstruktur laden local data = storage:get_string("registry") smart_light.registry = data ~= "" and minetest.deserialize(data) or { areas = {} } smart_light.shadow_to_original = {} smart_light.original_to_shadows = {} -- Definition der Stufen für die Dimm-Logik smart_light.LEVEL_ORDER = {"off", "low", "mid", "high", "max"} function smart_light.save() storage:set_string("registry", minetest.serialize(smart_light.registry)) end -- Hilfsfunktion: Status-Text (AN/AUS) für UI function smart_light.get_status_text(area, chan) if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then return "AUS" end local level = smart_light.registry.areas[area].channels[chan].last_level or "max" return (level == "off") and "AUS" or "AN" end -- Hilfsfunktion: Zählt Lichter in einem Channel function smart_light.get_count(area, chan) if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then return 0 end local count = 0 local target = smart_light.registry.areas[area].channels[chan].nodes or {} for _ in pairs(target) do count = count + 1 end return count end -- Hilfsfunktion: Entfernt ein Licht aus der Registry function smart_light.unregister_light(pos, area, chan) local pos_str = minetest.pos_to_string(pos) if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then if smart_light.registry.areas[area].channels[chan].nodes then smart_light.registry.areas[area].channels[chan].nodes[pos_str] = nil if next(smart_light.registry.areas[area].channels[chan].nodes) == nil then smart_light.registry.areas[area].channels[chan] = nil end smart_light.save() end end end -- Hilfsfunktion: Schalter-Visuals aktualisieren function smart_light.update_switch_visuals(area, chan, level) if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then return end local chan_data = smart_light.registry.areas[area].channels[chan] if not chan_data.switches then return end local node_name = (level == "off") and "smart_light:switch" or "smart_light:switch_active" for pos_str, _ in pairs(chan_data.switches) do local pos = minetest.string_to_pos(pos_str) local node = minetest.get_node(pos) if node.name:sub(1, 18) == "smart_light:switch" then minetest.swap_node(pos, {name = node_name, param2 = node.param2}) end end end -- Hilfsfunktion: Admin-Formspec function smart_light.get_admin_fs(area, selected_idx) local channels = {} if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels then for c_id, _ in pairs(smart_light.registry.areas[area].channels) do table.insert(channels, c_id) end table.sort(channels) end local list_str = "" for _, c_id in ipairs(channels) do list_str = list_str .. c_id .. " (" .. smart_light.get_count(area, c_id) .. ")," end return "size[6,7]label[0.5,0.2;Panel Verwaltung ("..area..")]" .. "field[0.8,1.2;5,1;new_area;Area-ID ändern;"..area.."]" .. "textlist[0.5,2.5;5,3;chan_list;"..list_str..";"..(selected_idx or "")..";false]" .. "button[0.5,6;2.5,1;del_chan;Channel löschen]" .. "button_exit[3.5,6;2,1;save_admin;Speichern]" end -- Hilfsfunktion: Schaltlogik (RECALL FIXED) function smart_light.switch_channel(area_id, channel_id, action) local area = smart_light.registry.areas[area_id] if not area or not area.channels or not area.channels[channel_id] then return end local chan_data = area.channels[channel_id] -- Korrekte Initialisierung der Datenstruktur if not chan_data.nodes then local old_nodes = table.copy(chan_data) area.channels[channel_id] = { nodes = old_nodes, last_level = "max", brightness = "max" } chan_data = area.channels[channel_id] end -- Helligkeits-Gedächtnis sicherstellen if not chan_data.brightness or chan_data.brightness == "off" then chan_data.brightness = "max" end local target_level if action == "off" then target_level = "off" -- Wir speichern target_level NICHT in brightness, um das Gedächtnis zu behalten elseif action == "on" then target_level = chan_data.brightness elseif action == "up" or action == "down" then local cur = chan_data.brightness local idx = 1 for i, v in ipairs(smart_light.LEVEL_ORDER) do if v == cur then idx = i end end if action == "up" then idx = math.min(idx + 1, 5) else idx = math.max(idx - 1, 2) end target_level = smart_light.LEVEL_ORDER[idx] chan_data.brightness = target_level -- Neues Gedächtnis speichern end -- Aktuellen Status für das UI speichern chan_data.last_level = target_level -- Physisches Umschalten for pos_str, _ in pairs(chan_data.nodes) do local pos = minetest.string_to_pos(pos_str) local node = minetest.get_node(pos) local original = smart_light.shadow_to_original[node.name] or node.name local shadows = smart_light.original_to_shadows[original] if shadows and shadows[target_level] then minetest.swap_node(pos, {name = shadows[target_level], param2 = node.param2}) end end smart_light.update_switch_visuals(area_id, channel_id, target_level) smart_light.save() end -- Dateien laden local path = minetest.get_modpath("smart_light") dofile(path .. "/nodes.lua") dofile(path .. "/tools.lua") dofile(path .. "/panel.lua") dofile(path .. "/handlers.lua") dofile(path .. "/switch.lua") dofile(path .. "/motion_sensor.lua") dofile(path .. "/overrides.lua")