Implement offline/out of range minecart movement and fix minecart respawning, remove railtype tracking

This commit is contained in:
teknomunk 2024-04-09 20:52:11 +00:00
parent a4987f63e9
commit 15c13b7bb3
4 changed files with 80 additions and 67 deletions

View File

@ -68,9 +68,8 @@ end
-- Table for item-to-entity mapping. Keys: itemstring, Values: Corresponding entity ID
local entity_mapping = {}
local function make_staticdata( railtype, connected_at, dir )
local function make_staticdata( _, connected_at, dir )
return {
railtype = railtype,
connected_at = connected_at,
distance = 0,
velocity = 0,
@ -122,12 +121,6 @@ function DEFAULT_CART_DEF:on_activate(staticdata, dtime_s)
-- Initialize
if type(data) == "table" then
-- Migrate old data
if data._railtype then
data.railtype = data._railtype
data._railtype = nil
end
-- Fix up types
data.dir = vector.new(data.dir)
@ -194,11 +187,17 @@ function DEFAULT_CART_DEF:on_step(dtime)
self._staticdata = staticdata
end
-- Update entity position
local pos = mod.get_cart_position(staticdata)
if pos then self.object:move_to(pos) end
-- Repair cart_type
if not staticdata.cart_type then
staticdata.cart_type = self.name
end
-- Remove superceded entities
if self._seq ~= staticdata.seq then
print("removing cart #"..staticdata.uuid.." with sequence number mismatch")
self.object:remove()
@ -207,22 +206,11 @@ function DEFAULT_CART_DEF:on_step(dtime)
-- Regen
local hp = self.object:get_hp()
if hp < MINECART_MAX_HP then
if (staticdata.regen_timer or 0) > 0.5 then
hp = hp + 1
staticdata.regen_timer = staticdata.regen_timer - 1
end
staticdata.regen_timer = (staticdata.regen_timer or 0) + dtime
local time_now = minetest.get_gametime()
if hp < MINECART_MAX_HP and staticdata.last_regen <= time_now - 1 then
staticdata.last_regen = time_now
hp = hp + 1
self.object:set_hp(hp)
else
staticdata.regen_timer = nil
end
-- Fix railtype field
local pos = self.object:get_pos()
if staticdata.connected_at and not staticdata.railtype then
local node = minetest.get_node(vector.floor(pos)).name
staticdata.railtype = minetest.get_item_group(node, "connect_to_raillike")
end
-- Cart specific behaviors
@ -256,27 +244,12 @@ function DEFAULT_CART_DEF:on_step(dtime)
end
end
if staticdata.connected_at then
do_movement(staticdata, dtime)
-- Update entity
local pos = mod.get_cart_position(staticdata)
if pos then self.object:move_to(pos) end
mod.update_cart_orientation(self)
else
if not staticdata.connected_at then
do_detached_movement(self, dtime)
end
-- TODO: move this into mcl_core:cactus _mcl_minecarts_on_enter_side
-- Drop minecart if it collides with a cactus node
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()
return
end
end
mod.update_cart_orientation(self)
end
function DEFAULT_CART_DEF:on_death(killer)
local staticdata = self._staticdata
@ -325,7 +298,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
local spawn_pos = pointed_thing.above
local cart_dir = vector.new(1,0,0)
local railtype, railpos, node
local railpos, node
if mcl_minecarts:is_rail(pointed_thing.under) then
railpos = pointed_thing.under
elseif mcl_minecarts:is_rail(pointed_thing.above) then
@ -334,8 +307,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
if railpos then
spawn_pos = railpos
node = minetest.get_node(railpos)
railtype = minetest.get_item_group(node.name, "connect_to_raillike")
cart_dir = mcl_minecarts:get_rail_direction(railpos, vector.new(1,0,0), nil, nil, railtype)
cart_dir = mcl_minecarts:get_rail_direction(railpos, vector.new(1,0,0))
end
local entity_id = entity_mapping[itemstack:get_name()]
@ -343,16 +315,18 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
cart:set_yaw(minetest.dir_to_yaw(cart_dir))
-- Setup cart data
local uuid = mcl_util.get_uuid(cart)
data = make_staticdata( nil, railpos, cart_dir )
data.uuid = uuid
data.cart_type = entity_id
update_cart_data(data)
save_cart_data(uuid)
-- Update static data
local le = cart:get_luaentity()
if le then
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)
end
-- Call placer
@ -361,7 +335,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
end
if railpos then
handle_cart_enter(le, railpos)
handle_cart_enter(data, railpos)
end
local pname = ""
@ -518,7 +492,7 @@ local function try_respawn_carts()
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
for x = min.x,max.x do
block_map[ vector.to_string(vector.new(x,y,z)) ] = true
end
end
@ -545,10 +519,42 @@ minetest.register_globalstep(function(dtime)
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
timer = duration / 250e-6 -- Schedule 50us per second
if timer > 5 then timer = 5 end
--print("Took "..tostring(duration).." seconds, rescheduling for "..tostring(timer).." seconds in the future")
end
-- TODO: handle periodically updating out-of-range carts
-- Handle periodically updating out-of-range carts
-- TODO: change how often cart positions are updated based on velocity
for uuid,staticdata in mod.carts() do
local pos = mod.get_cart_position(staticdata)
local le = mcl_util.get_luaentity_from_uuid(staticdata.uuid)
--[[
print("cart# "..uuid..
",velocity="..tostring(staticdata.velocity)..
",pos="..tostring(pos)..
",le="..tostring(le)..
",connected_at="..tostring(staticdata.connected_at)
)]]
--- Non-entity code
if staticdata.connected_at then
do_movement(staticdata, dtime)
-- TODO: move this into mcl_core:cactus _mcl_minecarts_on_enter_side
-- Drop minecart if it collides with a cactus node
local pos = mod.get_cart_position(staticdata)
if pos then
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()
return
end
end
end
end
end
end)

