From 49ef40aa3c4cb2ec427bd032d7cacaaf5847a416 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Wed, 10 Apr 2024 22:22:17 +0000 Subject: [PATCH] Correct crashes/item duplication with dropping carts, start API documentation --- mods/ENTITIES/mcl_minecarts/API.md | 44 +++++++++++++++ mods/ENTITIES/mcl_minecarts/carts.lua | 69 +++++++++++++++--------- mods/ENTITIES/mcl_minecarts/movement.lua | 4 +- 3 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 mods/ENTITIES/mcl_minecarts/API.md diff --git a/mods/ENTITIES/mcl_minecarts/API.md b/mods/ENTITIES/mcl_minecarts/API.md new file mode 100644 index 000000000..88794b1ba --- /dev/null +++ b/mods/ENTITIES/mcl_minecarts/API.md @@ -0,0 +1,44 @@ +== Cart-Node interactions + +As the cart moves thru the environment, it can interact with the surrounding blocks +thru a number of handlers in the block definitions. All these handlers are defined +as: + +`function(node_position, cart_luaentity, cart_direction, cart_position)` + +Arguments: +`node_position` - position of the node the cart is interacting with +`cart_luaentity` - The luaentity of the cart that is entering this block. Will + be nil for minecarts moving thru unloaded blocks +`cart_direction` - The direction the cart is moving +`cart_position` - The location of the cart +`cart_data` - Information about the cart. This will always be defined. + +There are several variants of this handler: +`_mcl_minecarts_on_enter` - The cart enters this block +`_mcl_minecarts_on_enter_below` - The cart enters above this block +`_mcl_minecarts_on_enter_above` - The cart enters below this block +`_mcl_minecarts_on_enter_side` - The cart enters beside this block + +Mods can also define global handlers that are called for every node. These +handlers are defined as: + +`function(node_position, cart_luaentity, cart_direction, node_definition, cart_data)` + +Arguments: +`node_position` - position of the node the cart is interacting with +`cart_luaentity` - The luaentity of the cart that is entering this block. Will + be nil for minecarts moving thru unloaded blocks +`cart_direction` - The direction the cart is moving +`cart_position` - The location of the cart +`cart_data` - Information about the cart. This will always be defined. +`node_definition` - The definition of the node at `node_position` + +The available hooks are: +`_mcl_minecarts.on_enter` - The cart enters this block +`_mcl_minecarts.on_enter_below` - The cart enters above this block +`_mcl_minecarts.on_enter_above` - The cart enters below this block +`_mcl_minecarts.on_enter_side` - The cart enters beside this block + +Only a single function can be installed in each of these handlers. Before installing, +preserve the existing handler and call it from inside your handler if not `nil`. diff --git a/mods/ENTITIES/mcl_minecarts/carts.lua b/mods/ENTITIES/mcl_minecarts/carts.lua index dce5124d3..846ba7058 100644 --- a/mods/ENTITIES/mcl_minecarts/carts.lua +++ b/mods/ENTITIES/mcl_minecarts/carts.lua @@ -249,18 +249,10 @@ function DEFAULT_CART_DEF:on_step(dtime) mod.update_cart_orientation(self) end -function DEFAULT_CART_DEF:on_death(killer) - local staticdata = self._staticdata +local function kill_cart(staticdata) + local pos minetest.log("action", "cart #"..staticdata.uuid.." was killed") - detach_driver(self) - - -- Detach passenger - if self._passenger then - local mob = self._passenger.object - mob:set_detach() - end - -- Leave nodes if staticdata.attached_at then handle_cart_leave(self, staticdata.attached_at, staticdata.dir ) @@ -268,23 +260,42 @@ function DEFAULT_CART_DEF:on_death(killer) mcl_log("TODO: handle detatched minecart death") end + -- Handle entity-related items + local le = mcl_util.get_luaentity_from_uuid(staticdata.uuid) + if le then + pos = le.object:get_pos() + + detach_driver(le) + + -- Detach passenger + if le._passenger then + local mob = le._passenger.object + mob:set_detach() + end + else + pos = mod.get_cart_position(staticdata) + end + + -- Drop items + if not staticdata.dropped then + local entity_def = minetest.registered_entities[staticdata.cart_type] + if entity_def then + local drop = entity_def.drop + for d=1, #drop do + minetest.add_item(pos, drop[d]) + end + + -- Prevent item duplication + staticdata.dropped = true + end + end + -- Remove data destroy_cart_data(staticdata.uuid) - -- Drop items - local drop = self.drop - if not killer or not minetest.is_creative_enabled(killer:get_player_name()) then - for d=1, #drop do - minetest.add_item(self.object:get_pos(), drop[d]) - end - elseif killer and killer:is_player() then - local inv = killer:get_inventory() - for d=1, #drop do - if not inv:contains_item("main", drop[d]) then - inv:add_item("main", drop[d]) - end - end - end +end +function DEFAULT_CART_DEF:on_death(killer) + kill_cart(self._staticdata) end -- Place a minecart at pointed_thing @@ -558,8 +569,14 @@ minetest.register_globalstep(function(dtime) local r = 0.6 for _, node_pos in pairs({{r, 0}, {0, r}, {-r, 0}, {0, -r}}) do if minetest.get_node(vector.offset(pos, node_pos[1], 0, node_pos[2])).name == "mcl_core:cactus" then - self:on_death() - self.object:remove() + kill_cart(staticdata) + local le = mcl_util.get_luaentity_from_uuid(staticdata.uuid) + if le then + le:on_death() + le.object:remove() + else + kill_cart(staticdata) + end return end end diff --git a/mods/ENTITIES/mcl_minecarts/movement.lua b/mods/ENTITIES/mcl_minecarts/movement.lua index a0b053a2a..31e95a4e9 100644 --- a/mods/ENTITIES/mcl_minecarts/movement.lua +++ b/mods/ENTITIES/mcl_minecarts/movement.lua @@ -62,11 +62,11 @@ local function handle_cart_enter_exit(staticdata, pos, next_dir, event) -- node-specific hook local hook_name = "_mcl_minecarts_"..event..check[4] local hook = node_def[hook_name] - if hook then hook(check_pos, luaentity, next_dir, pos) end + if hook then hook(check_pos, luaentity, next_dir, pos, staticdata) end -- global minecart hook hook = mcl_minecarts[event..check[4]] - if hook then hook(check_pos, luaentity, next_dir, node_def) end + if hook then hook(check_pos, luaentity, next_dir, pos, staticdata, node_def) end end end