aboutsummaryrefslogtreecommitdiff
path: root/builtin/common/item_s.lua
blob: f848ef6d8dabba945df67a146bacf668187844d4 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
-- Minetest: builtin/item_s.lua
-- The distinction of what goes here is a bit tricky, basically it's everything
-- that does not (directly or indirectly) need access to ServerEnvironment,
-- Server or writable access to IGameDef on the engine side.
-- (The '_s' stands for standalone.)

local builtin_shared = ...

--
-- Item definition helpers
--

function core.inventorycube(img1, img2, img3)
	img2 = img2 or img1
	img3 = img3 or img1
	return "[inventorycube"
			.. "{" .. img1:gsub("%^", "&")
			.. "{" .. img2:gsub("%^", "&")
			.. "{" .. img3:gsub("%^", "&")
end

function core.dir_to_facedir(dir, is6d)
	--account for y if requested
	if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then

		--from above
		if dir.y < 0 then
			if math.abs(dir.x) > math.abs(dir.z) then
				if dir.x < 0 then
					return 19
				else
					return 13
				end
			else
				if dir.z < 0 then
					return 10
				else
					return 4
				end
			end

		--from below
		else
			if math.abs(dir.x) > math.abs(dir.z) then
				if dir.x < 0 then
					return 15
				else
					return 17
				end
			else
				if dir.z < 0 then
					return 6
				else
					return 8
				end
			end
		end

	--otherwise, place horizontally
	elseif math.abs(dir.x) > math.abs(dir.z) then
		if dir.x < 0 then
			return 3
		else
			return 1
		end
	else
		if dir.z < 0 then
			return 2
		else
			return 0
		end
	end
end

-- Table of possible dirs
local facedir_to_dir = {
	vector.new( 0,  0,  1),
	vector.new( 1,  0,  0),
	vector.new( 0,  0, -1),
	vector.new(-1,  0,  0),
	vector.new( 0, -1,  0),
	vector.new( 0,  1,  0),
}
-- Mapping from facedir value to index in facedir_to_dir.
local facedir_to_dir_map = {
	[0]=1, 2, 3, 4,
	5, 2, 6, 4,
	6, 2, 5, 4,
	1, 5, 3, 6,
	1, 6, 3, 5,
	1, 4, 3, 2,
}
function core.facedir_to_dir(facedir)
	return facedir_to_dir[facedir_to_dir_map[facedir % 32]]
end

function core.dir_to_fourdir(dir)
	if math.abs(dir.x) > math.abs(dir.z) then
		if dir.x < 0 then
			return 3
		else
			return 1
		end
	else
		if dir.z < 0 then
			return 2
		else
			return 0
		end
	end
end

function core.fourdir_to_dir(fourdir)
	return facedir_to_dir[facedir_to_dir_map[fourdir % 4]]
end

function core.dir_to_wallmounted(dir)
	if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
		if dir.y < 0 then
			return 1
		else
			return 0
		end
	elseif math.abs(dir.x) > math.abs(dir.z) then
		if dir.x < 0 then
			return 3
		else
			return 2
		end
	else
		if dir.z < 0 then
			return 5
		else
			return 4
		end
	end
end

-- table of dirs in wallmounted order
local wallmounted_to_dir = {
	[0] = vector.new( 0,  1,  0),
	vector.new( 0, -1,  0),
	vector.new( 1,  0,  0),
	vector.new(-1,  0,  0),
	vector.new( 0,  0,  1),
	vector.new( 0,  0, -1),
}
function core.wallmounted_to_dir(wallmounted)
	return wallmounted_to_dir[wallmounted % 8]
end

function core.dir_to_yaw(dir)
	return -math.atan2(dir.x, dir.z)
end

function core.yaw_to_dir(yaw)
	return vector.new(-math.sin(yaw), 0, math.cos(yaw))
end

function core.is_colored_paramtype(ptype)
	return (ptype == "color") or (ptype == "colorfacedir") or
		(ptype == "color4dir") or (ptype == "colorwallmounted") or
		(ptype == "colordegrotate")
end

function core.strip_param2_color(param2, paramtype2)
	if not core.is_colored_paramtype(paramtype2) then
		return nil
	end
	if paramtype2 == "colorfacedir" then
		param2 = math.floor(param2 / 32) * 32
	elseif paramtype2 == "color4dir" then
		param2 = math.floor(param2 / 4) * 4
	elseif paramtype2 == "colorwallmounted" then
		param2 = math.floor(param2 / 8) * 8
	elseif paramtype2 == "colordegrotate" then
		param2 = math.floor(param2 / 32) * 32
	end
	-- paramtype2 == "color" requires no modification.
	return param2
end

-- Content ID caching

local old_get_content_id = core.get_content_id
local old_get_name_from_content_id = core.get_name_from_content_id

local name2content = setmetatable({}, {
	__index = function(self, name)
		return old_get_content_id(name)
	end,
})

local content2name = setmetatable({}, {
	__index = function(self, id)
		return old_get_name_from_content_id(id)
	end,
})

function core.get_content_id(name)
	return name2content[name]
end

function core.get_name_from_content_id(id)
	return content2name[id]
end

-- Cache content IDs after they have stopped changing.
function builtin_shared.cache_content_ids()
	for name in pairs(core.registered_nodes) do
		local id = old_get_content_id(name)
		name2content[name] = id
		content2name[id] = name
	end
	-- unknown is not in the registered node list.
	local unknown_name = old_get_name_from_content_id(core.CONTENT_UNKNOWN)
	name2content[unknown_name] = core.CONTENT_UNKNOWN
	content2name[core.CONTENT_UNKNOWN] = unknown_name

	for name in pairs(core.registered_aliases) do
		if core.registered_nodes[name] then
			name2content[name] = old_get_content_id(name)
		end
	end
end

if core.set_read_node and core.set_push_node then
	local function read_node(node)
		return name2content[node.name], node.param1, node.param2
	end
	core.set_read_node(read_node)
	core.set_read_node = nil

	local function push_node(content, param1, param2)
		return {name = content2name[content], param1 = param1, param2 = param2}
	end
	core.set_push_node(push_node)
	core.set_push_node = nil
end