From 095ad465e5085994bd938c0c982a4ff92ee4d08b Mon Sep 17 00:00:00 2001 From: teknomunk Date: Sun, 7 Apr 2024 10:18:55 +0000 Subject: [PATCH] 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 --- mods/CORE/mcl_util/init.lua | 12 +++ mods/ENTITIES/mcl_minecarts/carts.lua | 34 +++++-- .../mcl_minecarts/carts/with_furnace.lua | 4 + mods/ENTITIES/mcl_minecarts/init.lua | 7 +- mods/ENTITIES/mcl_minecarts/movement.lua | 23 +++-- mods/ENTITIES/mcl_minecarts/train.lua | 95 +++++++++++++------ 6 files changed, 127 insertions(+), 48 deletions(-) diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index 1d9440ff8..c9a012803 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -59,6 +59,15 @@ function mcl_util.mcl_log(message, module, bypass_default_logger) minetest.log(selected_module .. " " .. message) 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 = {} @@ -1176,6 +1185,9 @@ end 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] 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) local le = obj:get_luaentity() diff --git a/mods/ENTITIES/mcl_minecarts/carts.lua b/mods/ENTITIES/mcl_minecarts/carts.lua index d0b8296c9..f0e4fab65 100644 --- a/mods/ENTITIES/mcl_minecarts/carts.lua +++ b/mods/ENTITIES/mcl_minecarts/carts.lua @@ -3,13 +3,7 @@ local modpath = minetest.get_modpath(modname) local mod = mcl_minecarts local S = minetest.get_translator(modname) -local LOGGING_ON = minetest.settings:get_bool("mcl_logging_minecarts", false) -local DEBUG = false -local function mcl_log(message) - if LOGGING_ON then - mcl_util.mcl_log(message, "[Minecarts]", true) - end -end +local mcl_log = mcl_util.make_mcl_logger("mcl_logging_minecarts", "Minecarts") -- Imports local table_merge = mcl_util.table_merge @@ -53,6 +47,7 @@ local function make_staticdata( railtype, connected_at, dir ) velocity = 0, dir = vector.new(dir), mass = 1, + seq = 1, } end @@ -86,8 +81,15 @@ function DEFAULT_CART_DEF:on_activate(staticdata, dtime_s) if not data.uuid then data.uuid = mcl_util.get_uuid(self.object) end + self._seq = data.seq or 1 + 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 if type(data) == "table" then @@ -121,7 +123,7 @@ function DEFAULT_CART_DEF:on_activate(staticdata, dtime_s) end function DEFAULT_CART_DEF:get_staticdata() save_cart_data(self._staticdata.uuid) - return minetest.serialize({uuid = self._staticdata.uuid}) + return minetest.serialize({uuid = self._staticdata.uuid, seq=self._seq}) end function DEFAULT_CART_DEF:add_node_watch(pos) @@ -147,6 +149,15 @@ function DEFAULT_CART_DEF:remove_node_watch(pos) end staticdata.node_watches = new_watches 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) local staticdata = self._staticdata if not staticdata then @@ -154,6 +165,11 @@ function DEFAULT_CART_DEF:on_step(dtime) self._staticdata = staticdata 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 local hp = self.object:get_hp() if hp < MINECART_MAX_HP then diff --git a/mods/ENTITIES/mcl_minecarts/carts/with_furnace.lua b/mods/ENTITIES/mcl_minecarts/carts/with_furnace.lua index f2c6355b6..13693b733 100644 --- a/mods/ENTITIES/mcl_minecarts/carts/with_furnace.lua +++ b/mods/ENTITIES/mcl_minecarts/carts/with_furnace.lua @@ -73,6 +73,10 @@ mcl_minecarts.register_minecart({ -- Update furnace stuff 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 if staticdata.fueltime <= 0 then self.object:set_properties({textures = diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index 265428112..22c67de5b 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -5,9 +5,10 @@ local mod = mcl_minecarts mcl_minecarts.modpath = modpath -- Constants -mcl_minecarts.speed_max = 10 -mcl_minecarts.check_float_time = 15 -mcl_minecarts.FRICTION = 0.4 +mod.speed_max = 10 +mod.check_float_time = 15 +mod.FRICTION = 0.4 +mod.MAX_TRAIN_LENGTH = 4 for _,filename in pairs({"storage","functions","rails","train","carts"}) do dofile(modpath.."/"..filename..".lua") diff --git a/mods/ENTITIES/mcl_minecarts/movement.lua b/mods/ENTITIES/mcl_minecarts/movement.lua index fd2edb422..25db9a621 100644 --- a/mods/ENTITIES/mcl_minecarts/movement.lua +++ b/mods/ENTITIES/mcl_minecarts/movement.lua @@ -4,8 +4,9 @@ local mod = mcl_minecarts local S = minetest.get_translator(modname) -- 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 MAX_TRAIN_LENGTH = mod.MAX_TRAIN_LENGTH -- Imports 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)) 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)) 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 m2 = cart2_staticdata.mass - print("u1="..tostring(u1)..",u2="..tostring(u2)) - if u2 == 0 and u1 < 4 and train_length(cart1) < 3 then + --print("u1="..tostring(u1)..",u2="..tostring(u2)) + if u2 == 0 and u1 < 4 and train_length(cart1) < MAX_TRAIN_LENGTH then link_cart_ahead(cart1, cart2) cart2_staticdata.dir = mcl_minecarts:get_rail_direction(cart2_staticdata.connected_at, cart1_staticdata.dir) cart2_staticdata.velocity = cart1_staticdata.velocity @@ -275,7 +280,7 @@ local function do_movement_step(self, dtime) end if DEBUG and ( v_0 > 0 or a ~= 0 ) then - print( " cart "..tostring(staticdata.uuid).. + mcl_debug(" cart "..tostring(staticdata.uuid).. ": a="..tostring(a).. ",v_0="..tostring(v_0).. ",x_0="..tostring(x_0).. @@ -334,7 +339,7 @@ local function do_movement_step(self, dtime) staticdata.distance = x_1 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).. ",v_0="..tostring(v_0).. ",v_1="..tostring(v_1).. @@ -362,7 +367,7 @@ local function do_movement_step(self, dtime) -- Get the next direction local next_dir,_ = mcl_minecarts:get_rail_direction(pos, staticdata.dir, nil, nil, staticdata.railtype) 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 -- Handle cart collisions @@ -376,7 +381,7 @@ local function do_movement_step(self, dtime) -- Handle end of track 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 end @@ -384,7 +389,7 @@ local function do_movement_step(self, dtime) staticdata.dir = next_dir elseif stops_in_block and v_1 < (friction/5) and a <= 0 then -- 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 staticdata.velocity = 0 @@ -405,7 +410,7 @@ local function do_movement_step(self, dtime) -- Debug reporting 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).. ",v_0="..tostring(v_0).. ",v_1="..tostring(v_1).. diff --git a/mods/ENTITIES/mcl_minecarts/train.lua b/mods/ENTITIES/mcl_minecarts/train.lua index e9511a83d..c3cfdc187 100644 --- a/mods/ENTITIES/mcl_minecarts/train.lua +++ b/mods/ENTITIES/mcl_minecarts/train.lua @@ -4,7 +4,9 @@ local mod = mcl_minecarts -- Imports 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) while start.behind do local nxt = get_cart_data(start.behind) @@ -14,10 +16,13 @@ local function find_back(start) return start end +-- Iterate across all the cars in a train local function train_cars(anchor) local back = find_back(anchor._staticdata) + local limit = MAX_TRAIN_LENGTH return function() - if not back then return end + if not back or limit <= 0 then return end + limit = limit - 1 local ret = back if back.ahead then @@ -28,26 +33,6 @@ local function train_cars(anchor) return ret 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) local count = 0 for cart in train_cars(cart) do @@ -55,6 +40,68 @@ function mod.train_length(cart) end return count 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) local staticdata = cart._staticdata local ca_staticdata = cart_ahead._staticdata @@ -64,9 +111,3 @@ function mod.link_cart_ahead(cart, cart_ahead) staticdata.ahead = ca_staticdata.uuid ca_staticdata.behind = staticdata.uuid 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