X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=mods%2Fredstone%2Finit.lua;h=fa5efad4f8311b33e1a652abf7004b7d15375dbf;hb=3fd2beca9ff93822cfb41a69dfe3271e9d5da000;hp=d2e0f35d3fd3d52fe15034c610d8b8d10e76aa80;hpb=2fe7a05a3dfedc77dfdb2ef621695c9241dd8240;p=Crafter.git diff --git a/mods/redstone/init.lua b/mods/redstone/init.lua index d2e0f35..fa5efad 100644 --- a/mods/redstone/init.lua +++ b/mods/redstone/init.lua @@ -1,6 +1,55 @@ ---define the class +local +minetest,vector,math,table,pairs += +minetest,vector,math,table,pairs + +-- 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 registered_nodes +minetest.register_on_mods_loaded(function() + registered_nodes = minetest.registered_nodes +end) + +-- math class +local abs = math.abs +local floor = math.floor + +-- vector library +local new_vec = vector.new +local add_vec = vector.add +local sub_vec = vector.subtract +local vector_distance = vector.distance + +--this is written out manually so that +--math.abs is not needed +local order = { + {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}, +} + +-- redstone class redstone = {} + +local speed_test + local r_index = {} +local a_index = {} +local check_table = {} local path = minetest.get_modpath("redstone") dofile(path.."/functions.lua") @@ -20,306 +69,240 @@ dofile(path.."/space_maker.lua") dofile(path.."/pressure_plate.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_node_group(minetest.get_node(vector.add(vector.new(x,y,z),pos)).name, "redstone_power") - if level > max_level then - max_level = level - end - end - end +local get_local_power = function(pos) + if not pos then + return end + for _,order in pairs(order) do + --print(get_node(add_vec(new_vec(x,y,z),pos)).name) + if get_item_group(get_node(add_vec(new_vec(order.x,order.y,order.z),pos)).name, "redstone_power") > 0 then + return(1) + end + if get_meta(add_vec(new_vec(order.x,order.y,order.z),pos)):get_int("redstone_power") > 0 then + return(1) + end end - return(max_level) + return(0) 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) +local power +local pos +local get_powered_state_directional = function(pos) + pos = sub_vec(pos,facedir_to_dir(get_node(pos).param2)) + power = get_item_group(get_node(pos).name, "redstone_power") + if power == 0 then + power = get_meta(pos):get_int("redstone_power") + end + return(power) 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_node_group(behind_node.name, "redstone_power") - return(level) +local node +local redstone_activate = function(pos,power) + after(0,function() + node = get_node(pos).name + if registered_nodes[node].redstone_activation then + registered_nodes[node].redstone_activation(pos) + end + end) end - -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) - end - set_old_power(pos,power) - end,name,pos,power) +local node +local redstone_deactivate = function(pos,power) + after(0,function() + node = get_node(pos).name + if registered_nodes[node].redstone_deactivation then + registered_nodes[node].redstone_deactivation(pos) + end + end) 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) - end - set_old_power(pos,power) - end,name,pos,power) +--collect all nodes that are local to the modified +--node of redstone dust and store in memory +local function get_group(i,gotten_group) + return(get_item_group(get_node(i).name, gotten_group)) 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) - end - set_old_power(pos,power) - end,name,pos,power) -end +local localredstone = {} +localredstone.injector = function(i,origin) + if get_node(i).name == "air" then + return + end + if r_index[i.x] and r_index[i.x][i.y] then + if r_index[i.x][i.y][i.z] then + return + end + end + if vector_distance(i,origin) > 9 then + return + 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_node_group + --index dust + if get_group(i,"redstone_dust") > 0 then + if vector_distance(i,origin) <= 8 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} + + if not check_table[i.x] then check_table[i.x] = {} end + if not check_table[i.x][i.y] then check_table[i.x][i.y] = {} end + check_table[i.x][i.y][i.z] = 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!!! + localredstone.collector(i,origin) + return + else + 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 + 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 - local function get_group(i,gotten_group) - return(group(get_node(i).name, gotten_group)) + --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 a_index[i.x] then a_index[i.x] = {} end + if not a_index[i.x][i.y] then a_index[i.x][i.y] = {} end + if not a_index[i.x][i.y][i.z] then a_index[i.x][i.y][i.z] = {} end + + a_index[i.x][i.y][i.z].redstone_activation = true + a_index[i.x][i.y][i.z].directional = true 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 + --index objects that activate + if get_group(i,"redstone_activation") > 0 then + if not a_index[i.x] then a_index[i.x] = {} end + if not a_index[i.x][i.y] then a_index[i.x][i.y] = {} end + if not a_index[i.x][i.y][i.z] then a_index[i.x][i.y][i.z] = {} end + a_index[i.x][i.y][i.z].redstone_activation = true end + + --sneaky way to make levers and buttons work + if get_meta(i):get_int("redstone_power") > 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_meta(i):get_int("redstone_power")} end +end + +localredstone.collector = function(pos,origin) + for _,order in pairs(order) do + localredstone.injector(add_vec(pos,new_vec(order.x,order.y,order.z)),origin) end end --check if index table contains items --then execute an update -minetest.register_globalstep(function(dtime) +local function redstone_algorithm() --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 + --create the old version to help with deactivation calculation + redstone.calculate() --clear the index to avoid cpu looping wasting processing power r_index = {} -end) + a_index = {} + check_table = {} +end + + +function redstone.collect_info(pos) + if r_index[pos.x] and r_index[pos.x][pos.y] and r_index[pos.x][pos.y][pos.z] then + return + end + localredstone.injector(pos,pos) + localredstone.collector(pos,pos) + + redstone_algorithm() +end + --make all power sources push power out +local pos +local node +local power function redstone.calculate() + --speed_test = minetest.get_us_time()/1000000 + --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) + redstone.pathfind(new_vec(x,y,z),data.power) + r_index[x][y][z] = nil elseif data.torch_directional then - redstone.pathfind(vector.new(x,y,z),data.power,data.dir) - 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 + redstone.pathfind(new_vec(x,y,z),data.power,data.dir) + r_index[x][y][z] = nil 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 + + --print("total torch calc time:"..minetest.get_us_time()/1000000-speed_test) + + - 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 + --local count = 0 + 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 index.dust then - data[p_pos] = minetest.get_content_id("redstone:dust_"..index.level) + --print(get_node(new_vec(x,y,z)).name) + if index and index.dust and index.level ~= check_table[x][y][z] then + --count = count + 1 + minetest.set_node(new_vec(x,y,z),{name="redstone:dust_"..index.level}) end end end end - vm:set_data(data) - vm:write_to_map() - - - - --run through activators - for x,datax in pairs(r_index) do + --print("set "..count.." nodes") + + for x,datax in pairs(a_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) + if index.directional == true then + power = get_powered_state_directional(new_vec(x,y,z)) + if power then + if power > 0 then + redstone_activate(new_vec(x,y,z),power) + elseif power == 0 then + redstone_deactivate(new_vec(x,y,z),power) + end 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) + else + power = get_local_power(new_vec(x,y,z)) + --print(power) + if power then + if power > 0 then + redstone_activate(new_vec(x,y,z),power) + elseif power == 0 then + redstone_deactivate(new_vec(x,y,z),power) + end end end end @@ -328,44 +311,47 @@ function redstone.calculate() end --make redstone wire pass on current one level lower than it is -function redstone.pathfind(source,source_level,direction) +local i +local index +local passed_on_level +local function redstone_pathfinder(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) + i = add_vec(source,facedir_to_dir(direction)) 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] + index = r_index[i.x][i.y][i.z] --dust if index.dust then - local passed_on_level = source_level - 1 + 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) + redstone_pathfinder(i,passed_on_level,nil) 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)) + for _,order in pairs(order) do + i = add_vec(source,new_vec(order.x,order.y,order.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] + --print(minetest.get_node(i).name) + index = r_index[i.x][i.y][i.z] if index.dust then - local passed_on_level = source_level - 1 + 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) + redstone_pathfinder(i,passed_on_level,nil) end end end end - end - end end end +function redstone.pathfind(source,source_level,direction) + redstone_pathfinder(source,source_level,direction) +end @@ -419,7 +405,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 @@ -440,16 +426,10 @@ minetest.register_craftitem("redstone:dust", { end, }) -minetest.register_craft({ - type = "shapeless", - output = "redstone:dust", - recipe = {"redstone:dust"}, -}) - --8 power levels 8 being the highest local color = 0 for i = 0,8 do - local coloring = math.floor(color) + local coloring = floor(color) minetest.register_node("redstone:dust_"..i,{ description = "Redstone Dust", wield_image = "redstone_dust_item.png", @@ -475,8 +455,8 @@ for i = 0,8 do redstone.collect_info(pos) end, after_destruct = function(pos) - --redstone.remove(pos,minetest.registered_nodes[minetest.get_node(pos).name].power) - redstone.collect_info(pos,i) + --redstone.remove(pos,registered_nodes[get_node(pos).name].power) + redstone.collect_info(pos) end, connects_to = {"group:redstone"}, })