summaryrefslogtreecommitdiff
path: root/worldedit/visualization.lua
blob: dbee5d087029c680bbaa7b2b9bb8ffbeb70f3f8d (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
worldedit = worldedit or {}
local minetest = minetest --local copy of global

--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions
worldedit.sort_pos = function(pos1, pos2)
	pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}
	pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}
	if pos1.x > pos2.x then
		pos2.x, pos1.x = pos1.x, pos2.x
	end
	if pos1.y > pos2.y then
		pos2.y, pos1.y = pos1.y, pos2.y
	end
	if pos1.z > pos2.z then
		pos2.z, pos1.z = pos1.z, pos2.z
	end
	return pos1, pos2
end

--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume
worldedit.volume = function(pos1, pos2)
	local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
	return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)
end

minetest.register_node("worldedit:placeholder", {
	drawtype = "airlike",
	paramtype = "light",
	sunlight_propagates = true,
	diggable = false,
	groups = {not_in_creative_inventory=1},
})

--hides all nodes in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes hidden
worldedit.hide = function(pos1, pos2)
	--make area stay loaded
	local manip = minetest.get_voxel_manip()
	manip:read_from_map(pos1, pos2)

	local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
	local pos = {x=pos1.x, y=0, z=0}
	local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
	while pos.x <= pos2.x do
		pos.y = pos1.y
		while pos.y <= pos2.y do
			pos.z = pos1.z
			while pos.z <= pos2.z do
				local node = get_node(pos)
				if node.name ~= "worldedit:placeholder" then
					local data = get_meta(pos):to_table() --obtain metadata of original node
					data.fields.worldedit_placeholder = node.name --add the node's name
					node.name = "worldedit:placeholder" --set node name
					add_node(pos, node) --add placeholder node
					get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata
				end
				pos.z = pos.z + 1
			end
			pos.y = pos.y + 1
		end
		pos.x = pos.x + 1
	end
	return worldedit.volume(pos1, pos2)
end

--suppresses all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively replacing them with invisible nodes, returning the number of nodes suppressed
worldedit.suppress = function(pos1, pos2, nodename)
	--ignore placeholder supression
	if nodename == "worldedit:placeholder" then
		return 0
	end

	--make area stay loaded
	local manip = minetest.get_voxel_manip()
	manip:read_from_map(pos1, pos2)

	local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
	local nodes = minetest.find_nodes_in_area(pos1, pos2, nodename)
	local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
	for _, pos in ipairs(nodes) do
		local node = get_node(pos)
		local data = get_meta(pos):to_table() --obtain metadata of original node
		data.fields.worldedit_placeholder = node.name --add the node's name
		node.name = "worldedit:placeholder" --set node name
		add_node(pos, node) --add placeholder node
		get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata
	end
	return #nodes
end

--highlights all instances of `nodename` in a region defined by positions `pos1` and `pos2` by non-destructively hiding all other nodes, returning the number of nodes found
worldedit.highlight = function(pos1, pos2, nodename)
	--make area stay loaded
	local manip = minetest.get_voxel_manip()
	manip:read_from_map(pos1, pos2)

	local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
	local pos = {x=pos1.x, y=0, z=0}
	local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
	local count = 0
	while pos.x <= pos2.x do
		pos.y = pos1.y
		while pos.y <= pos2.y do
			pos.z = pos1.z
			while pos.z <= pos2.z do
				local node = get_node(pos)
				if node.name == nodename then --node found
					count = count + 1
				elseif node.name ~= "worldedit:placeholder" then --hide other nodes
					local data = get_meta(pos):to_table() --obtain metadata of original node
					data.fields.worldedit_placeholder = node.name --add the node's name
					node.name = "worldedit:placeholder" --set node name
					add_node(pos, node) --add placeholder node
					get_meta(pos):from_table(data) --set placeholder metadata to the original node's metadata
				end
				pos.z = pos.z + 1
			end
			pos.y = pos.y + 1
		end
		pos.x = pos.x + 1
	end
	return count
end

--restores all nodes hidden with WorldEdit functions in a region defined by positions `pos1` and `pos2`, returning the number of nodes restored
worldedit.restore = function(pos1, pos2)
	--make area stay loaded
	local manip = minetest.get_voxel_manip()
	manip:read_from_map(pos1, pos2)

	local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
	local nodes = minetest.find_nodes_in_area(pos1, pos2, "worldedit:placeholder")
	local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
	for _, pos in ipairs(nodes) do
		local node = get_node(pos)
		local data = get_meta(pos):to_table() --obtain node metadata
		node.name = data.fields.worldedit_placeholder --set node name
		data.fields.worldedit_placeholder = nil --delete old nodename
		add_node(pos, node) --add original node
		get_meta(pos):from_table(data) --set original node metadata
	end
	return #nodes
end