Fix cart reproduction bugs

master
Joachim Stolberg 2021-10-19 21:37:08 +02:00
parent 6812c99ade
commit b771ffcc6b
9 changed files with 97 additions and 72 deletions

View File

@ -149,6 +149,7 @@ History
2020-07-24 V1.08 Adapted to new techage ICTA style
2020-08-14 V1.09 Hopper support for digtron, protector:chest and default:furnace added
2020-11-12 V1.10 Make carts more robust against server lag
2021-04-10 V2.00 Complete revision to make carts robust against server load/lag,
Speed limit signs and cart terminal added
2021-09-02 V2.01 Chat command /stopcart added
2021-04-10 V2.00 Complete revision to make carts robust against server load/lag,
Speed limit signs and cart terminal added
2021-09-02 V2.01 Chat command /stopcart added
2021-10-18 V2.02 Cart reproduction bug fixed

View File

@ -257,9 +257,6 @@ function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID)
pos2 = minetest.find_node_near(pos, 1, minecart.lRails)
if not pos2 or not minecart.is_rail(pos2) then
pos2 = minetest.find_node_near(pos, 2, minecart.lRails)
if not pos2 or not minecart.is_rail(pos2) then
pos2 = minetest.find_node_near(pos, 2, {"air"})
end
end
else
pos2 = vector.new(pos)
@ -282,8 +279,6 @@ function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID)
ndef.after_place_node(pos2)
end
return pos2
else
minetest.add_item(pos, ItemStack({name = node_name}))
end
end
end
@ -363,10 +358,13 @@ function minecart.entity_to_node(pos, entity)
local dir = minetest.yaw_to_dir(rot.y)
local facedir = minetest.dir_to_facedir(dir)
minecart.stop_recording(entity, pos)
entity.object:remove()
local pos2 = minecart.add_nodecart(pos, entity.node_name, facedir, entity.cargo, entity.owner, entity.userID)
minecart.stop_monitoring(entity.owner, entity.userID, pos2)
minecart.monitoring_remove_cart(entity.owner, entity.userID)
if pos2 then
minecart.stop_monitoring(entity.owner, entity.userID, pos2)
entity.object:remove()
else
minecart.start_entitycart(entity, pos, facedir)
end
end
function minecart.add_node_to_player_inventory(pos, player, node_name)
@ -389,9 +387,10 @@ function minecart.remove_entity(self, pos, player)
minetest.sound_stop(self.sound_handle)
self.sound_handle = nil
end
minecart.add_node_to_player_inventory(pos, player, self.node_name or "minecart:cart")
if player then
minecart.add_node_to_player_inventory(pos, player, self.node_name or "minecart:cart")
end
minecart.stop_monitoring(self.owner, self.userID, pos)
minecart.stop_recording(self, pos)
minecart.monitoring_remove_cart(self.owner, self.userID)
self.object:remove()
end

View File

@ -159,13 +159,16 @@ minetest.register_craft({
})
minetest.register_lbm({
label = "Delete waiting times",
name = "minecart:del_time",
label = "Delete metadata",
name = "minecart:metadata",
nodenames = {"minecart:buffer"},
run_at_every_load = false,
run_at_every_load = true,
action = function(pos, node)
-- delete old data
minecart.get_route(pos)
M(pos):set_string("formspec", formspec(pos))
-- delete old metadata around the buffer (bugfix)
local pos1 = {x = pos.x - 2, y = pos.y - 2, z = pos.z - 2}
local pos2 = {x = pos.x + 2, y = pos.y + 2, z = pos.z + 2}
for _, pos in ipairs(minetest.find_nodes_with_meta(pos1, pos2)) do
minecart.del_metadata(pos)
end
end,
})

View File

@ -186,7 +186,7 @@ local function play_sound(self)
if self.object then
self.sound_handle = minetest.sound_play(
"carts_cart_moving", {
object = self.object,
pos = self.object:get_pos(),
gain = (self.curr_speed or 0) / MAX_SPEED,
})
end

View File

