Add cart entity respawn/destroy to match cart data (partially working)

This commit is contained in:
teknomunk 2024-04-07 12:27:53 +00:00
parent a0afbff984
commit 92a1c375e9
4 changed files with 105 additions and 3 deletions

View File

@ -6,11 +6,13 @@ local S = minetest.get_translator(modname)
local mcl_log = mcl_util.make_mcl_logger("mcl_logging_minecarts", "Minecarts")
-- Imports
local CART_BLOCK_SIZE = mod.CART_BLOCK_SIZE
local table_merge = mcl_util.table_merge
local get_cart_data = mod.get_cart_data
local save_cart_data = mod.save_cart_data
local update_cart_data = mod.update_cart_data
local destroy_cart_data = mod.destroy_cart_data
local find_carts_by_block_map = mod.find_carts_by_block_map
local do_movement,do_detached_movement,handle_cart_enter = dofile(modpath.."/movement.lua")
assert(do_movement)
assert(do_detached_movement)
@ -165,9 +167,15 @@ function DEFAULT_CART_DEF:on_step(dtime)
self._staticdata = staticdata
end
-- Repair cart_type
if not staticdata.cart_type then
staticdata.cart_type = self.name
end
if self._seq ~= staticdata.seq then
print("TODO: remove cart #"..staticdata.uuid.." with sequence number mismatch")
print("self.seq="..tostring(self._seq)..", staticdata.seq="..tostring(staticdata.seq))
print("removing cart #"..staticdata.uuid.." with sequence number mismatch")
self.object:remove()
return
end
-- Regen
@ -309,6 +317,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
local uuid = mcl_util.get_uuid(cart)
data = make_staticdata( railtype, railpos, cart_dir )
data.uuid = uuid
data.cart_type = entity_id
update_cart_data(data)
le._staticdata = data
save_cart_data(le._staticdata.uuid)
@ -447,7 +456,67 @@ if minetest.get_modpath("mcl_wip") then
mcl_wip.register_wip_item("mcl_minecarts:command_block_minecart")
end
local function respawn_cart(cart)
local cart_type = cart.cart_type or "mcl_minecarts:minecart"
local pos = mod.get_cart_position(cart)
print("Respawning cart #"..cart.uuid.." at "..tostring(pos))
-- Update sequence so that old cart entities get removed
cart.seq = (cart.seq or 1) + 1
save_cart_data(cart.uuid)
-- Create the new entity
local entity = minetest.add_entity(pos, cart_type)
local le = entity:get_luaentity()
le._seq = cart.seq
le._uuid = cart.uuid
le._staticdata = cart
-- We intentionally don't call the normal hooks because this minecart was already there
end
-- Try to respawn cart entities for carts that have moved into range of a player
local function try_respawn_carts()
-- Build a map of blocks near players
local block_map = {}
local players = minetest.get_connected_players()
for _,player in pairs(players) do
local pos = player:get_pos()
local min = vector.floor(vector.divide(vector.offset(pos,-CART_BLOCK_SIZE,-CART_BLOCK_SIZE,-CART_BLOCK_SIZE), CART_BLOCK_SIZE))
local max = vector.floor(vector.divide(vector.offset(pos, CART_BLOCK_SIZE, CART_BLOCK_SIZE, CART_BLOCK_SIZE), CART_BLOCK_SIZE)) + vector.new(1,1,1)
for z = min.z,max.z do
for y = min.y,max.y do
for x = min.x,min.x do
block_map[ vector.to_string(vector.new(x,y,z)) ] = true
end
end
end
end
-- Find all cart data that are in these blocks
local carts = find_carts_by_block_map(block_map)
-- Check to see if any of these don't have an entity
for _,cart in pairs(carts) do
local le = mcl_util.get_luaentity_from_uuid(cart.uuid)
if not le then
respawn_cart(cart)
end
end
end
local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer - dtime
if timer <= 0 then
local start_time = minetest.get_us_time()
try_respawn_carts()
local stop_time = minetest.get_us_time()
local duration = (stop_time - start_time) / 1e6
timer = duration / 50e-6 -- Schedule 50us per second
--print("Took "..tostring(duration).." seconds, rescheduling for "..tostring(timer).." seconds in the future")
end
-- TODO: handle periodically updating out-of-range carts
end)

View File

@ -356,4 +356,10 @@ function mcl_minecarts:update_cart_orientation()
self.object:set_rotation(rot)
end
function mod.get_cart_position(cart_staticdata)
local data = cart_staticdata
if not data.connected_at then return end
return vector.add(data.connected_at, vector.multiply(data.dir or vector.zero(), data.distance or 0))
end

View File

@ -9,6 +9,7 @@ mod.speed_max = 10
mod.check_float_time = 15
mod.FRICTION = 0.4
mod.MAX_TRAIN_LENGTH = 4
mod.CART_BLOCK_SIZE = 64
for _,filename in pairs({"storage","functions","rails","train","carts"}) do
dofile(modpath.."/"..filename..".lua")

View File

@ -1,10 +1,14 @@
local storage = minetest.get_mod_storage()
local mod = mcl_minecarts
-- Imports
local CART_BLOCK_SIZE = mod.CART_BLOCK_SIZE
local cart_data = {}
local cart_data_fail_cache = {}
local cart_ids = storage:get_keys()
function mod.get_cart_data(uuid)
local function get_cart_data(uuid)
if cart_data[uuid] then return cart_data[uuid] end
if cart_data_fail_cache[uuid] then return nil end
@ -17,6 +21,14 @@ function mod.get_cart_data(uuid)
cart_data[uuid] = data
return data
end
mod.get_cart_data = get_cart_data
-- Preload all cart data into memory
for _,id in pairs(cart_ids) do
local uuid = string.sub(id,6)
get_cart_data(uuid)
end
local function save_cart_data(uuid)
if not cart_data[uuid] then return end
storage:set_string("cart-"..uuid,minetest.serialize(cart_data[uuid]))
@ -35,3 +47,17 @@ function mod.destroy_cart_data(uuid)
cart_data_fail_cache[uuid] = true
end
function mod.find_carts_by_block_map(block_map)
local cart_list = {}
for _,data in pairs(cart_data) do
if data and data.connected_at then
local pos = mod.get_cart_position(data)
local block = vector.floor(vector.divide(pos,CART_BLOCK_SIZE))
if block_map[vector.to_string(block)] then
cart_list[#cart_list + 1] = data
end
end
end
return cart_list
end