From 29c7ff5228864bcf5456f391b122c9eb477c754b Mon Sep 17 00:00:00 2001
From: Vanessa Ezekowitz <vanessaezekowitz@gmail.com>
Date: Wed, 23 Jul 2014 16:00:13 +0200
Subject: [PATCH] don't attempt to force-load blocks if they're already loaded.

---
 technic/machines/switching_station.lua |  182 ++++++++++++++++++++++++++++++++++----------
 1 files changed, 139 insertions(+), 43 deletions(-)

diff --git a/technic/machines/switching_station.lua b/technic/machines/switching_station.lua
index de9b4aa..6b59277 100644
--- a/technic/machines/switching_station.lua
+++ b/technic/machines/switching_station.lua
@@ -27,20 +27,22 @@
 --
 --  The reason the LV|MV|HV type is prepended toe meta data is because some machine could require several supplies to work.
 --  This way the supplies are separated per network.
-technic.DBG = 1
-local dprint = technic.dprint
+
+technic.networks = {}
+
+local S = technic.getter
 
 minetest.register_craft({
 	output = "technic:switching_station",
 	recipe = {
-		{"default:steel_ingot",  "technic:lv_transformer", "default:steel_ingot"},
-		{"default:copper_ingot", "technic:lv_cable0",      "default:copper_ingot"},
-		{"default:steel_ingot",  "technic:lv_cable0",      "default:steel_ingot"}
+		{"",                        "technic:lv_transformer", ""},
+		{"default:copper_ingot",    "technic:machine_casing", "default:copper_ingot"},
+		{"technic:lv_cable0",       "technic:lv_cable0",      "technic:lv_cable0"}
 	}
 })
 
 minetest.register_node("technic:switching_station",{
-	description = "Switching Station",
+	description = S("Switching Station"),
 	tiles  = {"technic_water_mill_top_active.png", "technic_water_mill_top_active.png",
                   "technic_water_mill_top_active.png", "technic_water_mill_top_active.png",
 	          "technic_water_mill_top_active.png", "technic_water_mill_top_active.png"},
@@ -54,24 +56,10 @@
 	},
 	on_construct = function(pos)
 		local meta = minetest.get_meta(pos)
-		meta:set_string("infotext", "Switching Station")
+		meta:set_string("infotext", S("Switching Station"))
+		meta:set_string("active", 1)
 	end,
 })
-
---------------------------------------------------
--- Functions to help the machines on the electrical network
---------------------------------------------------
--- This one provides a timeout for a node in case it was disconnected from the network
--- A node must be touched by the station continuously in order to function
-function technic.switching_station_timeout_count(pos, tier)
-	local meta = minetest.get_meta(pos)
-	timeout = meta:get_int(tier.."_EU_timeout")
-	if timeout == 0 then
-		meta:set_int(tier.."_EU_input", 0)
-	else
-		meta:set_int(tier.."_EU_timeout", timeout - 1)
-	end
-end
 
 --------------------------------------------------
 -- Functions to traverse the electrical network
@@ -91,8 +79,15 @@
 	return true
 end
 
+local load_position = function(pos)
+	if minetest.get_node_or_nil(pos) then return end
+	local vm = VoxelManip()
+	local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
+end
+
 -- Generic function to add found connected nodes to the right classification array
-local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, all_nodes, pos, machines, tier)
+local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos)
+	load_position(pos)
 	local meta = minetest.get_meta(pos)
 	local name = minetest.get_node(pos).name
 
@@ -104,6 +99,15 @@
 			add_new_cable_node(PR_nodes, pos)
 		elseif machines[name] == technic.receiver then
 			add_new_cable_node(RE_nodes, pos)
+		elseif machines[name] == technic.producer_receiver then
+			add_new_cable_node(PR_nodes, pos)
+			add_new_cable_node(RE_nodes, pos)
+		elseif machines[name] == "SPECIAL" and
+				(pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) then
+			-- Another switching station -> disable it
+			add_new_cable_node(SP_nodes, pos)
+			meta:set_int("active", 0)
+			meta:set_string("active_pos", minetest.serialize(sw_pos))
 		elseif machines[name] == technic.battery then
 			add_new_cable_node(BA_nodes, pos)
 		end
@@ -113,7 +117,7 @@
 end
 
 -- Traverse a network given a list of machines and a cable type name
-local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, all_nodes, i, machines, tier)
+local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, i, machines, tier, sw_pos)
 	local pos = all_nodes[i]
 	local positions = {
 		{x=pos.x+1, y=pos.y,   z=pos.z},
@@ -124,8 +128,44 @@
 		{x=pos.x,   y=pos.y,   z=pos.z-1}}
 	--print("ON")
 	for i, cur_pos in pairs(positions) do
-		check_node_subp(PR_nodes, RE_nodes, BA_nodes, all_nodes, cur_pos, machines, tier)
+		check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, cur_pos, machines, tier, sw_pos)
 	end
