@@ -30,6 +30,8 @@ local facedir_to_euler = {
30
30
{y = math.pi / 2 , x = math.pi , z = 0 }
31
31
}
32
32
33
+ local gravity = tonumber (core .settings :get (" movement_gravity" )) or 9.81
34
+
33
35
--
34
36
-- Falling stuff
35
37
--
@@ -47,6 +49,7 @@ core.register_entity(":__builtin:falling_node", {
47
49
48
50
node = {},
49
51
meta = {},
52
+ floats = false ,
50
53
51
54
set_node = function (self , node , meta )
52
55
self .node = node
@@ -71,6 +74,11 @@ core.register_entity(":__builtin:falling_node", {
71
74
return
72
75
end
73
76
self .meta = meta
77
+
78
+ -- Cache whether we're supposed to float on water
79
+ self .floats = core .get_item_group (node .name , " float" ) ~= 0
80
+
81
+ -- Set entity visuals
74
82
if def .drawtype == " torchlike" or def .drawtype == " signlike" then
75
83
local textures
76
84
if def .tiles and def .tiles [1 ] then
@@ -113,6 +121,7 @@ core.register_entity(":__builtin:falling_node", {
113
121
glow = def .light_source ,
114
122
})
115
123
end
124
+
116
125
-- Rotate entity
117
126
if def .drawtype == " torchlike" then
118
127
self .object :set_yaw (math.pi * 0.25 )
@@ -172,6 +181,7 @@ core.register_entity(":__builtin:falling_node", {
172
181
173
182
on_activate = function (self , staticdata )
174
183
self .object :set_armor_groups ({immortal = 1 })
184
+ self .object :set_acceleration ({x = 0 , y = - gravity , z = 0 })
175
185
176
186
local ds = core .deserialize (staticdata )
177
187
if ds and ds .node then
@@ -183,85 +193,137 @@ core.register_entity(":__builtin:falling_node", {
183
193
end
184
194
end ,
185
195
186
- on_step = function (self , dtime )
187
- -- Set gravity
188
- local acceleration = self .object :get_acceleration ()
189
- if not vector .equals (acceleration , {x = 0 , y = - 10 , z = 0 }) then
190
- self .object :set_acceleration ({x = 0 , y = - 10 , z = 0 })
196
+ try_place = function (self , bcp , bcn )
197
+ local bcd = core .registered_nodes [bcn .name ]
198
+ -- Add levels if dropped on same leveled node
199
+ if bcd and bcd .leveled and
200
+ bcn .name == self .node .name then
201
+ local addlevel = self .node .level
202
+ if not addlevel or addlevel <= 0 then
203
+ addlevel = bcd .leveled
204
+ end
205
+ if core .add_node_level (bcp , addlevel ) == 0 then
206
+ return true
207
+ end
191
208
end
192
- -- Turn to actual node when colliding with ground, or continue to move
193
- local pos = self .object :get_pos ()
194
- -- Position of bottom center point
195
- local bcp = {x = pos .x , y = pos .y - 0.7 , z = pos .z }
196
- -- 'bcn' is nil for unloaded nodes
197
- local bcn = core .get_node_or_nil (bcp )
198
- -- Delete on contact with ignore at world edges
199
- if bcn and bcn .name == " ignore" then
200
- self .object :remove ()
201
- return
209
+
210
+ -- Decide if we're replacing the node or placing on top
211
+ local np = vector .new (bcp )
212
+ if bcd and bcd .buildable_to and
213
+ (not self .floats or bcd .liquidtype == " none" ) then
214
+ core .remove_node (bcp )
215
+ else
216
+ np .y = np .y + 1
202
217
end
203
- local bcd = bcn and core .registered_nodes [bcn .name ]
204
- if bcn and
205
- (not bcd or bcd .walkable or
206
- (core .get_item_group (self .node .name , " float" ) ~= 0 and
207
- bcd .liquidtype ~= " none" )) then
208
- if bcd and bcd .leveled and
209
- bcn .name == self .node .name then
210
- local addlevel = self .node .level
211
- if not addlevel or addlevel <= 0 then
212
- addlevel = bcd .leveled
218
+
219
+ -- Check what's here
220
+ local n2 = core .get_node (np )
221
+ local nd = core .registered_nodes [n2 .name ]
222
+ -- If it's not air or liquid, remove node and replace it with
223
+ -- it's drops
224
+ if n2 .name ~= " air" and (not nd or nd .liquidtype == " none" ) then
225
+ if nd and nd .buildable_to == false then
226
+ nd .on_dig (np , n2 , nil )
227
+ -- If it's still there, it might be protected
228
+ if core .get_node (np ).name == n2 .name then
229
+ return false
213
230
end
214
- if core .add_node_level (bcp , addlevel ) == 0 then
231
+ else
232
+ core .remove_node (np )
233
+ end
234
+ end
235
+
236
+ -- Create node
237
+ local def = core .registered_nodes [self .node .name ]
238
+ if def then
239
+ core .add_node (np , self .node )
240
+ if self .meta then
241
+ core .get_meta (np ):from_table (self .meta )
242
+ end
243
+ if def .sounds and def .sounds .place then
244
+ core .sound_play (def .sounds .place , {pos = np }, true )
245
+ end
246
+ end
247
+ core .check_for_falling (np )
248
+ return true
249
+ end ,
250
+
251
+ on_step = function (self , dtime , moveresult )
252
+ -- Fallback code since collision detection can't tell us
253
+ -- about liquids (which do not collide)
254
+ if self .floats then
255
+ local pos = self .object :get_pos ()
256
+
257
+ local bcp = vector .round ({x = pos .x , y = pos .y - 0.7 , z = pos .z })
258
+ local bcn = core .get_node (bcp )
259
+
260
+ local bcd = core .registered_nodes [bcn .name ]
261
+ if bcd and bcd .liquidtype ~= " none" then
262
+ if self :try_place (bcp , bcn ) then
215
263
self .object :remove ()
216
264
return
217
265
end
218
- elseif bcd and bcd .buildable_to and
219
- (core .get_item_group (self .node .name , " float" ) == 0 or
220
- bcd .liquidtype == " none" ) then
221
- core .remove_node (bcp )
222
- return
223
266
end
224
- local np = {x = bcp .x , y = bcp .y + 1 , z = bcp .z }
225
- -- Check what's here
226
- local n2 = core .get_node (np )
227
- local nd = core .registered_nodes [n2 .name ]
228
- -- If it's not air or liquid, remove node and replace it with
229
- -- it's drops
230
- if n2 .name ~= " air" and (not nd or nd .liquidtype == " none" ) then
231
- core .remove_node (np )
232
- if nd and nd .buildable_to == false then
233
- -- Add dropped items
234
- local drops = core .get_node_drops (n2 , " " )
235
- for _ , dropped_item in pairs (drops ) do
236
- core .add_item (np , dropped_item )
237
- end
238
- end
239
- -- Run script hook
240
- for _ , callback in pairs (core .registered_on_dignodes ) do
241
- callback (np , n2 )
242
- end
243
- end
244
- -- Create node and remove entity
245
- local def = core .registered_nodes [self .node .name ]
246
- if def then
247
- core .add_node (np , self .node )
248
- if self .meta then
249
- local meta = core .get_meta (np )
250
- meta :from_table (self .meta )
251
- end
252
- if def .sounds and def .sounds .place then
253
- core .sound_play (def .sounds .place , {pos = np }, true )
267
+ end
268
+
269
+ assert (moveresult )
270
+ if not moveresult .collides then
271
+ return -- Nothing to do :)
272
+ end
273
+
274
+ local bcp , bcn
275
+ if moveresult .touching_ground then
276
+ for _ , info in ipairs (moveresult .collisions ) do
277
+ if info .axis == " y" then
278
+ bcp = info .node_pos
279
+ bcn = core .get_node (bcp )
280
+ break
254
281
end
255
282
end
283
+ end
284
+
285
+ if not bcp then
286
+ -- We're colliding with something, but not the ground. Irrelevant to us.
287
+ return
288
+ elseif bcn .name == " ignore" then
289
+ -- Delete on contact with ignore at world edges
256
290
self .object :remove ()
257
- core .check_for_falling (np )
258
291
return
259
292
end
260
- local vel = self .object :get_velocity ()
261
- if vector .equals (vel , {x = 0 , y = 0 , z = 0 }) then
262
- local npos = self .object :get_pos ()
263
- self .object :set_pos (vector .round (npos ))
293
+
294
+ local failure = false
295
+
296
+ local pos = self .object :get_pos ()
297
+ local distance = vector .apply (vector .subtract (pos , bcp ), math.abs )
298
+ if distance .x >= 1 or distance .z >= 1 then
299
+ -- We're colliding with some part of a node that's sticking out
300
+ -- Since we don't want to visually teleport, drop as item
301
+ failure = true
302
+ elseif distance .y >= 2 then
303
+ -- Doors consist of a hidden top node and a bottom node that is
304
+ -- the actual door. Despite the top node being solid, the moveresult
305
+ -- almost always indicates collision with the bottom node.
306
+ -- Compensate for this by checking the top node
307
+ bcp .y = bcp .y + 1
308
+ bcn = core .get_node (bcp )
309
+ local def = core .registered_nodes [bcn .name ]
310
+ if not (def and def .walkable ) then
311
+ failure = true -- This is unexpected, fail
312
+ end
313
+ end
314
+
315
+ -- Try to actually place ourselves
316
+ if not failure then
317
+ failure = not self :try_place (bcp , bcn )
318
+ end
319
+
320
+ if failure then
321
+ local drops = core .get_node_drops (self .node , " " )
322
+ for _ , item in pairs (drops ) do
323
+ core .add_item (pos , item )
324
+ end
264
325
end
326
+ self .object :remove ()
265
327
end
266
328
})
267
329
0 commit comments