@@ -35,7 +35,12 @@ core.register_entity(":__builtin:item", {
35
35
itemstring = " " ,
36
36
moving_state = true ,
37
37
slippery_state = false ,
38
+ physical_state = true ,
39
+ -- Item expiry
38
40
age = 0 ,
41
+ -- Pushing item out of solid nodes
42
+ force_out = nil ,
43
+ force_out_start = nil ,
39
44
40
45
set_item = function (self , item )
41
46
local stack = ItemStack (item or self .itemstring )
@@ -131,6 +136,24 @@ core.register_entity(":__builtin:item", {
131
136
return true
132
137
end ,
133
138
139
+ enable_physics = function (self )
140
+ if not self .physical_state then
141
+ self .physical_state = true
142
+ self .object :set_properties ({physical = true })
143
+ self .object :set_velocity ({x = 0 , y = 0 , z = 0 })
144
+ self .object :set_acceleration ({x = 0 , y =- gravity , z = 0 })
145
+ end
146
+ end ,
147
+
148
+ disable_physics = function (self )
149
+ if self .physical_state then
150
+ self .physical_state = false
151
+ self .object :set_properties ({physical = false })
152
+ self .object :set_velocity ({x = 0 , y = 0 , z = 0 })
153
+ self .object :set_acceleration ({x = 0 , y = 0 , z = 0 })
154
+ end
155
+ end ,
156
+
134
157
on_step = function (self , dtime )
135
158
self .age = self .age + dtime
136
159
if time_to_live > 0 and self .age > time_to_live then
@@ -152,6 +175,74 @@ core.register_entity(":__builtin:item", {
152
175
return
153
176
end
154
177
178
+ local is_stuck = false
179
+ local snode = core .get_node_or_nil (pos )
180
+ if snode then
181
+ local sdef = core .registered_nodes [snode .name ] or {}
182
+ is_stuck = (sdef .walkable == nil or sdef .walkable == true )
183
+ and (sdef .collision_box == nil or sdef .collision_box .type == " regular" )
184
+ and (sdef .node_box == nil or sdef .node_box .type == " regular" )
185
+ end
186
+
187
+ -- Push item out when stuck inside solid node
188
+ if is_stuck then
189
+ local shootdir
190
+ local order = {
191
+ {x = 1 , y = 0 , z = 0 }, {x =- 1 , y = 0 , z = 0 },
192
+ {x = 0 , y = 0 , z = 1 }, {x = 0 , y = 0 , z =- 1 },
193
+ }
194
+
195
+ -- Check which one of the 4 sides is free
196
+ for o = 1 , # order do
197
+ local cnode = core .get_node (vector .add (pos , order [o ])).name
198
+ local cdef = core .registered_nodes [cnode ] or {}
199
+ if cnode ~= " ignore" and cdef .walkable == false then
200
+ shootdir = order [o ]
201
+ break
202
+ end
203
+ end
204
+ -- If none of the 4 sides is free, check upwards
205
+ if not shootdir then
206
+ shootdir = {x = 0 , y = 1 , z = 0 }
207
+ local cnode = core .get_node (vector .add (pos , shootdir )).name
208
+ if cnode == " ignore" then
209
+ shootdir = nil -- Do not push into ignore
210
+ end
211
+ end
212
+
213
+ if shootdir then
214
+ -- Set new item moving speed accordingly
215
+ local newv = vector .multiply (shootdir , 3 )
216
+ self :disable_physics ()
217
+ self .object :set_velocity (newv )
218
+
219
+ self .force_out = newv
220
+ self .force_out_start = vector .round (pos )
221
+ return
222
+ end
223
+ elseif self .force_out then
224
+ -- This code runs after the entity got a push from the above code.
225
+ -- It makes sure the entity is entirely outside the solid node
226
+ local c = self .object :get_properties ().collisionbox
227
+ local s = self .force_out_start
228
+ local f = self .force_out
229
+ local ok = (f .x > 0 and pos .x + c [1 ] > s .x + 0.5 ) or
230
+ (f .y > 0 and pos .y + c [2 ] > s .y + 0.5 ) or
231
+ (f .z > 0 and pos .z + c [3 ] > s .z + 0.5 ) or
232
+ (f .x < 0 and pos .x + c [4 ] < s .x - 0.5 ) or
233
+ (f .z < 0 and pos .z + c [6 ] < s .z - 0.5 )
234
+ if ok then
235
+ -- Item was successfully forced out
236
+ self .force_out = nil
237
+ self :enable_physics ()
238
+ end
239
+ end
240
+
241
+ if not self .physical_state then
242
+ return -- Don't do anything
243
+ end
244
+
245
+ -- Slide on slippery nodes
155
246
local vel = self .object :get_velocity ()
156
247
local def = node and core .registered_nodes [node .name ]
157
248
local is_moving = (def and not def .walkable ) or
0 commit comments