Give furnace minecart minimum velocity when lit, add train separation code, update logging code, add sequence number to entity staticdata to allow respawn/despawn when carts move when the entity is unloaded

This commit is contained in:
teknomunk 2024-04-07 10:18:55 +00:00
parent 4e27774679
commit 3320fe768b
6 changed files with 127 additions and 48 deletions

View File

@ -73,6 +73,15 @@ function mcl_util.mcl_log(message, module, bypass_default_logger)
minetest.log(selected_module .. " " .. message) minetest.log(selected_module .. " " .. message)
end end
end end
function mcl_util.make_mcl_logger(label, option)
-- Return dummy function if debug option isn't set
if not minetest.settings:get_bool(option,false) then return function() end, false end
local label_text = "["..tostring(label).."]"
return function(message)
mcl_util.mcl_log(message, label_text, true)
end, true
end
local player_timers = {} local player_timers = {}
@ -1204,6 +1213,9 @@ end
function mcl_util.get_active_object_id_from_uuid(uuid) function mcl_util.get_active_object_id_from_uuid(uuid)
return uuid_to_aoid_cache[uuid] or scan_active_objects() or uuid_to_aoid_cache[uuid] return uuid_to_aoid_cache[uuid] or scan_active_objects() or uuid_to_aoid_cache[uuid]
end end
function mcl_util.get_luaentity_from_uuid(uuid)
return minetest.luaentities[ mcl_util.get_active_object_id_from_uuid(uuid) ]
end
function mcl_util.get_uuid(obj) function mcl_util.get_uuid(obj)
local le = obj:get_luaentity() local le = obj:get_luaentity()

View File

@ -3,13 +3,7 @@ local modpath = minetest.get_modpath(modname)
local mod = mcl_minecarts local mod = mcl_minecarts
local S = minetest.get_translator(modname) local S = minetest.get_translator(modname)
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_minecarts", false) local mcl_log = mcl_util.make_mcl_logger("mcl_logging_minecarts", "Minecarts")
local DEBUG = false
local function mcl_log(message)
if LOGGING_ON then
mcl_util.mcl_log(message, "[Minecarts]", true)
end
end
-- Imports -- Imports
local table_merge = mcl_util.table_merge local table_merge = mcl_util.table_merge
@ -53,6 +47,7 @@ local function make_staticdata( railtype, connected_at, dir )
velocity = 0, velocity = 0,
dir = vector.new(dir), dir = vector.new(dir),
mass = 1, mass = 1,
seq = 1,
} }
end end
@ -86,8 +81,15 @@ function DEFAULT_CART_DEF:on_activate(staticdata, dtime_s)
if not data.uuid then if not data.uuid then
data.uuid = mcl_util.get_uuid(self.object) data.uuid = mcl_util.get_uuid(self.object)
end end
self._seq = data.seq or 1
local cd = get_cart_data(data.uuid) local cd = get_cart_data(data.uuid)
if not cd then update_cart_data(data) end if not cd then
update_cart_data(data)
else
if not cd.seq then cd.seq = 1 end
data = cd
end
-- Initialize -- Initialize
if type(data) == "table" then if type(data) == "table" then
@ -121,7 +123,7 @@ function DEFAULT_CART_DEF:on_activate(staticdata, dtime_s)
end end
function DEFAULT_CART_DEF:get_staticdata() function DEFAULT_CART_DEF:get_staticdata()
save_cart_data(self._staticdata.uuid) save_cart_data(self._staticdata.uuid)
return minetest.serialize({uuid = self._staticdata.uuid}) return minetest.serialize({uuid = self._staticdata.uuid, seq=self._seq})
end end
function DEFAULT_CART_DEF:add_node_watch(pos) function DEFAULT_CART_DEF:add_node_watch(pos)
@ -147,6 +149,15 @@ function DEFAULT_CART_DEF:remove_node_watch(pos)
end end
staticdata.node_watches = new_watches staticdata.node_watches = new_watches
end end
function DEFAULT_CART_DEF:get_cart_position()
local staticdata = self._staticdata
if staticdata.connected_at then
return staticdata.connected_at + staticdata.dir * staticdata.distance
else
return self.object:get_pos()
end
end
function DEFAULT_CART_DEF:on_step(dtime) function DEFAULT_CART_DEF:on_step(dtime)
local staticdata = self._staticdata local staticdata = self._staticdata
if not staticdata then if not staticdata then
@ -154,6 +165,11 @@ function DEFAULT_CART_DEF:on_step(dtime)
self._staticdata = staticdata self._staticdata = staticdata
end 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))
end
-- Regen -- Regen
local hp = self.object:get_hp() local hp = self.object:get_hp()
if hp < MINECART_MAX_HP then if hp < MINECART_MAX_HP then

