summaryrefslogtreecommitdiff
path: root/digilines/internal.lua
blob: 05c93faa8b0126bc08f409f4c80e92d9c5b331c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
function digilines.getspec(node)
	local def = minetest.registered_nodes[node.name]
	if not def then return false end
	return def.digilines or def.digiline
end

function digilines.importrules(spec, node)
	if type(spec) == 'function' then
		return spec(node)
	elseif spec then
		return spec
	else
		return digilines.rules.default
	end
end

function digilines.getAnyInputRules(pos)
	local node = digilines.get_node_force(pos)
	local spec = digilines.getspec(node)
	if not spec then return end

	if spec.wire then
		return digilines.importrules(spec.wire.rules, node)
	end
	if spec.effector then
		return digilines.importrules(spec.effector.rules, node)
	end
end

function digilines.getAnyOutputRules(pos)
	local node = digilines.get_node_force(pos)
	local spec = digilines.getspec(node)
	if not spec then return end

	if spec.wire then
		return digilines.importrules(spec.wire.rules, node)
	end
	if spec.receptor then
		return digilines.importrules(spec.receptor.rules, node)
	end
end

function digilines.rules_link(output, input)
	local outputrules = digilines.getAnyOutputRules(output)
	local inputrules  = digilines.getAnyInputRules (input)

	if not outputrules or not inputrules then return false end


	for _, orule in ipairs(outputrules) do
		if digilines.cmpPos(digilines.addPosRule(output, orule), input) then
			for _, irule in ipairs(inputrules) do
				if digilines.cmpPos(digilines.addPosRule(input, irule), output) then
					return true
				end
			end
		end
	end
	return false
end

function digilines.rules_link_anydir(output, input)
	return digilines.rules_link(output, input)
	or     digilines.rules_link(input, output)
end

local function queue_new()
	return {nextRead = 1, nextWrite = 1}
end

local function queue_empty(queue)
	return queue.nextRead == queue.nextWrite
end

local function queue_enqueue(queue, object)
	local nextWrite = queue.nextWrite
	queue[nextWrite] = object
	queue.nextWrite = nextWrite + 1
end

local function queue_dequeue(queue)
	local nextRead = queue.nextRead
	local object = queue[nextRead]
	queue[nextRead] = nil
	queue.nextRead = nextRead + 1
	return object
end

function digilines.transmit(pos, channel, msg, checked)
	local checkedID = minetest.hash_node_position(pos)
	if checked[checkedID] then
		return
	end
	checked[checkedID] = true
	
	digilines.vm_begin()
	local queue = queue_new()
	queue_enqueue(queue, pos)
	while not queue_empty(queue) do
		local curPos = queue_dequeue(queue)
		local node = digilines.get_node_force(curPos)
		local spec = digilines.getspec(node)
		if spec then
			-- Effector actions --> Receive
			if spec.effector then
				spec.effector.action(curPos, node, channel, msg)
			end

			-- Cable actions --> Transmit
			if spec.wire then
				local rules = digilines.importrules(spec.wire.rules, node)
				for _, rule in ipairs(rules) do
					local nextPos = digilines.addPosRule(curPos, rule)
					if digilines.rules_link(curPos, nextPos) then
						local checkedID = minetest.hash_node_position(nextPos)
						if not checked[checkedID] then
							checked[checkedID] = true
							queue_enqueue(queue, nextPos)
						end
					end
				end
			end
		end
	end
	digilines.vm_end()
end