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 252179c695
commit f86ff41554
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 -- Table for item-to-entity mapping. Keys: itemstring, Values: Corresponding entity ID
local entity_mapping = {} local entity_mapping = {}
local function make_staticdata( railtype, connected_at, dir ) local function make_staticdata( _, connected_at, dir )
return { return {
railtype = railtype,
connected_at = connected_at, connected_at = connected_at,
distance = 0, distance = 0,
velocity = 0, velocity = 0,
@ -122,12 +121,6 @@ function DEFAULT_CART_DEF:on_activate(staticdata, dtime_s)
-- Initialize -- Initialize
if type(data) == "table" then if type(data) == "table" then
-- Migrate old data
if data._railtype then
data.railtype = data._railtype
data._railtype = nil
end
-- Fix up types -- Fix up types
data.dir = vector.new(data.dir) data.dir = vector.new(data.dir)
@ -194,11 +187,17 @@ function DEFAULT_CART_DEF:on_step(dtime)
self._staticdata = staticdata self._staticdata = staticdata
end end
-- Update entity position
local pos = mod.get_cart_position(staticdata)
if pos then self.object:move_to(pos) end
-- Repair cart_type -- Repair cart_type
if not staticdata.cart_type then if not staticdata.cart_type then
staticdata.cart_type = self.name staticdata.cart_type = self.name
end end
-- Remove superceded entities
if self._seq ~= staticdata.seq then if self._seq ~= staticdata.seq then
print("removing cart #"..staticdata.uuid.." with sequence number mismatch") print("removing cart #"..staticdata.uuid.." with sequence number mismatch")
self.object:remove() self.object:remove()
@ -207,22 +206,11 @@ function DEFAULT_CART_DEF:on_step(dtime)
-- Regen -- Regen
local hp = self.object:get_hp() local hp = self.object:get_hp()
if hp < MINECART_MAX_HP then local time_now = minetest.get_gametime()
if (staticdata.regen_timer or 0) > 0.5 then if hp < MINECART_MAX_HP and staticdata.last_regen <= time_now - 1 then
hp = hp + 1 staticdata.last_regen = time_now
staticdata.regen_timer = staticdata.regen_timer - 1 hp = hp + 1
end
staticdata.regen_timer = (staticdata.regen_timer or 0) + dtime
self.object:set_hp(hp) 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 end
-- Cart specific behaviors -- Cart specific behaviors
@ -256,27 +244,12 @@ function DEFAULT_CART_DEF:on_step(dtime)
end end
end end
if staticdata.connected_at then if not 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
do_detached_movement(self, dtime) do_detached_movement(self, dtime)
end end
-- TODO: move this into mcl_core:cactus _mcl_minecarts_on_enter_side mod.update_cart_orientation(self)
-- 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
end end
function DEFAULT_CART_DEF:on_death(killer) function DEFAULT_CART_DEF:on_death(killer)
local staticdata = self._staticdata local staticdata = self._staticdata
@ -325,7 +298,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
local spawn_pos = pointed_thing.above local spawn_pos = pointed_thing.above
local cart_dir = vector.new(1,0,0) local cart_dir = vector.new(1,0,0)
local railtype, railpos, node local railpos, node
if mcl_minecarts:is_rail(pointed_thing.under) then if mcl_minecarts:is_rail(pointed_thing.under) then
railpos = pointed_thing.under railpos = pointed_thing.under
elseif mcl_minecarts:is_rail(pointed_thing.above) then 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 if railpos then
spawn_pos = railpos spawn_pos = railpos
node = minetest.get_node(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))
cart_dir = mcl_minecarts:get_rail_direction(railpos, vector.new(1,0,0), nil, nil, railtype)
end end
local entity_id = entity_mapping[itemstack:get_name()] 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)) 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 -- Update static data
local le = cart:get_luaentity() local le = cart:get_luaentity()
if le then 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 le._staticdata = data
save_cart_data(le._staticdata.uuid)
end end
-- Call placer -- Call placer
@ -361,7 +335,7 @@ function mcl_minecarts.place_minecart(itemstack, pointed_thing, placer)
end end
if railpos then if railpos then
handle_cart_enter(le, railpos) handle_cart_enter(data, railpos)
end end
local pname = "" 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) 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 z = min.z,max.z do
for y = min.y,max.y 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 block_map[ vector.to_string(vector.new(x,y,z)) ] = true
end end
end end
@ -545,10 +519,42 @@ minetest.register_globalstep(function(dtime)
try_respawn_carts() try_respawn_carts()
local stop_time = minetest.get_us_time() local stop_time = minetest.get_us_time()
local duration = (stop_time - start_time) / 1e6 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") --print("Took "..tostring(duration).." seconds, rescheduling for "..tostring(timer).." seconds in the future")
end 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) end)

