2024-04-05 08:39:42 +02:00
local modname = minetest.get_current_modname ( )
2024-04-06 19:09:54 +02:00
local modpath = minetest.get_modpath ( modname )
2024-04-05 08:39:42 +02:00
local mod = mcl_minecarts
local S = minetest.get_translator ( modname )
2024-04-12 23:25:40 +02:00
local mcl_log , DEBUG = mcl_util.make_mcl_logger ( " mcl_logging_minecarts " , " Minecarts " )
2024-04-05 08:39:42 +02:00
2024-04-06 19:09:54 +02:00
-- Imports
2024-04-07 14:27:53 +02:00
local CART_BLOCK_SIZE = mod.CART_BLOCK_SIZE
2024-04-05 08:39:42 +02:00
local table_merge = mcl_util.table_merge
2024-04-06 19:09:54 +02:00
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
2024-04-07 14:27:53 +02:00
local find_carts_by_block_map = mod.find_carts_by_block_map
2024-04-06 19:09:54 +02:00
local do_movement , do_detached_movement , handle_cart_enter = dofile ( modpath .. " /movement.lua " )
assert ( do_movement )
assert ( do_detached_movement )
assert ( handle_cart_enter )
2024-04-05 08:39:42 +02:00
-- Constants
local max_step_distance = 0.5
local MINECART_MAX_HP = 4
2024-04-23 18:34:39 +02:00
local TWO_OVER_PI = 2 / math.pi
2024-04-05 08:39:42 +02:00
local function detach_driver ( self )
2024-04-09 10:14:30 +02:00
local staticdata = self._staticdata
2024-04-05 08:39:42 +02:00
if not self._driver then
return
end
2024-04-09 09:35:57 +02:00
-- Update player infomation
local driver_name = self._driver
local playerinfo = mcl_playerinfo [ driver_name ]
if playerinfo then
playerinfo.attached_to = nil
end
mcl_player.player_attached [ driver_name ] = nil
minetest.log ( " action " , driver_name .. " left a minecart " )
-- Update cart informatino
2024-04-05 08:39:42 +02:00
self._driver = nil
self._start_pos = nil
2024-04-12 22:47:47 +02:00
local player_meta = mcl_playerinfo.get_mod_meta ( driver_name , modname )
player_meta.attached_to = nil
2024-04-09 09:35:57 +02:00
-- Detatch the player object from the minecart
local player = minetest.get_player_by_name ( driver_name )
2024-04-05 08:39:42 +02:00
if player then
2024-04-09 10:14:30 +02:00
local dir = staticdata.dir or vector.new ( 1 , 0 , 0 )
local cart_pos = mod.get_cart_position ( staticdata ) or self.object : get_pos ( )
local new_pos = vector.offset ( cart_pos , - dir.z , 0 , dir.x )
2024-04-05 08:39:42 +02:00
player : set_detach ( )
2024-04-25 10:34:11 +02:00
--print("placing player at "..tostring(new_pos).." from cart at "..tostring(cart_pos)..", old_pos="..tostring(player:get_pos()).."dir="..tostring(dir))
2024-04-09 10:14:30 +02:00
-- There needs to be a delay here or the player's position won't update
minetest.after ( 0.1 , function ( driver_name , new_pos )
local player = minetest.get_player_by_name ( driver_name )
player : moveto ( new_pos , false )
end , driver_name , new_pos )
2024-04-05 08:39:42 +02:00
player : set_eye_offset ( vector.new ( 0 , 0 , 0 ) , vector.new ( 0 , 0 , 0 ) )
mcl_player.player_set_animation ( player , " stand " , 30 )
2024-04-25 10:34:11 +02:00
--else
--print("No player object found for "..driver_name)
2024-04-05 08:39:42 +02:00
end
end
-- Table for item-to-entity mapping. Keys: itemstring, Values: Corresponding entity ID
local entity_mapping = { }
2024-04-09 22:52:11 +02:00
local function make_staticdata ( _ , connected_at , dir )
2024-04-05 08:39:42 +02:00
return {
connected_at = connected_at ,
distance = 0 ,
velocity = 0 ,
dir = vector.new ( dir ) ,
2024-04-06 15:40:40 +02:00
mass = 1 ,
2024-04-07 12:18:55 +02:00
seq = 1 ,
2024-04-05 08:39:42 +02:00
}
end
local DEFAULT_CART_DEF = {
initial_properties = {
physical = true ,
collisionbox = { - 10 / 16. , - 0.5 , - 10 / 16 , 10 / 16 , 0.25 , 10 / 16 } ,
visual = " mesh " ,
visual_size = { x = 1 , y = 1 } ,
} ,
hp_max = MINECART_MAX_HP ,
groups = {
minecart = 1 ,
} ,
_driver = nil , -- player who sits in and controls the minecart (only for minecart!)
_passenger = nil , -- for mobs
_start_pos = nil , -- Used to calculate distance for “On A Rail” achievement
_last_float_check = nil , -- timestamp of last time the cart was checked to be still on a rail
_boomtimer = nil , -- how many seconds are left before exploding
_blinktimer = nil , -- how many seconds are left before TNT blinking
_blink = false , -- is TNT blink texture active?
_old_pos = nil ,
_staticdata = nil ,
}
function DEFAULT_CART_DEF : on_activate ( staticdata , dtime_s )
2024-04-06 15:40:40 +02:00
-- Transfer older data
local data = minetest.deserialize ( staticdata ) or { }
if not data.uuid then
2024-04-10 01:09:10 +02:00
data.uuid = mcl_util.assign_uuid ( self.object )
2024-04-06 15:40:40 +02:00
end
2024-04-07 12:18:55 +02:00
self._seq = data.seq or 1
2024-04-06 15:40:40 +02:00
local cd = get_cart_data ( data.uuid )
2024-04-07 12:18:55 +02:00
if not cd then
update_cart_data ( data )
else
if not cd.seq then cd.seq = 1 end
data = cd
end
2024-04-06 15:40:40 +02:00
2024-04-10 00:32:58 +02:00
-- Fix up types
data.dir = vector.new ( data.dir )
2024-04-05 08:39:42 +02:00
2024-04-10 00:32:58 +02:00
-- Fix mass
data.mass = data.mass or 1
2024-04-06 15:40:40 +02:00
2024-04-10 00:32:58 +02:00
-- Make sure all carts have an ID to isolate them
self._uuid = data.uuid
self._staticdata = data
2024-04-05 08:39:42 +02:00
2024-04-06 15:40:40 +02:00
-- Activate cart if on powered activator rail
2024-04-05 08:39:42 +02:00
if self.on_activate_by_rail then
local pos = self.object : get_pos ( )
local node = minetest.get_node ( vector.floor ( pos ) )
if node.name == " mcl_minecarts:activator_rail_on " then
self : on_activate_by_rail ( )
end
end
end
2024-04-06 15:40:40 +02:00
function DEFAULT_CART_DEF : get_staticdata ( )
save_cart_data ( self._staticdata . uuid )
2024-04-07 12:18:55 +02:00
return minetest.serialize ( { uuid = self._staticdata . uuid , seq = self._seq } )
2024-04-06 15:40:40 +02:00
end
2024-04-11 15:09:24 +02:00
function DEFAULT_CART_DEF : _mcl_entity_invs_load_items ( )
local staticdata = self._staticdata
return staticdata.inventory or { }
end
function DEFAULT_CART_DEF : _mcl_entity_invs_save_items ( items )
local staticdata = self._staticdata
staticdata.inventory = table.copy ( items )
end
2024-04-05 08:39:42 +02:00
function DEFAULT_CART_DEF : add_node_watch ( pos )
local staticdata = self._staticdata
local watches = staticdata.node_watches or { }
2024-04-12 14:28:24 +02:00
for i = 1 , # watches do
if watches [ i ] == pos then return end
2024-04-05 08:39:42 +02:00
end
watches [ # watches + 1 ] = pos
staticdata.node_watches = watches
end
function DEFAULT_CART_DEF : remove_node_watch ( pos )
local staticdata = self._staticdata
local watches = staticdata.node_watches or { }
local new_watches = { }
2024-04-12 14:28:24 +02:00
for i = 1 , # watches do
local node_pos = watches [ i ]
2024-04-05 08:39:42 +02:00
if node_pos ~= pos then
2024-04-12 14:28:24 +02:00
new_watches [ # new_watches + 1 ] = node_pos
2024-04-05 08:39:42 +02:00
end
end
staticdata.node_watches = new_watches
end
2024-04-07 12:18:55 +02:00
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
2024-04-25 10:34:11 +02:00
function DEFAULT_CART_DEF : on_punch ( puncher , time_from_last_punch , tool_capabilities , dir , damage )
if puncher == self._driver then return end
local staticdata = self._staticdata
local controls = staticdata.controls or { }
local impulse = vector.multiply ( dir , damage * 20 )
local accel = vector.dot ( staticdata.dir , impulse )
if accel < 0 and staticdata.velocity == 0 then
mod.reverse_direction ( staticdata )
end
controls.impulse = impulse
--print("uuid="..self._uuid..", controls="..dump(controls))
staticdata.controls = controls
end
2024-04-05 08:39:42 +02:00
function DEFAULT_CART_DEF : on_step ( dtime )
local staticdata = self._staticdata
if not staticdata then
staticdata = make_staticdata ( )
self._staticdata = staticdata
end
2024-04-09 22:52:11 +02:00
-- Update entity position
local pos = mod.get_cart_position ( staticdata )
if pos then self.object : move_to ( pos ) end
2024-04-07 14:27:53 +02:00
-- Repair cart_type
if not staticdata.cart_type then
staticdata.cart_type = self.name
end
2024-04-09 22:52:11 +02:00
-- Remove superceded entities
2024-04-07 12:18:55 +02:00
if self._seq ~= staticdata.seq then
2024-04-25 10:34:11 +02:00
--print("removing cart #"..staticdata.uuid.." with sequence number mismatch")
2024-04-07 14:27:53 +02:00
self.object : remove ( )
return
2024-04-07 12:18:55 +02:00
end
2024-04-05 08:39:42 +02:00
-- Regen
local hp = self.object : get_hp ( )
2024-04-09 22:52:11 +02:00
local time_now = minetest.get_gametime ( )
2024-04-10 01:09:10 +02:00
if hp < MINECART_MAX_HP and ( staticdata.last_regen or 0 ) <= time_now - 1 then
2024-04-09 22:52:11 +02:00
staticdata.last_regen = time_now
hp = hp + 1
2024-04-05 08:39:42 +02:00
self.object : set_hp ( hp )
end
-- Cart specific behaviors
local hook = self._mcl_minecarts_on_step
if hook then hook ( self , dtime ) end
if ( staticdata.hopper_delay or 0 ) > 0 then
staticdata.hopper_delay = staticdata.hopper_delay - dtime
end
-- Controls
local ctrl , player = nil , nil
if self._driver then
player = minetest.get_player_by_name ( self._driver )
if player then
ctrl = player : get_player_control ( )
-- player detach
if ctrl.sneak then
detach_driver ( self )
return
end
-- Experimental controls
2024-04-10 11:03:59 +02:00
local now_time = minetest.get_gametime ( )
local controls = { }
if ctrl.up then controls.forward = now_time end
if ctrl.down then controls.brake = now_time end
2024-04-23 18:34:39 +02:00
controls.look = math.round ( player : get_look_horizontal ( ) * TWO_OVER_PI ) % 4
2024-04-10 11:03:59 +02:00
staticdata.controls = controls
2024-04-05 08:39:42 +02:00
end
-- Give achievement when player reached a distance of 1000 nodes from the start position
2024-04-16 22:06:08 +02:00
if pos and vector.distance ( self._start_pos , pos ) >= 1000 then
2024-04-05 08:39:42 +02:00
awards.unlock ( self._driver , " mcl:onARail " )
end
end
2024-04-09 22:52:11 +02:00
if not staticdata.connected_at then
2024-04-05 08:39:42 +02:00
do_detached_movement ( self , dtime )
end
2024-04-09 22:52:11 +02:00
mod.update_cart_orientation ( self )
2024-04-05 08:39:42 +02:00
end
2024-04-12 14:28:24 +02:00
function mod . kill_cart ( staticdata , killer )
2024-04-11 00:22:17 +02:00
local pos
2024-04-06 15:40:40 +02:00
minetest.log ( " action " , " cart # " .. staticdata.uuid .. " was killed " )
2024-04-05 08:39:42 +02:00
-- Leave nodes
if staticdata.attached_at then
handle_cart_leave ( self , staticdata.attached_at , staticdata.dir )
else
2024-04-12 22:47:47 +02:00
--mcl_log("TODO: handle detatched minecart death")
2024-04-05 08:39:42 +02:00
end
2024-04-11 00:22:17 +02:00
-- Handle entity-related items
local le = mcl_util.get_luaentity_from_uuid ( staticdata.uuid )
if le then
pos = le.object : get_pos ( )
2024-04-06 15:40:40 +02:00
2024-04-11 00:22:17 +02:00
detach_driver ( le )
-- Detach passenger
if le._passenger then
local mob = le._passenger . object
mob : set_detach ( )
2024-04-05 08:39:42 +02:00
end
2024-04-11 00:48:24 +02:00
-- Remove the entity
le.object : remove ( )
2024-04-11 00:22:17 +02:00
else
pos = mod.get_cart_position ( staticdata )
end
-- Drop items
if not staticdata.dropped then
2024-04-12 14:28:24 +02:00
-- Try to drop the cart
2024-04-11 00:22:17 +02:00
local entity_def = minetest.registered_entities [ staticdata.cart_type ]
if entity_def then
2024-04-12 14:28:24 +02:00
local drop_cart = true
if killer and minetest.is_creative_enabled ( killer : get_player_name ( ) ) then
drop_cart = false
end
if drop_cart then
local drop = entity_def.drop
for d = 1 , # drop do
minetest.add_item ( pos , drop [ d ] )
end
2024-04-05 08:39:42 +02:00
end
2024-04-12 14:28:24 +02:00
end
2024-04-11 00:22:17 +02:00
2024-04-12 14:28:24 +02:00
-- Drop any items in the inventory
local inventory = staticdata.inventory
if inventory then
for i = 1 , # inventory do
minetest.add_item ( pos , inventory [ i ] )
end
2024-04-05 08:39:42 +02:00
end
2024-04-12 14:28:24 +02:00
-- Prevent item duplication
staticdata.dropped = true
2024-04-05 08:39:42 +02:00
end
2024-04-11 00:22:17 +02:00
-- Remove data
destroy_cart_data ( staticdata.uuid )
end
2024-04-11 00:48:24 +02:00
local kill_cart = mod.kill_cart
2024-04-11 00:22:17 +02:00
function DEFAULT_CART_DEF : on_death ( killer )
2024-04-12 14:28:24 +02:00
kill_cart ( self._staticdata , killer )
2024-04-05 08:39:42 +02:00
end
2024-04-12 11:11:46 +02:00
-- Create a minecart
function mod . create_minecart ( entity_id , pos , dir )
-- Setup cart data
local uuid = mcl_util.gen_uuid ( )
2024-04-27 20:12:06 +02:00
local data = make_staticdata ( nil , pos , dir )
2024-04-12 11:11:46 +02:00
data.uuid = uuid
data.cart_type = entity_id
update_cart_data ( data )
save_cart_data ( uuid )
return uuid
end
local create_minecart = mod.create_minecart
2024-04-05 08:39:42 +02:00
-- Place a minecart at pointed_thing
2024-04-11 09:08:25 +02:00
function mod . place_minecart ( itemstack , pointed_thing , placer )
2024-04-05 08:39:42 +02:00
if not pointed_thing.type == " node " then
return
end
2024-04-06 08:50:30 +02:00
local spawn_pos = pointed_thing.above
local cart_dir = vector.new ( 1 , 0 , 0 )
2024-04-09 22:52:11 +02:00
local railpos , node
2024-04-05 08:39:42 +02:00
if mcl_minecarts : is_rail ( pointed_thing.under ) then
railpos = pointed_thing.under
elseif mcl_minecarts : is_rail ( pointed_thing.above ) then
railpos = pointed_thing.above
2024-04-06 08:50:30 +02:00
end
if railpos then
spawn_pos = railpos
node = minetest.get_node ( railpos )
2024-04-09 22:52:11 +02:00
cart_dir = mcl_minecarts : get_rail_direction ( railpos , vector.new ( 1 , 0 , 0 ) )
2024-04-05 08:39:42 +02:00
end
local entity_id = entity_mapping [ itemstack : get_name ( ) ]
2024-04-12 11:11:46 +02:00
local uuid = create_minecart ( entity_id , railpos , cart_dir )
2024-04-09 22:52:11 +02:00
2024-04-10 00:32:58 +02:00
-- Create the entity with the staticdata already setup
local sd = minetest.serialize ( { uuid = uuid , seq = 1 } )
local cart = minetest.add_entity ( spawn_pos , entity_id , sd )
2024-04-27 20:12:06 +02:00
local staticdata = get_cart_data ( uuid )
2024-04-10 00:32:58 +02:00
cart : set_yaw ( minetest.dir_to_yaw ( cart_dir ) )
2024-04-05 08:39:42 +02:00
-- Call placer
2024-04-27 20:12:06 +02:00
local le = cart : get_luaentity ( )
2024-04-05 08:39:42 +02:00
if le._mcl_minecarts_on_place then
le._mcl_minecarts_on_place ( le , placer )
end
2024-04-06 08:50:30 +02:00
if railpos then
2024-04-27 20:12:06 +02:00
handle_cart_enter ( staticdata , railpos )
2024-04-06 08:50:30 +02:00
end
2024-04-05 08:39:42 +02:00
2024-04-27 20:12:06 +02:00
local pname = placer and placer : get_player_name ( ) or " "
2024-04-05 08:39:42 +02:00
if not minetest.is_creative_enabled ( pname ) then
itemstack : take_item ( )
end
return itemstack
end
local function dropper_place_minecart ( dropitem , pos )
-- Don't try to place the minecart if pos isn't a rail
2024-04-06 09:33:47 +02:00
local node = minetest.get_node ( pos )
if minetest.get_item_group ( node.name , " rail " ) == 0 then return false end
2024-04-05 08:39:42 +02:00
2024-04-11 09:08:25 +02:00
mod.place_minecart ( dropitem , {
2024-04-05 08:39:42 +02:00
above = pos ,
under = vector.offset ( pos , 0 , - 1 , 0 )
} )
return true
end
local function register_minecart_craftitem ( itemstring , def )
local groups = { minecart = 1 , transport = 1 }
if def.creative == false then
groups.not_in_creative_inventory = 1
end
local item_def = {
stack_max = 1 ,
_mcl_dropper_on_drop = dropper_place_minecart ,
on_place = function ( itemstack , placer , pointed_thing )
if not pointed_thing.type == " node " then
return
end
-- Call on_rightclick if the pointed node defines it
local node = minetest.get_node ( pointed_thing.under )
if placer and not placer : get_player_control ( ) . sneak then
if minetest.registered_nodes [ node.name ] and minetest.registered_nodes [ node.name ] . on_rightclick then
return minetest.registered_nodes [ node.name ] . on_rightclick ( pointed_thing.under , node , placer , itemstack ) or itemstack
end
end
2024-04-11 09:08:25 +02:00
return mod.place_minecart ( itemstack , pointed_thing , placer )
2024-04-05 08:39:42 +02:00
end ,
_on_dispense = function ( stack , pos , droppos , dropnode , dropdir )
-- Place minecart as entity on rail. If there's no rail, just drop it.
local placed
if minetest.get_item_group ( dropnode.name , " rail " ) ~= 0 then
-- FIXME: This places minecarts even if the spot is already occupied
local pointed_thing = { under = droppos , above = vector.new ( droppos.x , droppos.y + 1 , droppos.z ) }
2024-04-11 09:08:25 +02:00
placed = mod.place_minecart ( stack , pointed_thing )
2024-04-05 08:39:42 +02:00
end
if placed == nil then
-- Drop item
minetest.add_item ( droppos , stack )
end
end ,
groups = groups ,
}
item_def.description = def.description
item_def._tt_help = def.tt_help
item_def._doc_items_longdesc = def.longdesc
item_def._doc_items_usagehelp = def.usagehelp
item_def.inventory_image = def.icon
item_def.wield_image = def.icon
minetest.register_craftitem ( itemstring , item_def )
end
--[[
Register a minecart
* itemstring : Itemstring of minecart item
* entity_id : ID of minecart entity
* description : Item name / description
* longdesc : Long help text
* usagehelp : Usage help text
* mesh : Minecart mesh
* textures : Minecart textures table
* icon : Item icon
* drop : Dropped items after destroying minecart
* on_rightclick : Called after rightclick
* on_activate_by_rail : Called when above activator rail
* creative : If false , don ' t show in Creative Inventory
] ]
2024-04-11 09:08:25 +02:00
function mod . register_minecart ( def )
-- Make sure all required parameters are present
for _ , name in pairs ( { " drop " , " itemstring " , " entity_id " } ) do
assert ( def [ name ] , " def. " .. name .. " , a required parameter, is missing " )
end
2024-04-05 08:39:42 +02:00
local entity_id = def.entity_id ; def.entity_id = nil
local craft = def.craft ; def.craft = nil
local itemstring = def.itemstring ; def.itemstring = nil
-- Build cart definition
local cart = table.copy ( DEFAULT_CART_DEF )
table_merge ( cart , def )
minetest.register_entity ( entity_id , cart )
-- Register item to entity mapping
entity_mapping [ itemstring ] = entity_id
register_minecart_craftitem ( itemstring , def )
if minetest.get_modpath ( " doc_identifier " ) then
doc.sub . identifier.register_object ( entity_id , " craftitems " , itemstring )
end
if craft then
minetest.register_craft ( craft )
end
end
2024-04-11 09:08:25 +02:00
local register_minecart = mod.register_minecart
2024-04-05 08:39:42 +02:00
2024-04-06 19:09:54 +02:00
dofile ( modpath .. " /carts/minecart.lua " )
dofile ( modpath .. " /carts/with_chest.lua " )
dofile ( modpath .. " /carts/with_commandblock.lua " )
dofile ( modpath .. " /carts/with_hopper.lua " )
dofile ( modpath .. " /carts/with_furnace.lua " )
dofile ( modpath .. " /carts/with_tnt.lua " )
2024-04-05 08:39:42 +02:00
if minetest.get_modpath ( " mcl_wip " ) then
mcl_wip.register_wip_item ( " mcl_minecarts:chest_minecart " )
mcl_wip.register_wip_item ( " mcl_minecarts:furnace_minecart " )
mcl_wip.register_wip_item ( " mcl_minecarts:command_block_minecart " )
end
2024-04-06 15:40:40 +02:00
2024-04-07 14:27:53 +02:00
local function respawn_cart ( cart )
local cart_type = cart.cart_type or " mcl_minecarts:minecart "
local pos = mod.get_cart_position ( cart )
2024-04-10 00:32:58 +02:00
local players = minetest.get_connected_players ( )
local distance = nil
for _ , player in pairs ( players ) do
local d = vector.distance ( player : get_pos ( ) , pos )
if not distance or d < distance then distance = d end
end
2024-04-10 01:27:49 +02:00
if not distance or distance > 90 then return end
2024-04-10 00:32:58 +02:00
2024-04-12 22:47:47 +02:00
mcl_log ( " Respawning cart # " .. cart.uuid .. " at " .. tostring ( pos ) .. " ,distance= " .. distance .. " ,node= " .. minetest.get_node ( pos ) . name )
2024-04-07 14:27:53 +02:00
-- Update sequence so that old cart entities get removed
cart.seq = ( cart.seq or 1 ) + 1
save_cart_data ( cart.uuid )
2024-04-10 01:27:49 +02:00
-- Create the new entity and refresh caches
2024-04-10 00:32:58 +02:00
local sd = minetest.serialize ( { uuid = cart.uuid , seq = cart.seq } )
local entity = minetest.add_entity ( pos , cart_type , sd )
2024-04-07 14:27:53 +02:00
local le = entity : get_luaentity ( )
le._staticdata = cart
2024-04-10 01:27:49 +02:00
mcl_util.assign_uuid ( entity )
2024-04-07 14:27:53 +02:00
-- 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 ( )
2024-04-11 02:04:59 +02:00
mod.add_blocks_to_map (
block_map ,
vector.offset ( pos , - CART_BLOCK_SIZE , - CART_BLOCK_SIZE , - CART_BLOCK_SIZE ) ,
vector.offset ( pos , CART_BLOCK_SIZE , CART_BLOCK_SIZE , CART_BLOCK_SIZE )
)
2024-04-07 14:27:53 +02:00
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
2024-04-06 15:40:40 +02:00
minetest.register_globalstep ( function ( dtime )
2024-04-12 14:28:24 +02:00
-- Periodically respawn carts that come into range of a player
2024-04-07 14:27:53 +02:00
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
2024-04-09 22:52:11 +02:00
timer = duration / 250e-6 -- Schedule 50us per second
if timer > 5 then timer = 5 end
2024-04-07 14:27:53 +02:00
end
2024-04-09 22:52:11 +02:00
-- Handle periodically updating out-of-range carts
-- TODO: change how often cart positions are updated based on velocity
2024-04-12 14:28:24 +02:00
local start_time
if DEBUG then start_time = minetest.get_us_time ( ) end
2024-04-09 22:52:11 +02:00
for uuid , staticdata in mod.carts ( ) do
local pos = mod.get_cart_position ( staticdata )
--[[
2024-04-11 10:18:52 +02:00
local le = mcl_util.get_luaentity_from_uuid ( staticdata.uuid )
2024-04-09 22:52:11 +02:00
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 )
end
end
2024-04-12 14:28:24 +02:00
if DEBUG then
local stop_time = minetest.get_us_time ( )
print ( " Update took " .. ( ( stop_time - start_time ) * 1e-6 ) .. " seconds " )
end
2024-04-06 15:40:40 +02:00
end )
2024-04-12 21:01:15 +02:00
minetest.register_on_joinplayer ( function ( player )
2024-04-12 23:25:40 +02:00
-- Try cart reattachment
2024-04-12 21:01:15 +02:00
local player_name = player : get_player_name ( )
2024-04-12 22:47:47 +02:00
local player_meta = mcl_playerinfo.get_mod_meta ( player_name , modname )
local cart_uuid = player_meta.attached_to
2024-04-12 21:01:15 +02:00
if cart_uuid then
local cartdata = get_cart_data ( cart_uuid )
-- Can't get into a cart that was destroyed
if not cartdata then
return
end
-- Don't reattach players if someone else got in the cart
if cartdata.last_player ~= player_name then
return
end
minetest.after ( 0.2 , function ( player_name , cart_uuid )
local player = minetest.get_player_by_name ( player_name )
if not player then
return
end
local cart = mcl_util.get_luaentity_from_uuid ( cart_uuid )
if not cart then
return
end
mod.attach_driver ( cart , player )
end , player_name , cart_uuid )
end
end )