@ -13,7 +13,7 @@
minecart = {}
-- Version for compatibility checks, see readme.md/history
minecart.version = 2.01
minecart.version = 2.02
minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false
minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") == true
@ -35,7 +35,7 @@ dofile(MP .. "/api.lua")
dofile(MP .. "/minecart.lua")
dofile(MP .. "/buffer.lua")
dofile(MP .. "/protection.lua")
--dofile(MP .. "/tool.lua") # for debugging only
--dofile(MP .. "/tool.lua") -- for debugging only
dofile(MP .. "/signs.lua")
dofile(MP .. "/terminal.lua")
dofile(MP .. "/pusher.lua")

View File

@ -68,9 +68,6 @@ local function get_checkpoint(cart)
cp = cart.checkpoints[cart.idx]
end
local pos = H2P(cp[1])
-- if M(pos):contains("waypoints") then
-- print("get_checkpoint", P2S(H2P(cp[1])), P2S(H2P(cp[2])))
-- end
return cp, cart.idx == #cart.checkpoints
end
@ -103,21 +100,41 @@ local function get_cart_info(owner, userID, query_pos)
end
end
local function logging(cart, err)
local s = string.format("[Minecart] Cart %s/%u %s!", cart.owner, cart.userID, err)
minetest.log("warning", s)
end
-- check cart data
local function valid_cart(cart)
if cart.objID == nil or cart.objID == 0 then
return false
end
if tCartsOnRail[cart.owner] and tCartsOnRail[cart.owner][cart.userID] then
return true
end
logging(cart, "with invalid data")
local entity = minetest.luaentities[cart.objID]
if entity then
entity.object:remove()
end
return false
end
local function monitoring(cycle)
local cart = pop(cycle)
-- All running cars
while cart do
-- All running cars
if cart.objID and cart.objID ~= 0 then
if valid_cart(cart) then
cart.idx = cart.idx + 1
local entity = minetest.luaentities[cart.objID]
if entity then -- cart entity running
local pos = entity.object:get_pos()
if pos then
cart.last_pos = vector.round(pos)
--print("entity card " .. cart.userID .. " at " .. P2S(cart.last_pos))
else
minetest.log("warning", "[Minecart] entity card without pos!")
logging(cart, "without pos")
end
push(cycle, cart)
elseif cart.checkpoints then
@ -130,16 +147,15 @@ local function monitoring(cycle)
end
push(cycle, cart)
else
minetest.log("warning", "[Minecart] zombie got lost")
logging(cart, "as zombie got lost")
end
else
local pos = cart.last_pos or cart.pos
pos = minecart.add_nodecart(pos, cart.node_name, 0, cart.cargo, cart.owner, cart.userID)
cart.objID = 0
cart.pos = pos
--print("cart to node", cycle, cart.userID, P2S(pos))
minecart.stop_monitoring(cart.owner, cart.userID, pos)
logging(cart, "stopped at " .. P2S(pos))
end
elseif cart and not cart.objID and tCartsOnRail[cart.owner] then
elseif not cart.objID and tCartsOnRail[cart.owner] then
-- Delete carts marked as "to be deleted"
tCartsOnRail[cart.owner][cart.userID] = nil
end
@ -184,6 +200,7 @@ function minecart.stop_monitoring(owner, userID, pos)
--print("stop_monitoring", owner, userID)
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then
tCartsOnRail[owner][userID].pos = pos
-- Mark as "stopped"
tCartsOnRail[owner][userID].objID = 0
minecart.store_carts()
end
@ -192,14 +209,20 @@ end
function minecart.monitoring_remove_cart(owner, userID)
--print("monitoring_remove_cart", owner, userID)
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then
tCartsOnRail[owner][userID].objID = nil
tCartsOnRail[owner][userID] = nil
-- Cart stopped?
if tCartsOnRail[owner][userID].objID == 0 then
-- Can directly be deleted
tCartsOnRail[owner][userID] = nil
else -- Cart running
-- Mark as "to be deleted" by monitoring
tCartsOnRail[owner][userID].objID = nil
end
minecart.store_carts()
end
end
function minecart.monitoring_valid_cart(owner, userID, pos, node_name)
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] and tCartsOnRail[owner][userID].pos then
return vector.equals(tCartsOnRail[owner][userID].pos, pos) and
tCartsOnRail[owner][userID].node_name == node_name
end
@ -245,28 +268,38 @@ minetest.register_chatcommand("mycart", {
minetest.register_chatcommand("stopcart", {
params = "<cart-num>",
description = S("Stop amd return a missing/running cart."),
description = S("Stop and return/drop a missing/running cart."),
func = function(owner, param)
local userID = tonumber(param)
local player_pos = minetest.get_player_by_name(owner):get_pos()
if userID then
local data = minecart.get_cart_monitoring_data(owner, userID)
if data then
if data.objID and data.objID ~= 0 then
local entity = minetest.luaentities[data.objID]
if entity then -- cart entity running
minecart.entity_to_node(player_pos, entity)
if data and data.objID then
local entity = minetest.luaentities[data.objID]
--print("stopcart", userID, data.pos, data.objID, entity)
if data.objID == 0 then
-- Cart as node
if data.pos then
local meta = M(data.pos)
if owner == meta:get_string("owner") and userID == meta:get_int("userID") then
minecart.remove_nodecart(data.pos)
end
end
elseif entity then
-- Cart as entity
minecart.remove_entity(entity, data.pos)
else
local pos = data.last_pos or data.pos
local cargo, _, _ = minecart.remove_nodecart(pos)
minecart.add_nodecart(player_pos, data.node_name, 0, cargo, owner, userID)
minecart.monitoring_remove_cart(owner, userID)
-- Cart as zombie/invalid/corrupted
-- nothing to do
end
return true, S("Cart") .. " " .. userID .. " " .. S("stopped")
minetest.add_item(player_pos, ItemStack({name = data.node_name}))
minecart.monitoring_remove_cart(owner, userID)
return true, S("Cart") .. " " .. userID .. " " .. S("dropped")
else
return false, S("Cart") .. " " .. userID .. " " .. S("is not existing!")
end
else
return false
end
end
})

View File

@ -585,6 +585,9 @@ end
-- minecart.get_next_buffer(pos, facedir)
minecart.get_next_buffer = get_next_buffer
-- minecart.del_metadata(pos)
minecart.del_metadata = del_metadata
--minetest.register_lbm({
-- label = "Delete waypoints",
-- name = "minecart:del_meta",

View File

@ -50,30 +50,15 @@ minetest.register_on_mods_loaded(function()
else
local t = minetest.deserialize(storage:get_string("CartsOnRail")) or {}
for owner, carts in pairs(t) do
minecart.CartsOnRail[owner] = {}
minecart.CartsOnRail[owner] = minecart.CartsOnRail[owner] or {}
for userID, cart in pairs(carts) do
print("reload cart", owner, userID, cart.objID)
minecart.CartsOnRail[owner][userID] = cart
-- mark all entity carts as zombified
if cart.objID and cart.objID ~= 0 then
cart.objID = -1
minecart.push(1, cart)
end
end
end
end
end)
minetest.after(10, function()
for owner, carts in pairs(minecart.CartsOnRail) do
for userID, cart in pairs(carts) do
-- Remove node carts that are not available anymore
if cart.pos and (cart.objID == 0 or not cart.objID) then
local node = minecart.get_node_lvm(cart.pos)
if not minecart.tNodeNames[node.name] then
-- Mark as "to be deleted"
print("Node cart deleted", owner, userID)
minecart.CartsOnRail[owner][userID] = nil
if cart.objID then
minecart.CartsOnRail[owner][userID] = cart
-- mark all entity carts as zombified
if cart.objID ~= 0 then
cart.objID = -1
minecart.push(1, cart)
end
end
end
end

View File

@ -78,7 +78,8 @@ local function click_left(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" then
local pos = pointed_thing.under
if minecart.is_rail(pos) then
test_get_buffer(pos, placer)
--test_get_buffer(pos, placer)
minecart.delete_waypoint(pos)
end
end
end