View File

@ -73,6 +73,10 @@ mcl_minecarts.register_minecart({
-- Update furnace stuff -- Update furnace stuff
if (staticdata.fueltime or 0) > 0 then if (staticdata.fueltime or 0) > 0 then
if staticdata.velocity < 0.25 then
staticdata.velocity = 0.25
end
staticdata.fueltime = (staticdata.fueltime or dtime) - dtime staticdata.fueltime = (staticdata.fueltime or dtime) - dtime
if staticdata.fueltime <= 0 then if staticdata.fueltime <= 0 then
self.object:set_properties({textures = self.object:set_properties({textures =

View File

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

View File

@ -4,8 +4,9 @@ local mod = mcl_minecarts
local S = minetest.get_translator(modname) local S = minetest.get_translator(modname)
-- Constants -- Constants
local DEBUG = false 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
-- Imports -- Imports
local train_length = mod.train_length local train_length = mod.train_length
@ -131,6 +132,10 @@ local function handle_cart_collision(cart1, prev_pos, next_dir)
local meta = minetest.get_meta(vector.add(pos,next_dir)) local meta = minetest.get_meta(vector.add(pos,next_dir))
if not cart_uuid then return end if not cart_uuid then return end
-- Don't collide with the train car in front of you
if cart1._staticdata.ahead == cart_uuid then return end
minetest.log("action","cart #"..cart1._staticdata.uuid.." collided with cart #"..cart_uuid.." at "..tostring(pos)) minetest.log("action","cart #"..cart1._staticdata.uuid.." collided with cart #"..cart_uuid.." at "..tostring(pos))
local cart2_aoid = mcl_util.get_active_object_id_from_uuid(cart_uuid) local cart2_aoid = mcl_util.get_active_object_id_from_uuid(cart_uuid)
@ -146,8 +151,8 @@ local function handle_cart_collision(cart1, prev_pos, next_dir)
local m1 = cart1_staticdata.mass local m1 = cart1_staticdata.mass
local m2 = cart2_staticdata.mass local m2 = cart2_staticdata.mass
print("u1="..tostring(u1)..",u2="..tostring(u2)) --print("u1="..tostring(u1)..",u2="..tostring(u2))
if u2 == 0 and u1 < 4 and train_length(cart1) < 3 then if u2 == 0 and u1 < 4 and train_length(cart1) < MAX_TRAIN_LENGTH then
link_cart_ahead(cart1, cart2) link_cart_ahead(cart1, cart2)
cart2_staticdata.dir = mcl_minecarts:get_rail_direction(cart2_staticdata.connected_at, cart1_staticdata.dir) cart2_staticdata.dir = mcl_minecarts:get_rail_direction(cart2_staticdata.connected_at, cart1_staticdata.dir)
cart2_staticdata.velocity = cart1_staticdata.velocity cart2_staticdata.velocity = cart1_staticdata.velocity
@ -275,7 +280,7 @@ local function do_movement_step(self, dtime)
end end
if DEBUG and ( v_0 > 0 or a ~= 0 ) then if DEBUG and ( v_0 > 0 or a ~= 0 ) then
print( " cart "..tostring(staticdata.uuid).. mcl_debug(" cart "..tostring(staticdata.uuid)..
": a="..tostring(a).. ": a="..tostring(a)..
",v_0="..tostring(v_0).. ",v_0="..tostring(v_0)..
",x_0="..tostring(x_0).. ",x_0="..tostring(x_0)..
@ -334,7 +339,7 @@ local function do_movement_step(self, dtime)
staticdata.distance = x_1 staticdata.distance = x_1
if DEBUG and (1==0) and ( v_0 > 0 or a ~= 0 ) then if DEBUG and (1==0) and ( v_0 > 0 or a ~= 0 ) then
print( "- cart #"..tostring(staticdata.uuid).. mcl_debug( "- cart #"..tostring(staticdata.uuid)..
": a="..tostring(a).. ": a="..tostring(a)..
",v_0="..tostring(v_0).. ",v_0="..tostring(v_0)..
",v_1="..tostring(v_1).. ",v_1="..tostring(v_1)..
@ -362,7 +367,7 @@ local function do_movement_step(self, dtime)
-- Get the next direction -- Get the next direction
local next_dir,_ = mcl_minecarts:get_rail_direction(pos, staticdata.dir, nil, nil, staticdata.railtype) local next_dir,_ = mcl_minecarts:get_rail_direction(pos, staticdata.dir, nil, nil, staticdata.railtype)
if DEBUG and next_dir ~= staticdata.dir then if DEBUG and next_dir ~= staticdata.dir then
print( "Changing direction from "..tostring(staticdata.dir).." to "..tostring(next_dir)) mcl_debug( "Changing direction from "..tostring(staticdata.dir).." to "..tostring(next_dir))
end end
-- Handle cart collisions -- Handle cart collisions
@ -376,7 +381,7 @@ local function do_movement_step(self, dtime)
-- Handle end of track -- Handle end of track
if next_dir == staticdata.dir * -1 and next_dir.y == 0 then if next_dir == staticdata.dir * -1 and next_dir.y == 0 then
if DEBUG then print("Stopping cart at end of track at "..tostring(pos)) end if DEBUG then mcl_debug("Stopping cart at end of track at "..tostring(pos)) end
staticdata.velocity = 0 staticdata.velocity = 0
end end
@ -384,7 +389,7 @@ local function do_movement_step(self, dtime)
staticdata.dir = next_dir staticdata.dir = next_dir
elseif stops_in_block and v_1 < (friction/5) and a <= 0 then elseif stops_in_block and v_1 < (friction/5) and a <= 0 then
-- Handle direction flip due to gravity -- Handle direction flip due to gravity
if DEBUG then print("Gravity flipped direction") end if DEBUG then mcl_debug("Gravity flipped direction") end
-- Velocity should be zero at this point -- Velocity should be zero at this point
staticdata.velocity = 0 staticdata.velocity = 0
@ -405,7 +410,7 @@ local function do_movement_step(self, dtime)
-- Debug reporting -- Debug reporting
if DEBUG and ( v_0 > 0 or v_1 > 0 ) then if DEBUG and ( v_0 > 0 or v_1 > 0 ) then
print( " cart #"..tostring(staticdata.uuid).. mcl_debug( " cart #"..tostring(staticdata.uuid)..
": a="..tostring(a).. ": a="..tostring(a)..
",v_0="..tostring(v_0).. ",v_0="..tostring(v_0)..
",v_1="..tostring(v_1).. ",v_1="..tostring(v_1)..

View File

@ -4,7 +4,9 @@ local mod = mcl_minecarts
-- Imports -- Imports
local get_cart_data = mod.get_cart_data local get_cart_data = mod.get_cart_data
local MAX_TRAIN_LENGTH = mod.MAX_TRAIN_LENGTH
-- Follow .behind to the back end of a train
local function find_back(start) local function find_back(start)
while start.behind do while start.behind do
local nxt = get_cart_data(start.behind) local nxt = get_cart_data(start.behind)
@ -14,10 +16,13 @@ local function find_back(start)
return start return start
end end
-- Iterate across all the cars in a train
local function train_cars(anchor) local function train_cars(anchor)
local back = find_back(anchor._staticdata) local back = find_back(anchor._staticdata)
local limit = MAX_TRAIN_LENGTH
return function() return function()
if not back then return end if not back or limit <= 0 then return end
limit = limit - 1
local ret = back local ret = back
if back.ahead then if back.ahead then
@ -28,26 +33,6 @@ local function train_cars(anchor)
return ret return ret
end end
end end
function mod.update_train(cart)
local sum_velocity = 0
local count = 0
for cart in train_cars(cart) do
count = count + 1
sum_velocity = sum_velocity + (cart.velocity or 0)
end
local avg_velocity = sum_velocity / count
if count == 0 then return end
print("Using velocity "..tostring(avg_velocity))
-- Set the entire train to the average velocity
for c in train_cars(cart) do
print(tostring(c.behind).."->"..c.uuid.."->"..tostring(c.ahead).." setting cart #"..c.uuid.." velocity to "..tostring(avg_velocity))
c.velocity = avg_velocity
end
end
function mod.train_length(cart) function mod.train_length(cart)
local count = 0 local count = 0
for cart in train_cars(cart) do for cart in train_cars(cart) do
@ -55,6 +40,68 @@ function mod.train_length(cart)
end end
return count return count
end end
function mod.is_in_same_train(anchor, other)
for cart in train_cars(anchor) do
if cart.uuid == other.uuid then return true end
end
return false
end
function mod.distance_between_cars(car1, car2)
if not car1.connected_at then return nil end
if not car2.connected_at then return nil end
if not car1.dir then car1.dir = vector.zero() end
if not car2.dir then car2.dir = vector.zero() end
local pos1 = vector.add(car1.connected_at, vector.multiply(car1.dir, car1.distance))
local pos2 = vector.add(car2.connected_at, vector.multiply(car2.dir, car2.distance))
return vector.distance(pos1, pos2)
end
local distance_between_cars = mod.distance_between_cars
function mod.update_train(cart)
local staticdata = cart._staticdata
-- Only update from the back
if staticdata.behind or not staticdata.ahead then return end
print("\nUpdating train")
-- Do no special processing if the cart is not part of a train
if not staticdata.ahead and not staticdata.behind then return end
-- Calculate the average velocity of all train cars
local sum_velocity = 0
for cart in train_cars(cart) do
if cart.velocity or 0 > velocity then
velocity = cart.velocity
end
end
print("Using velocity "..tostring(velocity))
-- Set the entire train to the average velocity
local behind = nil
for c in train_cars(cart) do
local e = 0
local separation
if behind then
separation = distance_between_cars(behind, c)
local e = 0
if separation > 1.25 then
velocity = velocity * 0.9
elseif separation < 1.15 then
velocity = velocity * 1.1
end
end
print(tostring(c.behind).."->"..c.uuid.."->"..tostring(c.ahead).."("..tostring(separation)..") setting cart #"..c.uuid.." velocity to "..tostring(velocity))
c.velocity = velocity
behind = c
end
end
function mod.link_cart_ahead(cart, cart_ahead) function mod.link_cart_ahead(cart, cart_ahead)
local staticdata = cart._staticdata local staticdata = cart._staticdata
local ca_staticdata = cart_ahead._staticdata local ca_staticdata = cart_ahead._staticdata
@ -64,9 +111,3 @@ function mod.link_cart_ahead(cart, cart_ahead)
staticdata.ahead = ca_staticdata.uuid staticdata.ahead = ca_staticdata.uuid
ca_staticdata.behind = staticdata.uuid ca_staticdata.behind = staticdata.uuid
end end
function mod.is_in_same_train(anchor, other)
for cart in train_cars(anchor) do
if cart.uuid == other.uuid then return true end
end
return false
end