X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=mods%2Fredstone%2Finit.lua;h=b9030461ab204cc63e99c3428f695c7155762846;hb=db3e7e0a4d893c156e354568eb1ed724a30f8379;hp=91726637935accdc723c720275814decbcb05751;hpb=33b7983a7ff8bdea3ca0a9cc8afea165f7cdc0ae;p=Crafter.git diff --git a/mods/redstone/init.lua b/mods/redstone/init.lua index 9172663..b903046 100644 --- a/mods/redstone/init.lua +++ b/mods/redstone/init.lua @@ -1,378 +1,733 @@ ---define the class +--if you attempt to read this, god bless you + +local +minetest,vector,math,table,pairs,next += +minetest,vector,math,table,pairs,next + +-- minetest class +local get_node = minetest.get_node +local get_item_group = minetest.get_item_group +local get_meta = minetest.get_meta +local facedir_to_dir = minetest.facedir_to_dir +local content_id = minetest.get_name_from_content_id +local get_content_id = minetest.get_content_id +local get_voxel_manip = minetest.get_voxel_manip +local after = minetest.after + +local swap_node = minetest.swap_node +local registered_nodes +minetest.register_on_mods_loaded(function() + registered_nodes = minetest.registered_nodes +end) + +-- math class +local abs = math.abs +local floor = math.floor +local ceil = math.ceil + +-- vector library +local new_vec = vector.new +local add_vec = vector.add +local sub_vec = vector.subtract +local vector_distance = vector.distance +local vec_equals = vector.equals + +local activator_table = {} -- this holds the translation data of activator tables (activator functions) +local capacitor_table = {} +local player_detection_table = {} + +-- redstone class redstone = {} -local r_index = {} -r_copy = nil + +redstone.player_detector_add = function(pos) + player_detection_table[minetest.serialize(pos)] = pos +end + +redstone.player_detector_remove = function(pos) + player_detection_table[minetest.serialize(pos)] = nil +end + + +-- enables mods to create data functions +function redstone.register_activator(data) + activator_table[data.name] = { + activate = data.activate, + deactivate = data.deactivate + } +end + +-- enables mods to create data functions +function redstone.register_capacitor(data) + capacitor_table[data.name] = { + off = data.off, + on = data.on + } +end local path = minetest.get_modpath("redstone") dofile(path.."/functions.lua") -dofile(path.."/wire.lua") dofile(path.."/torch.lua") dofile(path.."/lever.lua") dofile(path.."/button.lua") dofile(path.."/repeater.lua") dofile(path.."/light.lua") dofile(path.."/piston.lua") -dofile(path.."/comparator.lua") +--dofile(path.."/comparator.lua") dofile(path.."/craft.lua") -dofile(path.."/ore.lua") +--dofile(path.."/ore.lua") dofile(path.."/inverter.lua") dofile(path.."/player_detector.lua") dofile(path.."/space_maker.lua") -dofile(path.."/pressure_plate.lua") +--dofile(path.."/pressure_plate.lua") +dofile(path.."/capacitors.lua") +dofile(path.."/breaker.lua") +dofile(path.."/detector.lua") -get_old_power = function(pos) - local meta = minetest.get_meta(pos) - local oldpower = meta:get_int("old_power") - return(oldpower) -end ---set the data for powered states -get_local_power = function(pos) - local max_level = 0 - for x = -1,1 do - for y = -1,1 do - for z = -1,1 do - --index only direct neighbors - if not (math.abs(x)+math.abs(z) > 1) or (math.abs(x)+math.abs(z) == 0) then - --print(minetest.get_node(vector.add(vector.new(x,y,z),pos)).name) - local level = minetest.get_item_group(minetest.get_node(vector.add(vector.new(x,y,z),pos)).name, "redstone_power") - if level > max_level then - max_level = level +--this is written out manually so that +--math.abs is not needed +local order = { + {x=0,y=0,z=0}, + + {x=1, y=0, z=0}, {x=-1, y=0, z= 0}, + {x=0, y=0, z=1}, {x= 0, y=0, z=-1}, + + {x=0, y=1, z=0}, {x= 0, y=-1, z=0}, + + {x=1, y=1, z=0}, {x=-1, y=1, z= 0}, + {x=0, y=1, z=1}, {x= 0, y=1, z=-1}, + + {x=1, y=-1, z=0}, {x=-1, y=-1, z= 0}, + {x=0, y=-1, z=1}, {x= 0, y=-1, z=-1}, +} + +--thanks to RhodiumToad for helping me figure out a good method to do this + +local pool = {} -- this holds all redstone data (literal 3d virtual memory map) + + +local function data_injection(pos,data) + -- add data into 3d memory + if data then + if not pool[pos.x] then pool[pos.x] = {} end + if not pool[pos.x][pos.y] then pool[pos.x][pos.y] = {} end + pool[pos.x][pos.y][pos.z] = data + --delete data from 3d memory + else + if pool and pool[pos.x] and pool[pos.x][pos.y] then + pool[pos.x][pos.y][pos.z] = data + if pool[pos.x][pos.y] and not next(pool[pos.x][pos.y]) then + pool[pos.x][pos.y] = nil + -- only run this if y axis is empty + if pool[pos.x] and not next(pool[pos.x]) then + pool[pos.x] = nil + end end end end - end - end - return(max_level) end ---this is used for a power state comparison -set_old_power = function(pos,level) - local meta = minetest.get_meta(pos) - meta:set_int("old_power",level) +--[[ + _ __ + ___ | ' \ + ___ \ / ___ ,'\_ | .-. \ /| + \ / | |,'__ \ ,'\_ | \ | | | | ,' |_ /| + _ | | | |\/ \ \ | \ | |\_| _ | |_| | _ '-. .-',' |_ _ +// | | | |____| | | |\_|| |__ // | | ,'_`. | | '-. .-',' `. ,'\_ +\\_| |_,' .-, _ | | | | |\ \ // .| |\_/ | / \ || | | | / |\ \| \ + `-. .-'| |/ / | | | | | | \ \// | | | | | || | | | | |_\ || |\_| + | | | || \_| | | | /_\ \ / | |` | | | || | | | | .---'| | + | | | |\___,_\ /_\ _ // | | | \_/ || | | | | | /\| | + /_\ | | //_____// .||` _ `._,' | | | | \ `-' /| | + /_\ `------' \ | /-\ND _ `.\ | | `._,' /_\ + \| |HE `.\ + __ _ _ __ _ + / |__| /_\ |\ /| |_) |_ |_) + \__ | | / \ | \/ | |_) |__ | \ + _ _ + (_)|- ___ __ __ __ + | /\ |__)| |_ (_ + | /--\|__)|__|____) +]]-- + + +local table_3d +local temp_pool +local function create_boundary_box(pos) + table_3d = {} + for x = pos.x-9,pos.x+9 do + if pool[x] then + for y = pos.y-9,pos.y+9 do + if pool[x][y] then + for z = pos.z-9,pos.z+9 do + temp_pool = pool[x][y][z] + if temp_pool then + if not table_3d[x] then table_3d[x] = {} end + if not table_3d[x][y] then table_3d[x][y] = {} end + + if (x == pos.x-9 or x == pos.x+9 or + y == pos.y-9 or y == pos.y+9 or + z == pos.z-9 or z == pos.z+9) and + temp_pool.dust and temp_pool.dust > 1 then + table_3d[x][y][z] = {torch=temp_pool.dust} + else + if temp_pool.dust then + table_3d[x][y][z] = {dust=0,origin=temp_pool.dust} + else + table_3d[x][y][z] = temp_pool + end + end + end + end + end + end + end + end + return(table_3d) end -get_powered_state_directional = function(pos) - local meta = minetest.get_meta(pos) - local node = minetest.get_node(pos) - local param2 = node.param2 - local dir = minetest.facedir_to_dir(param2) - local input_pos = vector.subtract(pos,dir) - local behind_node = minetest.get_node(input_pos) - local level = minetest.get_item_group(behind_node.name, "redstone_power") - return(level) -end +local i +local index +local function capacitor_pathfind(source,mem_map) + for _,order in pairs(order) do + + i = add_vec(source,order) + if not mem_map[i.x] then mem_map[i.x] = {} end + if not mem_map[i.x][i.y] then mem_map[i.x][i.y] = {} end + if not mem_map[i.x][i.y][i.z] then -local redstone_activate = function(name,pos,power) - minetest.after(0,function(name,pos) - if minetest.registered_nodes[name].redstone_activation then - minetest.registered_nodes[name].redstone_activation(pos) + if i and pool and pool[i.x] and pool[i.x][i.y] and pool[i.x][i.y][i.z] then + index = pool[i.x][i.y][i.z] + if index.capacitor then + mem_map[i.x][i.y][i.z] = {name = index.name, capacitor = 0, source = index.source} + if index.source then + mem_map.found = true + end + capacitor_pathfind(i,mem_map) + end + end + end end - set_old_power(pos,power) - end,name,pos,power) + return mem_map end -local redstone_deactivate = function(name,pos,power) - minetest.after(0,function(name,pos) - if minetest.registered_nodes[name].redstone_deactivation then - minetest.registered_nodes[name].redstone_deactivation(pos) +local table_3d +local found +local temp_pool +local function capacitor_sniff(pos) + table_3d = {} + table_3d = capacitor_pathfind(pos,table_3d) + found = table_3d.found + table_3d.found = nil + if found then + for x,datax in pairs(table_3d) do + for y,datay in pairs(datax) do + for z,data in pairs(datay) do + temp_pool = pool[x][y][z] + if temp_pool then + temp_pool.capacitor = 1 + if capacitor_table[temp_pool.name] then + swap_node(new_vec(x,y,z),{name=capacitor_table[temp_pool.name].on}) + redstone.update(new_vec(x,y,z)) + end + end + end + end + end + else + for x,datax in pairs(table_3d) do + for y,datay in pairs(datax) do + for z,data in pairs(datay) do + temp_pool = pool[x][y][z] + if temp_pool then + temp_pool.capacitor = 0 + if capacitor_table[temp_pool.name] then + swap_node(new_vec(x,y,z),{name=capacitor_table[temp_pool.name].off}) + redstone.update(new_vec(x,y,z)) + end + end + end + end + end end - set_old_power(pos,power) - end,name,pos,power) end -local redstone_update = function(name,pos,power) - minetest.after(0,function(name,pos,power) - if minetest.registered_nodes[name].redstone_update then - minetest.registered_nodes[name].redstone_update(pos) + + +-- activators +local n_pos +local temp_pool +local temp_pool2 +local non_directional_activator = function(pos) + if pool[pos.x] and pool[pos.x][pos.y] and pool[pos.x][pos.y][pos.z] then + temp_pool = pool[pos.x][pos.y][pos.z] + if temp_pool then + for _,order in pairs(order) do + n_pos = add_vec(pos,order) + if pool[n_pos.x] and pool[n_pos.x][n_pos.y] and pool[n_pos.x][n_pos.y][n_pos.z] then + temp_pool2 = pool[n_pos.x][n_pos.y][n_pos.z] + if temp_pool2 then + if (not temp_pool2.directional_activator and temp_pool2.torch) or + (temp_pool2.dust and temp_pool2.dust > 0) or + (temp_pool2.torch_directional and vector.equals(temp_pool2.output, pos)) then + if activator_table[temp_pool.name] and activator_table[temp_pool.name].activate then + activator_table[temp_pool.name].activate(pos) + end + return + end + end + end + end + if activator_table[temp_pool.name] and activator_table[temp_pool.name].deactivate then + activator_table[temp_pool.name].deactivate(pos) + end + end end - set_old_power(pos,power) - end,name,pos,power) end +-- directional activators +local n_pos +local temp_pool +local temp_pool2 +local input +local ignore +local directional_activator = function(pos) + + ignore = false + input = nil + temp_pool = nil + temp_pool2 = nil + if not (pool[pos.x] and pool[pos.x][pos.y] and pool[pos.x][pos.y][pos.z]) then return end + + temp_pool = pool[pos.x][pos.y][pos.z] + + if not temp_pool then ignore = true end + if not ignore then + input = temp_pool.input + end + if not input then ignore = true end ---collect all nodes that are local to the modified ---node of redstone dust and store in memory -function redstone.collect_info(pos) - --if table.getn(r_index) == 0 then - --print("-----------------------") - --print("started indexing") - --end - local get_node = minetest.get_node - local group = minetest.get_item_group - - local function get_group(i,gotten_group) - return(group(get_node(i).name, gotten_group)) + if not ignore then + input = temp_pool.input end - - for x = -1,1 do - for y = -1,1 do - for z = -1,1 do - --index only direct neighbors - if not (math.abs(x)+math.abs(z) > 1) or (math.abs(x)+math.abs(z) == 0) then - local r_type = "" - local i = vector.add(pos,vector.new(x,y,z)) - local execute_collection = true - if r_index[i.x] and r_index[i.x][i.y] then - if r_index[i.x][i.y][i.z] then - execute_collection = false - end - end - --[[ EXPLANATION - we run through the groups - 1 redstone_torch overrides dust if defined - 2 torch_directional overrides torch if defined - 3 redstone activation is bolted on with directional overriding general - - this is to prevent weird behavior - - - This new method also uses a table bolted onto the x,y,z positional data value - what does this mean? - It's much easier to work with and modify - ]]-- - - if execute_collection == true then - --index dust - if get_group(i,"redstone_dust") > 0 then - --add data to both maps - if not r_index[i.x] then r_index[i.x] = {} end - if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end - r_index[i.x][i.y][i.z] = {dust = true,level = 0} --get_group(i,"redstone_power")} - --the data to the 3d array must be written to memory before this is executed - --or a stack overflow occurs!!! - --pass down info for activators - redstone.collect_info(i,get_group(i,"redstone_power")) - end - --index power sources - if get_group(i,"redstone_torch") > 0 then - if not r_index[i.x] then r_index[i.x] = {} end - if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end - r_index[i.x][i.y][i.z] = {torch = true,power=get_group(i,"redstone_power")} - end - --index directional power sources (Like repeaters/comparators) - --only outputs forwards - if get_group(i,"torch_directional") > 0 then - if not r_index[i.x] then r_index[i.x] = {} end - if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end - r_index[i.x][i.y][i.z] = {torch_directional = true, dir = get_node(i).param2 , power = get_group(i,"redstone_power")} - end - - --index directional activators (Like repeaters/comparators) - --only accepts input from the back - if get_group(i,"redstone_activation_directional") > 0 then - --print("indexing directional") - if not r_index[i.x] then r_index[i.x] = {} end - if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end - if not r_index[i.x][i.y][i.z] then r_index[i.x][i.y][i.z] = {} end - --r_index[i.x][i.y][i.z].activate = false - r_index[i.x][i.y][i.z].redstone_activation = true - r_index[i.x][i.y][i.z].directional = true - r_index[i.x][i.y][i.z].dir = get_node(i).param2 - end - - --index objects that activate - if get_group(i,"redstone_activation") > 0 then - if not r_index[i.x] then r_index[i.x] = {} end - if not r_index[i.x][i.y] then r_index[i.x][i.y] = {} end - if not r_index[i.x][i.y][i.z] then r_index[i.x][i.y][i.z] = {} end - --r_index[i.x][i.y][i.z].activate = false - r_index[i.x][i.y][i.z].redstone_activation = true - r_index[i.x][i.y][i.z].name = get_node(i).name - - - --set_powered_state(i) - - --local powered = get_powered_state(i) - - - --print("powered:"..powered,"oldpowered:"..old_powered) - - --r_index[i.x][i.y][i.z].powered = powered - --r_index[i.x][i.y][i.z].old_powered = old_powered - - --split this into update up and down - --if powered > old_powered then - -- r_index[i.x][i.y][i.z].deactivate = true - ---elseif powered > 0 and old_powered == 0 then - -- r_index[i.x][i.y][i.z].deactivate = true - --end - end - end - end + + if not ignore and pool and pool[input.x] and pool[input.x][input.y] and pool[input.x][input.y][input.z] then + temp_pool2 = pool[input.x][input.y][input.z] + else + ignore = true end + + if not temp_pool2 then ignore = true end + + if not ignore and ((temp_pool2.dust and temp_pool2.dust > 0) or (temp_pool2.torch and temp_pool2.directional_activator and temp_pool2.dir == temp_pool.dir) or + (not temp_pool2.directional_activator and temp_pool2.torch) or (temp_pool2.capacitor and temp_pool2.capacitor > 0)) then + if activator_table[temp_pool.name] and activator_table[temp_pool.name].activate then + activator_table[temp_pool.name].activate(pos) + return + end + return end + + if activator_table[temp_pool.name] and activator_table[temp_pool.name].deactivate then + activator_table[temp_pool.name].deactivate(pos) end end +--make redstone wire pass on current one level lower than it is +local i +local index +local passed_on_level +local x,y,z +local function redstone_distribute(pos,power,mem_map,output) ---check if index table contains items ---then execute an update -minetest.register_globalstep(function(dtime) - --if indexes exist then calculate redstone - if r_index and next(r_index) then - --create the old version to help with deactivation calculation - r_copy = table.copy(r_index) - redstone.calculate() - end - --clear the index to avoid cpu looping wasting processing power - r_index = {} -end) + power = power - 1 ---make all power sources push power out -function redstone.calculate() - --pathfind through memory map - for x,index_x in pairs(r_index) do - for y,index_y in pairs(index_x) do - for z,data in pairs(index_y) do - --allow data values for torches - if data.torch then - redstone.pathfind(vector.new(x,y,z),data.power) - elseif data.torch_directional then - redstone.pathfind(vector.new(x,y,z),data.power,data.dir) + --directional torches + if output then + x=output.x + y=output.y + z=output.z + if mem_map.dust[x] and mem_map.dust[x][y] and mem_map.dust[x][y][z] then + if mem_map.dust[x][y][z].dust < power then + mem_map.dust[x][y][z].dust = power + redstone_distribute(new_vec(x,y,z),power,mem_map,nil) + end + end + else + --redstone and torch + for _,order in pairs(order) do + i = add_vec(pos,order) + x=i.x + y=i.y + z=i.z + if mem_map.dust[x] and mem_map.dust[x][y] and mem_map.dust[x][y][z] then + if mem_map.dust[x][y][z].dust < power then + mem_map.dust[x][y][z].dust = power + redstone_distribute(new_vec(x,y,z),power,mem_map,nil) end end end end - - --calculate values for voxel manip - local x_min,x_max,y_min,y_max,z_min,z_max - for x,index_x in pairs(r_index) do - for y,index_y in pairs(index_x) do - for z,_ in pairs(index_y) do - --do this because the root (x) will always come first - if not x_min then - x_min = x - x_max = x - y_min = y - y_max = y - z_min = z - z_max = z + return(mem_map) +end + + +--[[ + , + ,. | \ + |: \ ; :\ + :' ;\| ::\ + \ : | `::\ + _) | `:`. + ,' , `. ;: ; + ,' ;: ;"' ,:: |_ + /, ` . ;::: |:`-.__ + _,' _o\ ,::.`:' ; ; . ' + _,-' `:. ;""\, + ,-' ,: `-;, + \, ;: ;--._ + `.______,-,----._ ,' ;: ,/ , ,` + / /,-';' \ ; `: ,'/,::.::: + ,',;-'-'_,--; ; :. ,',',;:::::: + ( /___,-' `. ;::,,'o/ ,::::::: + `' ) ;:,'o / ;"- -:: + \__ _,'o ,' ,:: + ) `--' ,..:::: + ; `. ,::::::: + ; ``::. ::::::: +]]-- sic em boy! +local i +local index +local function dust_sniff(pos,mem_map,boundary,single,origin,ignore) + if not single then + --print("all position index--") + for _,order in pairs(order) do + i = add_vec(pos,order) + + if not mem_map[i.x] then mem_map[i.x] = {} end + if not mem_map[i.x][i.y] then mem_map[i.x][i.y] = {} end + + if not mem_map[i.x][i.y][i.z] then + if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then + index = boundary[i.x][i.y][i.z] + + if index.dust then + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.dust[i.x] then mem_map.dust[i.x] = {} end + if not mem_map.dust[i.x][i.y] then mem_map.dust[i.x][i.y] = {} end + + mem_map.dust[i.x][i.y][i.z] = index + + dust_sniff(i,mem_map,boundary) + + elseif index.torch and index.torch > 1 then + if index.torch_directional and vec_equals(pos,index.output) then + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.torch[i.x] then mem_map.torch[i.x] = {} end + if not mem_map.torch[i.x][i.y] then mem_map.torch[i.x][i.y] = {} end + + mem_map.torch[i.x][i.y][i.z] = index + + + elseif not index.torch_directional then + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.torch[i.x] then mem_map.torch[i.x] = {} end + if not mem_map.torch[i.x][i.y] then mem_map.torch[i.x][i.y] = {} end + + mem_map.torch[i.x][i.y][i.z] = index + end + end + + if index.activator then + mem_map[i.x][i.y][i.z] = true + + if not mem_map.activator[i.x] then mem_map.activator[i.x] = {} end + if not mem_map.activator[i.x][i.y] then mem_map.activator[i.x][i.y] = {} end + + mem_map.activator[i.x][i.y][i.z] = index + elseif index.directional_activator and vec_equals(pos,index.input) then + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.activator[i.x] then mem_map.activator[i.x] = {} end + if not mem_map.activator[i.x][i.y] then mem_map.activator[i.x][i.y] = {} end + + mem_map.activator[i.x][i.y][i.z] = index + end end - if x < x_min then x_min = x end - if x > x_max then x_max = x end - if y < y_min then y_min = y end - if y > y_max then y_max = y end - if z < z_min then z_min = z end - if z > z_max then z_max = z end end end - end + else + --print("single position index") + + i = pos - local min = vector.new(x_min,y_min,z_min) - local max = vector.new(x_max,y_max,z_max) - local vm = minetest.get_voxel_manip() - local emin, emax = vm:read_from_map(min,max) - local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax} - local data = vm:get_data() - local content_id = minetest.get_name_from_content_id - --reassemble the table into a position list minetest can understand - - --run through and set dust - for x,datax in pairs(r_index) do - for y,datay in pairs(datax) do - for z,index in pairs(datay) do - local p_pos = area:index(x,y,z) + + if not mem_map[i.x] then mem_map[i.x] = {} end + if not mem_map[i.x][i.y] then mem_map[i.x][i.y] = {} end + + if not mem_map[i.x][i.y][i.z] then + if i and boundary and boundary[i.x] and boundary[i.x][i.y] and boundary[i.x][i.y][i.z] then + index = boundary[i.x][i.y][i.z] if index.dust then - data[p_pos] = minetest.get_content_id("redstone:dust_"..index.level) + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.dust[i.x] then mem_map.dust[i.x] = {} end + if not mem_map.dust[i.x][i.y] then mem_map.dust[i.x][i.y] = {} end + + mem_map.dust[i.x][i.y][i.z] = index + + dust_sniff(i,mem_map,boundary) + + elseif index.torch and index.torch > 1 then + if index.torch_directional and (vec_equals(origin,index.output) or ignore) then + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.torch[i.x] then mem_map.torch[i.x] = {} end + if not mem_map.torch[i.x][i.y] then mem_map.torch[i.x][i.y] = {} end + + mem_map.torch[i.x][i.y][i.z] = index + + + elseif not index.torch_directional then + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.torch[i.x] then mem_map.torch[i.x] = {} end + if not mem_map.torch[i.x][i.y] then mem_map.torch[i.x][i.y] = {} end + + mem_map.torch[i.x][i.y][i.z] = index + end + end + + if index.activator then + mem_map[i.x][i.y][i.z] = true + + if not mem_map.activator[i.x] then mem_map.activator[i.x] = {} end + if not mem_map.activator[i.x][i.y] then mem_map.activator[i.x][i.y] = {} end + + mem_map.activator[i.x][i.y][i.z] = index + elseif index.directional_activator and (vec_equals(origin,index.input) or ignore) then + + mem_map[i.x][i.y][i.z] = true + + if not mem_map.activator[i.x] then mem_map.activator[i.x] = {} end + if not mem_map.activator[i.x][i.y] then mem_map.activator[i.x][i.y] = {} end + + mem_map.activator[i.x][i.y][i.z] = index end end end end - vm:set_data(data) - vm:write_to_map() - - - - --run through activators - for x,datax in pairs(r_index) do - for y,datay in pairs(datax) do - for z,index in pairs(datay) do - local pos = vector.new(x,y,z) - local node = minetest.get_node(pos) - --directional activators - if index.redstone_activation == true and index.directional == true then - local power = get_powered_state_directional(pos) - local old_power = get_old_power(pos) - if power > 0 and old_power == 0 then - redstone_activate(node.name,pos,power) - elseif power == 0 and old_power > 0 then - redstone_deactivate(node.name,pos,power) - --do an update if state has not changed - elseif power > 0 and old_power > 0 then - redstone_update(node.name,pos,power) - elseif power == 0 and old_power == 0 then - redstone_update(node.name,pos,power) + return mem_map +end + +--make all power sources push power out +local pos +local node +local power +local boundary +local dust_detected +local dust_map +local pos3 +local temp_pool3 +local directional +local function calculate(pos,is_capacitor) + if not is_capacitor then + boundary = create_boundary_box(pos) + dust_map = {} + + dust_map.dust = {} + dust_map.torch = {} + dust_map.activator = {} + + dust_detected = false + + directional = false + + if boundary[pos.x] and boundary[pos.x][pos.y] and boundary[pos.x][pos.y][pos.z] then + if boundary[pos.x][pos.y][pos.z].torch_directional or boundary[pos.x][pos.y][pos.z].directional_activator then + directional = true + end + end + + -- sniff all possible dust within boundaries + if not directional then + dust_sniff(pos,dust_map,boundary) + for _,pos2 in pairs(order) do + pos3 = add_vec(pos,pos2) + if boundary[pos3.x] and boundary[pos3.x][pos3.y] and boundary[pos3.x][pos3.y][pos3.z] and + not (dust_map[pos3.x] and dust_map[pos3.x][pos3.y] and dust_map[pos3.x][pos3.y][pos3.z]) then + temp_pool3 = boundary[pos3.x][pos3.y][pos3.z] + if temp_pool3.dust then + dust_sniff(pos3,dust_map,boundary) end - --non directional activators - elseif index.redstone_activation == true then - local power = get_local_power(pos) - local old_power = get_old_power(pos) - if power > 0 and old_power == 0 then - redstone_activate(node.name,pos,power) - elseif power == 0 and old_power > 0 then - redstone_deactivate(node.name,pos,power) - --do an update if state has not changed - elseif power > 0 and old_power > 0 then - redstone_update(node.name,pos,power) - elseif power == 0 and old_power == 0 then - redstone_update(node.name,pos,power) + end + end + else + dust_sniff(pos,dust_map,boundary,true,pos,true) + + local input = boundary[pos.x][pos.y][pos.z].input + local output = boundary[pos.x][pos.y][pos.z].output + + if input and boundary[input.x] and boundary[input.x][input.y] and boundary[input.x][input.y][input.z] then + dust_sniff(input,dust_map,boundary,true,pos) + end + if output and boundary[output.x] and boundary[output.x][output.y] and boundary[output.x][output.y][output.z] then + dust_sniff(output,dust_map,boundary,true,pos) + end + end + --do torches + for x,datax in pairs(dust_map.torch) do + for y,datay in pairs(datax) do + for z,data in pairs(datay) do + if data.torch then + if data.torch_directional then + redstone_distribute(new_vec(x,y,z),data.torch,dust_map,data.output) + else + redstone_distribute(new_vec(x,y,z),data.torch,dust_map) + end end end end end - end -end ---make redstone wire pass on current one level lower than it is -function redstone.pathfind(source,source_level,direction) - --directional torches - if direction then - --print("starting direction") - local dir = minetest.facedir_to_dir(direction) - local i = vector.add(source,dir) - if r_index and r_index[i.x] and r_index[i.x][i.y] and r_index[i.x][i.y][i.z] then - local index = r_index[i.x][i.y][i.z] - --dust - if index.dust then - local passed_on_level = source_level - 1 - if passed_on_level > 0 then - r_index[i.x][i.y][i.z].level = passed_on_level - redstone.pathfind(i,passed_on_level) + --set dust, set pool memory + for x,datax in pairs(dust_map.dust) do + for y,datay in pairs(datax) do + for z,data in pairs(datay) do + if data.dust and data.dust ~= data.origin then + swap_node(new_vec(x,y,z),{name="redstone:dust_"..data.dust}) + data_injection(new_vec(x,y,z),data) + end end end end - else - --redstone and torch - for x = -1,1 do - for y = -1,1 do - for z = -1,1 do - local i = vector.add(source,vector.new(x,y,z)) - if r_index and r_index[i.x] and r_index[i.x][i.y] and r_index[i.x][i.y][i.z] then - local index = r_index[i.x][i.y][i.z] - if index.dust then - local passed_on_level = source_level - 1 - if passed_on_level > 0 and index.level < source_level then - r_index[i.x][i.y][i.z].level = passed_on_level - redstone.pathfind(i,passed_on_level) + + --activators + --this must be run at the end + for x,datax in pairs(dust_map.activator) do + for y,datay in pairs(datax) do + for z,data in pairs(datay) do + if data.directional_activator then + directional_activator(new_vec(x,y,z)) + elseif data.activator then + non_directional_activator(new_vec(x,y,z)) end end end end + else + capacitor_sniff(pos) + end +end + + +function redstone.inject(pos,data) + data_injection(pos,data) +end + + + +local level +local pos2 +local power +local max +local function player_detector_calculation() + for _,pos in pairs(player_detection_table) do + level = pool[pos.x][pos.y][pos.z].torch + max = 0 + for _,player in ipairs(minetest.get_connected_players()) do + pos2 = player:get_pos() + power = floor(11-vector_distance(pos2,pos)) + if power > 9 then + power = 9 + elseif power < 0 then + power = 0 + end + + if power > max then + max = power + end end + + if max ~= level then + swap_node(pos,{name="redstone:player_detector_"..max}) + redstone.inject(pos,{ + name = "redstone:player_detector_"..max, + torch = max, + }) + redstone.update(pos) end end end +local recursion_check = {} +local bad_node +local queue = {} +function redstone.update(pos,is_capacitor) + local count = table.getn(queue) + local s_pos = minetest.serialize(pos) + if not recursion_check[s_pos] then + recursion_check[s_pos] = 0 + end + recursion_check[s_pos] = recursion_check[s_pos] + 1 + if recursion_check[s_pos] > 25 then + --print(recursion_check[s_pos]) + minetest.after(0,function() + bad_node = minetest.get_node(pos).name + bad_node = minetest.get_node_drops(bad_node, "main:rubypick") + for _,nodey in pairs(bad_node) do + minetest.throw_item(pos,nodey) + end + minetest.remove_node(pos) + data_injection(pos,nil) + redstone.update(pos) + end) + return + end + calculate(pos,is_capacitor) +end +local dtime_goal = 0.02 +local sleep = 0 +minetest.register_globalstep(function(dtime) + player_detector_calculation() + recursion_check = {} + --[[ + if dtime > dtime_goal then + sleep = dtime - dtime_goal + end + if sleep == 0 then + for index,element in pairs(queue) do + calculate(element.pos,element.is_capacitor) + end - + queue = {} + + else + sleep = sleep - dtime + if sleep <= 0 then + sleep = 0 + end + end + ]]-- +end) ---------------------------------------------------------------------------- @@ -420,7 +775,7 @@ minetest.register_craftitem("redstone:dust", { return end local sneak = placer:get_player_control().sneak - local noddef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name] + local noddef = registered_nodes[get_node(pointed_thing.under).name] if not sneak and noddef.on_rightclick then minetest.item_place(itemstack, placer, pointed_thing) return @@ -431,32 +786,20 @@ minetest.register_craftitem("redstone:dust", { itemstack:take_item() return(itemstack) end - - - --minetest.add_node(pointed_thing.above, {name="redstone:dust_0"}) - --itemstack:take_item(1) - --minetest.sound_play("stone", {pos=pointed_thing.above}) - --return(itemstack) - --end end, }) -minetest.register_craft({ - type = "shapeless", - output = "redstone:dust", - recipe = {"redstone:dust"}, -}) - ---8 power levels 8 being the highest -local color = 0 +--15 power levels 15 being the highest for i = 0,8 do - local coloring = math.floor(color) + + local color = floor(255 * (i/8)) + minetest.register_node("redstone:dust_"..i,{ description = "Redstone Dust", wield_image = "redstone_dust_item.png", tiles = { - "redstone_dust_main.png^[colorize:red:"..coloring, "redstone_turn.png^[colorize:red:"..coloring, - "redstone_t.png^[colorize:red:"..coloring, "redstone_cross.png^[colorize:red:"..coloring + "redstone_dust_main.png^[colorize:red:"..color, "redstone_turn.png^[colorize:red:"..color, + "redstone_t.png^[colorize:red:"..color, "redstone_cross.png^[colorize:red:"..color }, power=i, drawtype = "raillike", @@ -473,13 +816,22 @@ for i = 0,8 do groups={dig_immediate=1,attached_node=1,redstone_dust=1,redstone=1,redstone_power=i}, drop="redstone:dust", on_construct = function(pos) - redstone.collect_info(pos) + data_injection(pos,{dust=i}) + calculate(pos) end, after_destruct = function(pos) - --redstone.remove(pos,minetest.registered_nodes[minetest.get_node(pos).name].power) - redstone.collect_info(pos,i) + data_injection(pos,nil) + calculate(pos) end, connects_to = {"group:redstone"}, }) - color= color +31.875 + + minetest.register_lbm({ + name = "redstone:"..i, + nodenames = {"redstone:dust_"..i}, + run_at_every_load = true, + action = function(pos) + data_injection(pos,{dust=i}) + end, + }) end