]> git.lizzy.rs Git - Crafter.git/blobdiff - mods/redstone/init.lua
Speed up redstone even more
[Crafter.git] / mods / redstone / init.lua
index 704ae42a435d1115e20041cff0ace185db230dc1..5db9a2b2f9621888807c1716af568bcd98a9045f 100644 (file)
---[[
-might have to calculate this in a local memory table then set the nodes using a voxelmanip
-]]--
+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
 
----set a torch source
+-- redstone class
+redstone = {}
 
+local speed_test
 
+local r_index = {}
+local a_index = {}
 
 local path = minetest.get_modpath("redstone")
+dofile(path.."/functions.lua")
 dofile(path.."/wire.lua")
 dofile(path.."/torch.lua")
-dofile(path.."/switches.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.."/craft.lua")
+dofile(path.."/ore.lua")
+dofile(path.."/inverter.lua")
+dofile(path.."/player_detector.lua")
+dofile(path.."/space_maker.lua")
+dofile(path.."/pressure_plate.lua")
 
-redstone = {}
 
-local r_index = {}
+--set the data for powered states
+local get_local_power = function(pos)
+       if not pos then
+               return
+       end
+       for x = -1,1 do
+       for y = -1,1 do
+       for z = -1,1 do
+               --index only direct neighbors
+               if abs(x)+abs(z)+abs(y) == 1 then
+                       --print(get_node(add_vec(new_vec(x,y,z),pos)).name)
+                       if get_item_group(get_node(add_vec(new_vec(x,y,z),pos)).name, "redstone_power") > 0 then
+                               return(1)
+                       end
+                       if get_meta(add_vec(new_vec(x,y,z),pos)):get_int("redstone_power") > 0 then
+                               return(1)
+                       end
+               end
+       end
+       end
+       end     
+       return(0)
+end
+
+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
+
+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 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
 
 --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_name = minetest.get_node
-       local group = minetest.get_node_group
+local localredstone = {}
+local node
+localredstone.injector = function(i)
+       node = get_node(i).name
+       if node == "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
+
+       --index dust
+       if get_item_group(node,"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}
+               --the data to the 3d array must be written to memory before this is executed
+               --or a stack overflow occurs!!!
+               localredstone.collector(i)
+               return
+       end
+       --index power sources
+       if get_item_group(node,"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_item_group(node,"redstone_power")}
+       end     
+       --index directional power sources (Like repeaters/comparators)
+       --only outputs forwards
+       if get_item_group(node,"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_item_group(node,"redstone_power")}
+       end
        
-       local function get_group(i,gotten_group)
-               return(group(get_name(i).name, gotten_group))
+       --index directional activators (Like repeaters/comparators)
+       --only accepts input from the back
+       if get_item_group(node,"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
        
+       --index objects that activate
+       if get_item_group(node,"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)
        for x = -1,1 do
        for y = -1,1 do
        for z = -1,1 do
-               --do not index self
-               if not (math.abs(x)+math.abs(z) > 1) 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
-                       
-                       if execute_collection == true then
-                               --index dust
-                               if get_group(i,"redstone_dust") > 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] = 0
-                                       --the data to the 3d array must be written to memory before this is executed
-                                       --or a stack overflow occurs!!!
-                                       redstone.collect_info(i)
-                               --index power sources
-                               elseif 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"
-                               --index objects that activate
-                               elseif 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
-                                       r_index[i.x][i.y][i.z] = "deactivate"
-                               end
-                       end
-                               
+               if abs(x)+abs(z) == 1 then
+                       localredstone.injector(add_vec(pos,new_vec(x,y,z)))
                end
        end
        end
        end
 end
 
+
+function redstone.collect_info(pos)
+       localredstone.injector(pos)
+       localredstone.collector(pos)
+end
+
+
 --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
+       if (r_index and next(r_index)) or (a_index and next(a_index)) then
+               --create the old version to help with deactivation calculation
                redstone.calculate()
+               --clear the index to avoid cpu looping wasting processing power
+               r_index = {}
+               a_index = {}
        end
-       --clear the index to avoid cpu looping wasting processing power
-       r_index = {}
 end)
 
 --make all power sources push power out
+local x_min
+local x_max
+local y_min
+local y_max
+local z_min
+local z_max
+local initial_check
+
+
+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
-                               if data == "torch" then
-                                       redstone.pathfind(vector.new(x,y,z),9)
+                               --allow data values for torches
+                               if data.torch then
+                                       redstone.pathfind(new_vec(x,y,z),data.power)
+                                       r_index[x][y][z] = nil
+                               elseif data.torch_directional then
+                                       redstone.pathfind(new_vec(x,y,z),data.power,data.dir)
+                                       r_index[x][y][z] = 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
+       print("total torch calc time:"..minetest.get_us_time()/1000000-speed_test)
+
+
+
+       --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
+                               --print(get_node(new_vec(x,y,z)).name)
+                               if index and index.dust then
+                                       minetest.set_node(new_vec(x,y,z),{name="redstone:dust_"..index.level})
                                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
 
-       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
-       for x,datax in pairs(r_index) do
+       for x,datax in pairs(a_index) do
                for y,datay in pairs(datax) do
-                       for z,level in pairs(datay) do
-                               local p_pos = area:index(x,y,z)
-                               --print(dump(z),dump(dataz))
-                               if type(level) == "number" then
-                                       data[p_pos] = minetest.get_content_id("redstone:dust_"..level)
-                               elseif type(level) == "string" and level == "activate" then
-                                       --print("activating")
-                                       local name = content_id(data[p_pos])
-                                       if minetest.registered_nodes[name].redstone_activation then
-                                               minetest.after(0,function(name,x,y,z)
-                                                       minetest.registered_nodes[name].redstone_activation(vector.new(x,y,z))
-                                               end,name,x,y,z)
+                       for z,index in pairs(datay) do
+                               --directional activators
+                               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
-                               elseif type(level) == "string" and level == "deactivate" then
-                                       --print("deactivating")
-                                       local name = content_id(data[p_pos])
-                                       if minetest.registered_nodes[name].redstone_deactivation then
-                                               minetest.after(0,function(name,x,y,z)
-                                                       minetest.registered_nodes[name].redstone_deactivation(vector.new(x,y,z))
-                                               end,name,x,y,z)
+                               --non directional activators
+                               else
+                                       power = get_local_power(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
                                end
                        end
                end
        end
-       vm:set_data(data)
-       vm:write_to_map()
 end
 
 --make redstone wire pass on current one level lower than it is
-function redstone.pathfind(source,source_level)
-       for x = -1,1 do
-       for y = -1,1 do
-       for z = -1,1 do
-               i = vector.add(vector.new(source.x,source.y,source.z),vector.new(x,y,z))
+local i
+local index
+local passed_on_level
+local function redstone_pathfinder(source,source_level,direction)
+       --directional torches
+
+       if direction then
+               --print("starting direction")
+               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
-                       level = r_index[i.x][i.y][i.z]
-                       
-                       --normal redstone
-                       if type(level) == "number" then
-                               if level < source_level then
-                                       local passed_on_level = source_level - 1
-                                       r_index[i.x][i.y][i.z] = passed_on_level
-                                       if passed_on_level > 0 then
-                                               redstone.pathfind(i,passed_on_level)
-                                       end
+                       index = r_index[i.x][i.y][i.z]
+                       --dust
+                       if index.dust  then
+                               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_pathfinder(i,passed_on_level,nil,origin)
                                end
-                       --activators
-                       elseif type(level) == "string" and level == "deactivate" then
-                               local passed_on_level = source_level - 1
-                               if source_level > 0 then
-                                       r_index[i.x][i.y][i.z] = "activate"
+                       end
+               end
+       else
+               --redstone and torch
+               for x = -1,1 do
+               for y = -1,1 do
+               for z = -1,1 do
+                       if abs(x)+abs(z) == 1 then
+                               i = add_vec(source,new_vec(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
+                                       index = r_index[i.x][i.y][i.z]                                  
+                                       if index.dust  then
+                                               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_pathfinder(i,passed_on_level,nil)
+                                               end
+                                       end
                                end
                        end
                end
-       end
-       end
+               end
+               end
        end
 end
+function redstone.pathfind(source,source_level,direction)
+       redstone_pathfinder(source,source_level,direction)
+end
+
+
+
+
+
+
+
+
+----------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -208,20 +374,6 @@ end
 
 
 
---make torches activate activators when placed
-function redstone.torch_activate(pos)
-       --print("test")
-       for x = -1,1 do
-       for y = -1,1 do
-       for z = -1,1 do
-               local i = vector.add(pos,vector.new(x,y,z))
-               if minetest.get_node_group(minetest.get_node(i).name, "redstone_activation") > 0 then
-                       minetest.registered_nodes[minetest.get_node(i).name].redstone_activation(i)
-               end
-       end
-       end
-       end
-end
 
 
 minetest.register_craftitem("redstone:dust", {
@@ -233,25 +385,33 @@ minetest.register_craftitem("redstone:dust", {
        on_place = function(itemstack, placer, pointed_thing)
                if not pointed_thing.type == "node" then
                        return
+               end             
+               local sneak = placer:get_player_control().sneak
+               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
                end
-               local pos = pointed_thing.above
-               if minetest.registered_nodes[minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name].walkable and minetest.get_node(pointed_thing.above).name == "air" then
-                       minetest.add_node(pointed_thing.above, {name="redstone:dust_0"})
-                       itemstack:take_item(1)
-                       --print(minetest.get_node(pointed_thing.above).param1)
-                       --minetest.after(0,function(pointed_thing)
-                       --      redstone.add(pos)
-                       --end,pointed_thing)
+               
+               local _,worked = minetest.item_place(ItemStack("redstone:dust_0"), placer, pointed_thing)
+               if worked then
+                       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,
 })
 
-
 --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",
@@ -270,13 +430,14 @@ for i = 0,8 do
                        type = "fixed",
                        fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
                },
-               groups={dig_immediate=1,attached=1,redstone_dust=1,redstone=1},
+               sounds = main.stoneSound(),
+               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)
                end,
                after_destruct = function(pos)
-                       --redstone.remove(pos,minetest.registered_nodes[minetest.get_node(pos).name].power)
+                       --redstone.remove(pos,registered_nodes[get_node(pos).name].power)
                        redstone.collect_info(pos)
                end,
                connects_to = {"group:redstone"},