View File

@ -372,7 +372,7 @@ function mod.reverse_cart_direction(staticdata)
staticdata.distance = 1 - (staticdata.distance or 0)
-- recalculate direction
local next_dir,_ = mod:get_rail_direction(staticdata.connected_at, next_dir, nil, nil, staticdata.railtype)
local next_dir,_ = mod:get_rail_direction(staticdata.connected_at, next_dir)
staticdata.dir = next_dir
end

View File

@ -7,8 +7,8 @@ local S = minetest.get_translator(modname)
local mcl_debug,DEBUG = mcl_util.make_mcl_logger("mcl_logging_minecart_debug", "Minecart Debug")
local friction = mcl_minecarts.FRICTION
local MAX_TRAIN_LENGTH = mod.MAX_TRAIN_LENGTH
DEBUG = true
mcl_debug = function(msg) print(msg) end
--DEBUG = false
--mcl_debug = function(msg) print(msg) end
-- Imports
local train_length = mod.train_length
@ -30,13 +30,9 @@ end
mod.detach_minecart = detach_minecart
local function try_detach_minecart(staticdata)
if not staticdata then return end
-- Don't try to detach if alread detached
if not staticdata.connected_at then return end
local node = minetest.get_node(staticdata.connected_at)
if minetest.get_item_group(node.name, "rail") == 0 then
if not staticdata or not staticdata.connected_at then return end
if not mod:is_rail(staticdata.connected_at) then
print("Detaching minecart"..tostring(staticdata.uuid))
detach_minecart(staticdata)
end
end
@ -77,10 +73,10 @@ local function handle_cart_enter_exit(staticdata, pos, next_dir, event)
-- Handle cart-specific behaviors
if luaentity then
local hook = luaentity["_mcl_minecarts_"..event]
if hook then hook(self, pos) end
else
minetest.log("warning", "TODO: chanve _mcl_minecarts_"..event.." calling so it is not dependent on the existence of a luaentity")
--minetest.log("warning", "TODO: change _mcl_minecarts_"..event.." calling so it is not dependent on the existence of a luaentity")
end
if hook then hook(self, pos) end
end
local function set_metadata_cart_status(pos, uuid, state)
local meta = minetest.get_meta(pos)
@ -117,6 +113,8 @@ local function handle_cart_node_watches(staticdata, dtime)
end
local function handle_cart_collision(cart1_staticdata, prev_pos, next_dir)
if not cart1_staticdata then return end
-- Look ahead one block
local pos = vector.add(prev_pos, next_dir)
@ -387,7 +385,7 @@ local function do_movement_step(staticdata, dtime)
end
-- Handle cart collisions
handle_cart_collision(self, pos, next_dir)
handle_cart_collision(staticdata, pos, next_dir)
-- Leave the old node
handle_cart_leave(staticdata, old_pos, next_dir )

View File

@ -54,6 +54,10 @@ function mod.destroy_cart_data(uuid)
cart_data_fail_cache[uuid] = true
end
function mod.carts()
return pairs(cart_data)
end
function mod.find_carts_by_block_map(block_map)
local cart_list = {}
for _,data in pairs(cart_data) do
@ -68,3 +72,8 @@ function mod.find_carts_by_block_map(block_map)
return cart_list
end
minetest.register_on_shutdown(function()
for uuid,_ in pairs(cart_data) do
save_cart_data(uuid)
end
end)