View File

@ -372,7 +372,7 @@ function mod.reverse_cart_direction(staticdata)
staticdata.distance = 1 - (staticdata.distance or 0) staticdata.distance = 1 - (staticdata.distance or 0)
-- recalculate direction -- 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 staticdata.dir = next_dir
end 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 mcl_debug,DEBUG = mcl_util.make_mcl_logger("mcl_logging_minecart_debug", "Minecart Debug")
local friction = mcl_minecarts.FRICTION local friction = mcl_minecarts.FRICTION
local MAX_TRAIN_LENGTH = mod.MAX_TRAIN_LENGTH local MAX_TRAIN_LENGTH = mod.MAX_TRAIN_LENGTH
DEBUG = true --DEBUG = false
mcl_debug = function(msg) print(msg) end --mcl_debug = function(msg) print(msg) end
-- Imports -- Imports
local train_length = mod.train_length local train_length = mod.train_length
@ -30,13 +30,9 @@ end
mod.detach_minecart = detach_minecart mod.detach_minecart = detach_minecart
local function try_detach_minecart(staticdata) local function try_detach_minecart(staticdata)
if not staticdata then return end if not staticdata or not staticdata.connected_at then return end
if not mod:is_rail(staticdata.connected_at) then
-- Don't try to detach if alread detached print("Detaching minecart"..tostring(staticdata.uuid))
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
detach_minecart(staticdata) detach_minecart(staticdata)
end end
end end
@ -77,10 +73,10 @@ local function handle_cart_enter_exit(staticdata, pos, next_dir, event)
-- Handle cart-specific behaviors -- Handle cart-specific behaviors
if luaentity then if luaentity then
local hook = luaentity["_mcl_minecarts_"..event] local hook = luaentity["_mcl_minecarts_"..event]
if hook then hook(self, pos) end
else 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 end
if hook then hook(self, pos) end
end end
local function set_metadata_cart_status(pos, uuid, state) local function set_metadata_cart_status(pos, uuid, state)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
@ -117,6 +113,8 @@ local function handle_cart_node_watches(staticdata, dtime)
end end
local function handle_cart_collision(cart1_staticdata, prev_pos, next_dir) local function handle_cart_collision(cart1_staticdata, prev_pos, next_dir)
if not cart1_staticdata then return end
-- Look ahead one block -- Look ahead one block
local pos = vector.add(prev_pos, next_dir) local pos = vector.add(prev_pos, next_dir)
@ -387,7 +385,7 @@ local function do_movement_step(staticdata, dtime)
end end
-- Handle cart collisions -- Handle cart collisions
handle_cart_collision(self, pos, next_dir) handle_cart_collision(staticdata, pos, next_dir)
-- Leave the old node -- Leave the old node
handle_cart_leave(staticdata, old_pos, next_dir ) 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 cart_data_fail_cache[uuid] = true
end end
function mod.carts()
return pairs(cart_data)
end
function mod.find_carts_by_block_map(block_map) function mod.find_carts_by_block_map(block_map)
local cart_list = {} local cart_list = {}
for _,data in pairs(cart_data) do for _,data in pairs(cart_data) do
@ -68,3 +72,8 @@ function mod.find_carts_by_block_map(block_map)
return cart_list return cart_list
end end
minetest.register_on_shutdown(function()
for uuid,_ in pairs(cart_data) do
save_cart_data(uuid)
end
end)