+end
+
+local touch_nodes = function(list, tier)
+	for _, pos in ipairs(list) do
+		local meta = minetest.get_meta(pos)
+		meta:set_int(tier.."_EU_timeout", 2) -- Touch node
+	end
+end
+
+local get_network = function(sw_pos, pos1, tier)
+	local cached = technic.networks[minetest.hash_node_position(pos1)]
+	if cached and cached.tier == tier then
+		touch_nodes(cached.PR_nodes, tier)
+		touch_nodes(cached.BA_nodes, tier)
+		touch_nodes(cached.RE_nodes, tier)
+		for _, pos in ipairs(cached.SP_nodes) do
+			local meta = minetest.get_meta(pos)
+			meta:set_int("active", 0)
+			meta:set_string("active_pos", minetest.serialize(sw_pos))
+		end
+		return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes
+	end
+	local i = 1
+	local PR_nodes = {}
+	local BA_nodes = {}
+	local RE_nodes = {}
+	local SP_nodes = {}
+	local all_nodes = {pos1}
+	repeat
+		traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes,
+				i, technic.machines[tier], tier, sw_pos)
+		i = i + 1
+	until all_nodes[i] == nil
+	technic.networks[minetest.hash_node_position(pos1)] = {tier = tier, PR_nodes = PR_nodes,
+			RE_nodes = RE_nodes, BA_nodes = BA_nodes, SP_nodes = SP_nodes}
+	return PR_nodes, BA_nodes, RE_nodes
 end
 
 -----------------------------------------------
@@ -145,33 +185,52 @@
 		local RE_EU            = 0 -- EUs to RE nodes
 
 		local tier      = ""
-		local all_nodes = {}
-		local PR_nodes  = {}
-		local BA_nodes  = {} 
-		local RE_nodes  = {}
+		local PR_nodes
+		local BA_nodes
+		local RE_nodes
+		local machine_name = S("Switching Station")
 
+		if meta:get_int("active") ~= 1 then
+			meta:set_int("active", 1)
+			local active_pos = minetest.deserialize(meta:get_string("active_pos"))
+			if active_pos then
+				local meta1 = minetest.get_meta(active_pos)
+				meta:set_string("infotext", S("%s (Slave)"):format(meta1:get_string("infotext")))
+			end
+			return
+		end
+		
 		-- Which kind of network are we on:
 		pos1 = {x=pos.x, y=pos.y-1, z=pos.z}
-		all_nodes[1] = pos1
 
 		local name = minetest.get_node(pos1).name
 		local tier = technic.get_cable_tier(name)
 		if tier then
-			local i = 1
-			repeat
-				traverse_network(PR_nodes, RE_nodes, BA_nodes, all_nodes,
-						i, technic.machines[tier], tier)
-				i = i + 1
-			until all_nodes[i] == nil
+			PR_nodes, BA_nodes, RE_nodes = get_network(pos, pos1, tier)
 		else
 			--dprint("Not connected to a network")
-			meta:set_string("infotext", "Switching Station - no network")
+			meta:set_string("infotext", S("%s Has No Network"):format(machine_name))
 			return
 		end
-		--dprint("nodes="..table.getn(all_nodes)
-		--		.." PR="..table.getn(PR_nodes)
-		--		.." BA="..table.getn(BA_nodes)
-		--		.." RE="..table.getn(RE_nodes))
+		
+		-- Run all the nodes
+		local function run_nodes(list)
+			for _, pos2 in ipairs(list) do
+				load_position(pos2)
+				local node2 = minetest.get_node(pos2)
+				local nodedef
+				if node2 and node2.name then
+					nodedef = minetest.registered_nodes[node2.name]
+				end
+				if nodedef and nodedef.technic_run then
+					nodedef.technic_run(pos2, node2)
+				end
+			end
+		end
+		
+		run_nodes(PR_nodes)
+		run_nodes(RE_nodes)
+		run_nodes(BA_nodes)
 
 		-- Strings for the meta data
 		local eu_demand_str    = tier.."_EU_demand"
@@ -211,8 +270,8 @@
 		--dprint("Total BA demand:"..BA_eu_demand)
 
 		meta:set_string("infotext",
-				"Switching Station. Supply: "..PR_eu_supply
-				.." Demand: "..RE_eu_demand)
+				S("%s. Supply: %d Demand: %d"):format(
+				machine_name, PR_eu_supply, RE_eu_demand))
 
 		-- If the PR supply is enough for the RE demand supply them all
 		if PR_eu_supply >= RE_eu_demand then
@@ -278,6 +337,43 @@
 	end,
 })
 
+-- Timeout ABM
+-- Timeout for a node in case it was disconnected from the network
+-- A node must be touched by the station continuously in order to function
+local function switching_station_timeout_count(pos, tier)
+	local meta = minetest.get_meta(pos)
+	local timeout = meta:get_int(tier.."_EU_timeout")
+	if timeout <= 0 then
+		--meta:set_int(tier.."_EU_input", 0) -- Not needed anymore
+		return true
+	else
+		meta:set_int(tier.."_EU_timeout", timeout - 1)
+		return false
+	end
+end
+minetest.register_abm({
+	nodenames = {"group:technic_machine"},
+	interval   = 1,
+	chance     = 1,
+	action = function(pos, node, active_object_count, active_object_count_wider)
+		for tier, machines in pairs(technic.machines) do
+			if machines[node.name] and switching_station_timeout_count(pos, tier) then
+				local nodedef = minetest.registered_nodes[node.name]
+				if nodedef and nodedef.technic_disabled_machine_name then
+					node.name = nodedef.technic_disabled_machine_name
+					minetest.swap_node(pos, node)
+				elseif nodedef and nodedef.technic_on_disable then
+					nodedef.technic_on_disable(pos, node)
+				end
+				if nodedef then
+					local meta = minetest.get_meta(pos)
+					meta:set_string("infotext", S("%s Has No Network"):format(nodedef.description))
+				end
+			end
+		end
+	end,
+})
+
 for tier, machines in pairs(technic.machines) do
 	-- SPECIAL will not be traversed
 	technic.register_machine(tier, "technic:switching_station", "SPECIAL")

--
Gitblit v1.8.0