add jumpdrive (modified)
34
jumpdrive/.luacheckrc
Normal file
@ -0,0 +1,34 @@
|
||||
unused_args = false
|
||||
allow_defined_top = true
|
||||
|
||||
ignore = {"512"}
|
||||
|
||||
globals = {
|
||||
"jumpdrive",
|
||||
|
||||
-- write
|
||||
"travelnet",
|
||||
"pipeworks",
|
||||
"beds"
|
||||
}
|
||||
|
||||
read_globals = {
|
||||
-- Stdlib
|
||||
string = {fields = {"split"}},
|
||||
table = {fields = {"copy", "getn"}},
|
||||
|
||||
-- Minetest
|
||||
"minetest",
|
||||
"vector", "ItemStack",
|
||||
"dump", "VoxelArea",
|
||||
|
||||
-- Deps
|
||||
"unified_inventory", "default", "monitoring",
|
||||
"digilines",
|
||||
"mesecons",
|
||||
"technic",
|
||||
"locator",
|
||||
"display_api",
|
||||
"areas",
|
||||
"ropes"
|
||||
}
|
19
jumpdrive/backbone.lua
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
minetest.register_node("jumpdrive:backbone", {
|
||||
description = "Jumpdrive Backbone",
|
||||
|
||||
tiles = {"jumpdrive_backbone.png"},
|
||||
groups = {cracky=3,oddly_breakable_by_hand=3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
light_source = 13
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'jumpdrive:backbone',
|
||||
recipe = {
|
||||
{'technic:composite_plate', 'default:mese_block', 'technic:composite_plate'},
|
||||
{'technic:stainless_steel_block', 'default:obsidian', 'technic:stainless_steel_block'},
|
||||
{'technic:composite_plate', 'default:mese_block', 'technic:composite_plate'}
|
||||
}
|
||||
})
|
19
jumpdrive/backbone.lua.ORIG
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
minetest.register_node("jumpdrive:backbone", {
|
||||
description = "Jumpdrive Backbone",
|
||||
|
||||
tiles = {"jumpdrive_backbone.png"},
|
||||
groups = {cracky=3,oddly_breakable_by_hand=3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
light_source = 13
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'jumpdrive:backbone',
|
||||
recipe = {
|
||||
{'default:mese_block', 'default:steelblock', 'default:mese_block'},
|
||||
{'default:steelblock', 'default:steelblock', 'default:steelblock'},
|
||||
{'default:mese_block', 'default:steelblock', 'default:mese_block'}
|
||||
}
|
||||
})
|
23
jumpdrive/blacklist.lua
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
if minetest.get_modpath("technic") then
|
||||
table.insert(jumpdrive.blacklist, "technic:forcefield_emitter_on")
|
||||
end
|
||||
|
||||
if minetest.get_modpath("advtrains") then
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_atc_st")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_cr")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_cr_30")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_cr_45")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_cr_60")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_detector_off_st")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_st")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_st_30")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_st_45")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_st_60")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_vst1")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:dtrack_vst2")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:platform_high_stonebrick")
|
||||
table.insert(jumpdrive.blacklist, "advtrains:platform_low_stonebrick")
|
||||
end
|
||||
|
||||
-- TODO bedrock, advtrains tracks
|
6
jumpdrive/blacklist.lua.ORIG
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
if minetest.get_modpath("technic") then
|
||||
table.insert(jumpdrive.blacklist, "technic:forcefield_emitter_on")
|
||||
end
|
||||
|
||||
-- TODO bedrock, advtrains tracks
|
366
jumpdrive/common.lua
Normal file
@ -0,0 +1,366 @@
|
||||
|
||||
jumpdrive.sanitize_coord = function(coord)
|
||||
return math.max( math.min( coord, 31000 ), -31000 )
|
||||
end
|
||||
|
||||
-- get pos object from pos
|
||||
jumpdrive.get_meta_pos = function(pos)
|
||||
local meta = minetest.get_meta(pos);
|
||||
return {x=meta:get_int("x"), y=meta:get_int("y"), z=meta:get_int("z")}
|
||||
end
|
||||
|
||||
-- set pos object from pos
|
||||
jumpdrive.set_meta_pos = function(pos, target)
|
||||
local meta = minetest.get_meta(pos);
|
||||
meta:set_int("x", target.x)
|
||||
meta:set_int("y", target.y)
|
||||
meta:set_int("z", target.z)
|
||||
end
|
||||
|
||||
-- get offset from meta
|
||||
jumpdrive.get_radius = function(pos)
|
||||
local meta = minetest.get_meta(pos);
|
||||
return meta:get_int("radius")
|
||||
end
|
||||
|
||||
-- calculates the power requirements for a jump
|
||||
jumpdrive.calculate_power = function(radius, distance, sourcePos, targetPos)
|
||||
return 10 * distance * radius
|
||||
end
|
||||
|
||||
jumpdrive.simulate_jump = function(pos, player, show_marker)
|
||||
|
||||
local targetPos = jumpdrive.get_meta_pos(pos)
|
||||
|
||||
if jumpdrive.check_mapgen(pos) then
|
||||
return false, "Error: mapgen was active in this area, please try again later for your own safety!"
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local radius = jumpdrive.get_radius(pos)
|
||||
local distance = vector.distance(pos, targetPos)
|
||||
|
||||
local playername = meta:get_string("owner")
|
||||
|
||||
if player ~= nil then
|
||||
playername = player:get_player_name()
|
||||
end
|
||||
|
||||
local radius_vector = {x=radius, y=radius, z=radius}
|
||||
local source_pos1 = vector.subtract(pos, radius_vector)
|
||||
local source_pos2 = vector.add(pos, radius_vector)
|
||||
local target_pos1 = vector.subtract(targetPos, radius_vector)
|
||||
local target_pos2 = vector.add(targetPos, radius_vector)
|
||||
|
||||
local x_overlap = (target_pos1.x <= source_pos2.x and target_pos1.x >= source_pos1.x) or
|
||||
(target_pos2.x <= source_pos2.x and target_pos2.x >= source_pos1.x)
|
||||
local y_overlap = (target_pos1.y <= source_pos2.y and target_pos1.y >= source_pos1.y) or
|
||||
(target_pos2.y <= source_pos2.y and target_pos2.y >= source_pos1.y)
|
||||
local z_overlap = (target_pos1.z <= source_pos2.z and target_pos1.z >= source_pos1.z) or
|
||||
(target_pos2.z <= source_pos2.z and target_pos2.z >= source_pos1.z)
|
||||
|
||||
if x_overlap and y_overlap and z_overlap then
|
||||
return false, "Error: jump into itself! extend your jump target"
|
||||
end
|
||||
|
||||
-- load chunk
|
||||
minetest.get_voxel_manip():read_from_map(target_pos1, target_pos2)
|
||||
|
||||
if show_marker then
|
||||
jumpdrive.show_marker(targetPos, radius, "red")
|
||||
jumpdrive.show_marker(pos, radius, "green")
|
||||
end
|
||||
|
||||
local msg = nil
|
||||
local success = true
|
||||
|
||||
local blacklisted_pos_list = minetest.find_nodes_in_area(source_pos1, source_pos2, jumpdrive.blacklist)
|
||||
for _, nodepos in ipairs(blacklisted_pos_list) do
|
||||
return false, "Can't jump node @ " .. minetest.pos_to_string(nodepos)
|
||||
end
|
||||
|
||||
if minetest.find_node_near(targetPos, radius, "vacuum:vacuum", true) then
|
||||
msg = "Warning: Jump-target is in vacuum!"
|
||||
end
|
||||
|
||||
if minetest.find_node_near(targetPos, radius, "ignore", true) then
|
||||
return false, "Warning: Jump-target is in uncharted area"
|
||||
end
|
||||
|
||||
if jumpdrive.is_area_protected(source_pos1, source_pos2, playername) then
|
||||
return false, "Jump-source is protected!"
|
||||
end
|
||||
|
||||
if jumpdrive.is_area_protected(target_pos1, target_pos2, playername) then
|
||||
return false, "Jump-target is protected!"
|
||||
end
|
||||
|
||||
local is_empty, empty_msg = jumpdrive.is_area_empty(target_pos1, target_pos2)
|
||||
|
||||
if not is_empty then
|
||||
msg = "Jump-target is obstructed (" .. empty_msg .. ")"
|
||||
success = false
|
||||
end
|
||||
|
||||
-- check preflight conditions
|
||||
local preflight_result = jumpdrive.preflight_check(pos, targetPos, radius, playername)
|
||||
|
||||
if not preflight_result.success then
|
||||
-- check failed in customization
|
||||
msg = "Preflight check failed!"
|
||||
if preflight_result.message then
|
||||
msg = preflight_result.message
|
||||
end
|
||||
success = false
|
||||
end
|
||||
|
||||
local power_req = jumpdrive.calculate_power(radius, distance, pos, targetPos)
|
||||
local powerstorage = meta:get_int("powerstorage")
|
||||
|
||||
if powerstorage < power_req then
|
||||
-- not enough power
|
||||
msg = "Not enough power: required=" .. math.floor(power_req) .. ", actual: " .. powerstorage .. " EU"
|
||||
success = false
|
||||
end
|
||||
|
||||
return success, msg
|
||||
end
|
||||
|
||||
-- preflight check, for overriding
|
||||
jumpdrive.preflight_check = function(source, destination, radius, playername)
|
||||
return { success=true }
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- execute jump
|
||||
jumpdrive.execute_jump = function(pos, player)
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local playername = meta:get_string("owner")
|
||||
|
||||
if player ~= nil then
|
||||
playername = player:get_player_name()
|
||||
end
|
||||
|
||||
|
||||
local radius = jumpdrive.get_radius(pos)
|
||||
local targetPos = jumpdrive.get_meta_pos(pos)
|
||||
|
||||
local distance = vector.distance(pos, targetPos)
|
||||
local power_req = jumpdrive.calculate_power(radius, distance, pos, targetPos)
|
||||
|
||||
local radius_vector = {x=radius, y=radius, z=radius}
|
||||
local source_pos1 = vector.subtract(pos, radius_vector)
|
||||
local source_pos2 = vector.add(pos, radius_vector)
|
||||
local target_pos1 = vector.subtract(targetPos, radius_vector)
|
||||
local target_pos2 = vector.add(targetPos, radius_vector)
|
||||
|
||||
local success, msg = jumpdrive.simulate_jump(pos, player, false)
|
||||
if not success then
|
||||
minetest.chat_send_player(playername, msg)
|
||||
return false, msg
|
||||
end
|
||||
|
||||
-- consume power from storage
|
||||
local powerstorage = meta:get_int("powerstorage")
|
||||
meta:set_int("powerstorage", powerstorage - power_req)
|
||||
|
||||
local t0 = minetest.get_us_time()
|
||||
|
||||
minetest.sound_play("jumpdrive_engine", {
|
||||
pos = pos,
|
||||
max_hear_distance = 50,
|
||||
gain = 0.7,
|
||||
})
|
||||
|
||||
-- actual move
|
||||
jumpdrive.move(source_pos1, source_pos2, target_pos1, target_pos2)
|
||||
|
||||
local t1 = minetest.get_us_time()
|
||||
local time_micros = t1 - t0
|
||||
local time_millis = math.floor(time_micros / 1000)
|
||||
|
||||
minetest.log("action", "[jumpdrive] jump took " .. time_micros .. " us")
|
||||
minetest.chat_send_player(playername, "Jump executed in " .. time_millis .. " ms")
|
||||
|
||||
|
||||
-- show animation in source
|
||||
minetest.add_particlespawner({
|
||||
amount = 200,
|
||||
time = 2,
|
||||
minpos = source_pos1,
|
||||
maxpos = source_pos2,
|
||||
minvel = {x = -2, y = -2, z = -2},
|
||||
maxvel = {x = 2, y = 2, z = 2},
|
||||
minacc = {x = -3, y = -3, z = -3},
|
||||
maxacc = {x = 3, y = 3, z = 3},
|
||||
minexptime = 0.1,
|
||||
maxexptime = 5,
|
||||
minsize = 1,
|
||||
maxsize = 1,
|
||||
texture = "spark.png",
|
||||
glow = 5,
|
||||
})
|
||||
|
||||
|
||||
-- show animation in target
|
||||
minetest.add_particlespawner({
|
||||
amount = 200,
|
||||
time = 2,
|
||||
minpos = target_pos1,
|
||||
maxpos = target_pos2,
|
||||
minvel = {x = -2, y = -2, z = -2},
|
||||
maxvel = {x = 2, y = 2, z = 2},
|
||||
minacc = {x = -3, y = -3, z = -3},
|
||||
maxacc = {x = 3, y = 3, z = 3},
|
||||
minexptime = 0.1,
|
||||
maxexptime = 5,
|
||||
minsize = 1,
|
||||
maxsize = 1,
|
||||
texture = "spark.png",
|
||||
glow = 5,
|
||||
})
|
||||
|
||||
return true, time_micros
|
||||
end
|
||||
|
||||
|
||||
jumpdrive.update_formspec = function(meta, pos)
|
||||
|
||||
meta:set_string("formspec", "size[8,10;]" ..
|
||||
"field[0,1;2,1;x;X;" .. meta:get_int("x") .. "]" ..
|
||||
"field[2,1;2,1;y;Y;" .. meta:get_int("y") .. "]" ..
|
||||
"field[4,1;2,1;z;Z;" .. meta:get_int("z") .. "]" ..
|
||||
"field[6,1;2,1;radius;Radius;" .. meta:get_int("radius") .. "]" ..
|
||||
|
||||
"button_exit[0,2;2,1;jump;Jump]" ..
|
||||
"button_exit[2,2;2,1;show;Show]" ..
|
||||
"button_exit[4,2;2,1;save;Save]" ..
|
||||
"button[6,2;2,1;reset;Reset]" ..
|
||||
|
||||
"list[context;main;0,3;8,1;]" ..
|
||||
|
||||
"button[0,4;4,1;write_book;Write to book]" ..
|
||||
"button[4,4;4,1;read_book;Read from book]" ..
|
||||
|
||||
"list[current_player;main;0,5;8,4;]" ..
|
||||
|
||||
-- listring stuff
|
||||
"listring[]")
|
||||
end
|
||||
|
||||
jumpdrive.write_to_book = function(pos, sender)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
if inv:contains_item("main", {name="default:book", count=1}) then
|
||||
local stack = inv:remove_item("main", {name="default:book", count=1})
|
||||
|
||||
local new_stack = ItemStack("default:book_written")
|
||||
|
||||
local data = {}
|
||||
|
||||
data.owner = sender:get_player_name()
|
||||
data.title = "Jumpdrive coordinates"
|
||||
data.description = "Jumpdrive coordiates"
|
||||
data.text = minetest.serialize(jumpdrive.get_meta_pos(pos))
|
||||
data.page = 1
|
||||
data.page_max = 1
|
||||
|
||||
new_stack:get_meta():from_table({ fields = data })
|
||||
|
||||
if inv:room_for_item("main", new_stack) then
|
||||
-- put written book back
|
||||
inv:add_item("main", new_stack)
|
||||
else
|
||||
-- put back old stack
|
||||
inv:add_item("main", stack)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
jumpdrive.read_from_book = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local player_name = meta:get_string("owner")
|
||||
|
||||
if inv:contains_item("main", {name="default:book_written", count=1}) then
|
||||
local stack = inv:remove_item("main", {name="default:book_written", count=1})
|
||||
local stackMeta = stack:get_meta()
|
||||
|
||||
local text = stackMeta:get_string("text")
|
||||
local data = minetest.deserialize(text)
|
||||
|
||||
if data == nil then
|
||||
-- put book back, it may contain other information
|
||||
inv:add_item("main", stack)
|
||||
-- alert player
|
||||
if nil ~= player_name then
|
||||
minetest.chat_send_player(player_name, "Invalid data")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local x = tonumber(data.x)
|
||||
local y = tonumber(data.y)
|
||||
local z = tonumber(data.z)
|
||||
|
||||
if x == nil or y == nil or z == nil then
|
||||
-- put book back, it may contain other information
|
||||
inv:add_item("main", stack)
|
||||
-- alert player
|
||||
if nil ~= player_name then
|
||||
minetest.chat_send_player(player_name, "Invalid coordinates")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
meta:set_int("x", jumpdrive.sanitize_coord(x))
|
||||
meta:set_int("y", jumpdrive.sanitize_coord(y))
|
||||
meta:set_int("z", jumpdrive.sanitize_coord(z))
|
||||
|
||||
-- put book back
|
||||
inv:add_item("main", stack)
|
||||
elseif inv:contains_item("main", {name="missions:wand_position", count=1}) then
|
||||
local stack = inv:remove_item("main", {name="missions:wand_position", count=1})
|
||||
local stackMeta = stack:get_meta()
|
||||
|
||||
local text = stackMeta:get_string("pos")
|
||||
local target_pos = minetest.string_to_pos(text)
|
||||
|
||||
if nil == target_pos then
|
||||
-- put wand back, I don't see a way to corrupt a wand atm
|
||||
inv:add_item("main", stack)
|
||||
return
|
||||
end
|
||||
|
||||
local x = target_pos.x
|
||||
local y = target_pos.y
|
||||
local z = target_pos.z
|
||||
|
||||
if x == nil or y == nil or z == nil then
|
||||
-- put wand back, I don't see a way to corrupt a wand atm
|
||||
inv:add_item("main", stack)
|
||||
return
|
||||
end
|
||||
|
||||
meta:set_int("x", jumpdrive.sanitize_coord(x))
|
||||
meta:set_int("y", jumpdrive.sanitize_coord(y))
|
||||
meta:set_int("z", jumpdrive.sanitize_coord(z))
|
||||
|
||||
-- put wand back
|
||||
inv:add_item("main", stack)
|
||||
end
|
||||
end
|
||||
|
||||
jumpdrive.reset_coordinates = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
meta:set_int("x", pos.x)
|
||||
meta:set_int("y", pos.y)
|
||||
meta:set_int("z", pos.z)
|
||||
|
||||
end
|
57
jumpdrive/compat/anchor.lua
Normal file
@ -0,0 +1,57 @@
|
||||
-- stolen from technic / anchor.lua
|
||||
|
||||
local function compute_forceload_positions(pos, meta)
|
||||
local radius = meta:get_int("radius")
|
||||
local minpos = vector.subtract(pos, vector.new(radius, radius, radius))
|
||||
local maxpos = vector.add(pos, vector.new(radius, radius, radius))
|
||||
local minbpos = {}
|
||||
local maxbpos = {}
|
||||
for _, coord in ipairs({"x","y","z"}) do
|
||||
minbpos[coord] = math.floor(minpos[coord] / 16) * 16
|
||||
maxbpos[coord] = math.floor(maxpos[coord] / 16) * 16
|
||||
end
|
||||
local flposes = {}
|
||||
for x = minbpos.x, maxbpos.x, 16 do
|
||||
for y = minbpos.y, maxbpos.y, 16 do
|
||||
for z = minbpos.z, maxbpos.z, 16 do
|
||||
table.insert(flposes, vector.new(x, y, z))
|
||||
end
|
||||
end
|
||||
end
|
||||
return flposes
|
||||
end
|
||||
|
||||
local function currently_forceloaded_positions(meta)
|
||||
local ser = meta:get_string("forceloaded")
|
||||
return ser == "" and {} or minetest.deserialize(ser)
|
||||
end
|
||||
|
||||
local function forceload_off(meta)
|
||||
local flposes = currently_forceloaded_positions(meta)
|
||||
meta:set_string("forceloaded", "")
|
||||
for _, p in ipairs(flposes) do
|
||||
minetest.forceload_free_block(p)
|
||||
end
|
||||
end
|
||||
|
||||
local function forceload_on(pos, meta)
|
||||
local want_flposes = compute_forceload_positions(pos, meta)
|
||||
local have_flposes = {}
|
||||
for _, p in ipairs(want_flposes) do
|
||||
if minetest.forceload_block(p) then
|
||||
table.insert(have_flposes, p)
|
||||
end
|
||||
end
|
||||
meta:set_string("forceloaded", #have_flposes == 0 and "" or minetest.serialize(have_flposes))
|
||||
end
|
||||
|
||||
jumpdrive.anchor_compat = function(from, to)
|
||||
local to_meta = minetest.get_meta(to)
|
||||
local from_meta = minetest.get_meta(from)
|
||||
|
||||
if from_meta:get_int("enabled") ~= 0 then
|
||||
-- anchor enabled
|
||||
forceload_off(from_meta)
|
||||
forceload_on(to, to_meta)
|
||||
end
|
||||
end
|
64
jumpdrive/compat/beds.lua
Normal file
@ -0,0 +1,64 @@
|
||||
local bed_bottoms = {"beds:bed_bottom", "beds:fancy_bed_bottom"}
|
||||
|
||||
-- Calculate a bed's middle position (where players would spawn)
|
||||
local function calc_bed_middle(bed_pos, facedir)
|
||||
local dir = minetest.facedir_to_dir(facedir)
|
||||
local bed_middle = {
|
||||
x = bed_pos.x + dir.x / 2,
|
||||
y = bed_pos.y,
|
||||
z = bed_pos.z + dir.z / 2
|
||||
}
|
||||
return bed_middle
|
||||
end
|
||||
|
||||
jumpdrive.beds_compat = function(target_pos1, target_pos2, delta_vector)
|
||||
if beds == nil or
|
||||
beds.spawn == nil or
|
||||
beds.save_spawns == nil then
|
||||
-- Something is wrong. Don't do anything
|
||||
return
|
||||
end
|
||||
|
||||
-- Look for beds in target area
|
||||
local beds_list = minetest.find_nodes_in_area(target_pos1, target_pos2, bed_bottoms)
|
||||
|
||||
if next(beds_list) ~= nil then
|
||||
-- We found some beds!
|
||||
local source_pos1 = vector.subtract(target_pos1, delta_vector)
|
||||
local source_pos2 = vector.subtract(target_pos2, delta_vector)
|
||||
|
||||
-- Look for players with spawn in source area
|
||||
local affected_players = {}
|
||||
for name, pos in pairs(beds.spawn) do
|
||||
-- pos1 and pos2 must already be sorted
|
||||
if pos.x >= source_pos1.x and pos.x <= source_pos2.x and
|
||||
pos.y >= source_pos1.y and pos.y <= source_pos2.y and
|
||||
pos.z >= source_pos1.z and pos.z <= source_pos2.z then
|
||||
table.insert(affected_players, name)
|
||||
end
|
||||
end
|
||||
|
||||
if next(affected_players) ~= nil then
|
||||
-- Some players seem to be affected.
|
||||
-- Iterate over all beds
|
||||
for _, pos in pairs(beds_list) do
|
||||
local facedir = minetest.get_node(pos).param2
|
||||
local old_middle = calc_bed_middle(vector.subtract(pos, delta_vector), facedir)
|
||||
|
||||
for _, name in ipairs(affected_players) do
|
||||
local spawn = beds.spawn[name]
|
||||
if spawn.x == old_middle.x and
|
||||
spawn.y == old_middle.y and
|
||||
spawn.z == old_middle.z then
|
||||
---- Player spawn seems to match old bed position; update
|
||||
beds.spawn[name] = calc_bed_middle(pos, facedir)
|
||||
minetest.log("action",
|
||||
"[jumpdrive] Updated bed spawn for player " .. name)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Tell beds mod to save the new spawns.
|
||||
beds.save_spawns()
|
||||
end
|
||||
end
|
||||
end
|
71
jumpdrive/compat/compat.lua
Normal file
@ -0,0 +1,71 @@
|
||||
local MP = minetest.get_modpath("jumpdrive")
|
||||
|
||||
local has_travelnet_mod = minetest.get_modpath("travelnet")
|
||||
local has_technic_mod = minetest.get_modpath("technic")
|
||||
local has_locator_mod = minetest.get_modpath("locator")
|
||||
local has_elevator_mod = minetest.get_modpath("elevator")
|
||||
local has_display_mod = minetest.get_modpath("display_api")
|
||||
local has_pipeworks_mod = minetest.get_modpath("pipeworks")
|
||||
local has_beds_mod = minetest.get_modpath("beds")
|
||||
local has_ropes_mod = minetest.get_modpath("ropes")
|
||||
|
||||
dofile(MP.."/compat/travelnet.lua")
|
||||
dofile(MP.."/compat/locator.lua")
|
||||
dofile(MP.."/compat/elevator.lua")
|
||||
dofile(MP.."/compat/signs.lua")
|
||||
dofile(MP.."/compat/itemframes.lua")
|
||||
dofile(MP.."/compat/anchor.lua")
|
||||
dofile(MP.."/compat/telemosaic.lua")
|
||||
dofile(MP.."/compat/beds.lua")
|
||||
dofile(MP.."/compat/ropes.lua")
|
||||
|
||||
if has_pipeworks_mod then
|
||||
dofile(MP.."/compat/teleporttube.lua")
|
||||
end
|
||||
|
||||
|
||||
jumpdrive.node_compat = function(name, source_pos, target_pos)
|
||||
if (name == "locator:beacon_1" or name == "locator:beacon_2" or name == "locator:beacon_3") and has_locator_mod then
|
||||
jumpdrive.locator_compat(source_pos, target_pos)
|
||||
|
||||
elseif has_technic_mod and name == "technic:admin_anchor" then
|
||||
jumpdrive.anchor_compat(source_pos, target_pos)
|
||||
|
||||
elseif has_pipeworks_mod and string.find(name, "^pipeworks:teleport_tube") then
|
||||
jumpdrive.teleporttube_compat(source_pos, target_pos)
|
||||
|
||||
elseif name == "telemosaic:beacon" or name == "telemosaic:beacon_protected" then
|
||||
jumpdrive.telemosaic_compat(source_pos, target_pos)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
jumpdrive.commit_node_compat = function()
|
||||
if has_pipeworks_mod then
|
||||
jumpdrive.teleporttube_compat_commit()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
jumpdrive.target_region_compat = function(pos1, pos2, delta_vector)
|
||||
if has_travelnet_mod then
|
||||
jumpdrive.travelnet_compat(pos1, pos2)
|
||||
end
|
||||
|
||||
if has_elevator_mod then
|
||||
jumpdrive.elevator_compat(pos1, pos2)
|
||||
end
|
||||
|
||||
if has_display_mod then
|
||||
jumpdrive.signs_compat(pos1, pos2)
|
||||
end
|
||||
|
||||
if has_beds_mod then
|
||||
jumpdrive.beds_compat(pos1, pos2, delta_vector)
|
||||
end
|
||||
|
||||
if has_ropes_mod then
|
||||
jumpdrive.ropes_compat(pos1, pos2, delta_vector)
|
||||
end
|
||||
end
|
||||
|
18
jumpdrive/compat/elevator.lua
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
jumpdrive.elevator_compat = function(pos1, pos2)
|
||||
|
||||
-- find potential elevators
|
||||
local elevator_motors = minetest.find_nodes_in_area(pos1, pos2, "elevator:motor")
|
||||
|
||||
for _,pos in ipairs(elevator_motors) do
|
||||
-- delegate to compat
|
||||
|
||||
local def = minetest.registered_nodes["elevator:motor"]
|
||||
minetest.log("action", "[jumpdrive] Restoring elevator @ " .. pos.x .. "/" .. pos.y .. "/" .. pos.z)
|
||||
|
||||
-- function(pos, placer, itemstack)
|
||||
def.after_place_node(pos, nil, nil)
|
||||
end
|
||||
|
||||
end
|
20
jumpdrive/compat/itemframes.lua
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
local update_item = function(pos, node)
|
||||
-- TODO
|
||||
end
|
||||
|
||||
|
||||
jumpdrive.itemframes_compat = function(pos1, pos2)
|
||||
|
||||
local nodes = minetest.find_nodes_in_area(pos1, pos2, {"itemframes:pedestal", "itemframes:frame"})
|
||||
|
||||
if nodes then
|
||||
for _,pos in pairs(nodes) do
|
||||
minetest.log("action", "[jumpdrive] updating itemframe @ " .. minetest.pos_to_string(pos))
|
||||
local node = minetest.get_node(pos)
|
||||
update_item(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
8
jumpdrive/compat/locator.lua
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
jumpdrive.locator_compat = function(from, to)
|
||||
local meta = minetest.get_meta(to)
|
||||
locator.remove_beacon(from)
|
||||
locator.update_beacon(to, meta)
|
||||
end
|
||||
|
86
jumpdrive/compat/ropes.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local rope_nodes = { -- Top, middle, bottom
|
||||
{"ropes:rope_top", "ropes:rope", "ropes:rope_bottom"}, -- Rope boxes
|
||||
{"ropes:ropeladder_falling", "ropes:ropeladder", "ropes:ropeladder_bottom"}, -- Rope ladders
|
||||
}
|
||||
|
||||
jumpdrive.ropes_compat = function(target_pos1, target_pos2, delta_vector)
|
||||
if ropes == nil or
|
||||
ropes.destroy_rope == nil then
|
||||
-- Something is wrong. Don't do anything
|
||||
return
|
||||
end
|
||||
|
||||
-- Bottom slice of the target area
|
||||
local target_bottom_pos1 = target_pos1
|
||||
local target_bottom_pos2 = {
|
||||
x = target_pos2.x,
|
||||
y = target_pos1.y,
|
||||
z = target_pos2.z
|
||||
}
|
||||
|
||||
-- Top slice of the target area
|
||||
local target_top_pos1 = {
|
||||
x = target_pos1.x,
|
||||
y = target_pos2.y,
|
||||
z = target_pos1.z
|
||||
}
|
||||
local target_top_pos2 = target_pos2
|
||||
|
||||
|
||||
|
||||
-- For every type of rope
|
||||
for _, rope_type_nodes in ipairs(rope_nodes) do
|
||||
|
||||
-- Look for ropes hanging out of the jump area
|
||||
local ropes_hanging_out = minetest.find_nodes_in_area(
|
||||
target_bottom_pos1, target_bottom_pos2,
|
||||
{rope_type_nodes[1], rope_type_nodes[2]})
|
||||
|
||||
for _, pos in ipairs(ropes_hanging_out) do
|
||||
-- Swap with a proper end node, keeping param2
|
||||
local end_node = minetest.get_node(pos)
|
||||
minetest.swap_node(pos, {
|
||||
name=rope_type_nodes[3],
|
||||
param2=end_node.param2
|
||||
})
|
||||
|
||||
-- Destroy remainder of the rope below the source area
|
||||
local remainder_pos = {
|
||||
x = pos.x - delta_vector.x,
|
||||
y = pos.y - delta_vector.y - 1,
|
||||
z = pos.z - delta_vector.z
|
||||
}
|
||||
ropes.destroy_rope(remainder_pos, rope_type_nodes)
|
||||
end
|
||||
|
||||
|
||||
-- Look for ropes hanging into the jump area
|
||||
local ropes_hanging_in = minetest.find_nodes_in_area(
|
||||
target_top_pos1, target_top_pos2,
|
||||
rope_type_nodes)
|
||||
|
||||
for _, pos in ipairs(ropes_hanging_in) do
|
||||
-- Probably there is a loose end above the source area
|
||||
local end_pos = {
|
||||
x = pos.x - delta_vector.x,
|
||||
y = pos.y - delta_vector.y + 1,
|
||||
z = pos.z - delta_vector.z
|
||||
}
|
||||
local end_node = minetest.get_node(end_pos)
|
||||
|
||||
if end_node and
|
||||
(end_node.name == rope_type_nodes[1] or
|
||||
end_node.name == rope_type_nodes[2]) then
|
||||
|
||||
-- Swap with a proper end node, keeping param2
|
||||
minetest.swap_node(end_pos, {
|
||||
name=rope_type_nodes[3],
|
||||
param2=end_node.param2
|
||||
})
|
||||
end
|
||||
|
||||
-- Destroy remainder of the rope in the target area
|
||||
ropes.destroy_rope(pos, rope_type_nodes)
|
||||
end
|
||||
end
|
||||
end
|
13
jumpdrive/compat/signs.lua
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
jumpdrive.signs_compat = function(pos1, pos2)
|
||||
|
||||
local nodes = minetest.find_nodes_in_area(pos1, pos2, {"group:display_modpack_node"})
|
||||
|
||||
if nodes then
|
||||
for _,pos in pairs(nodes) do
|
||||
minetest.log("action", "[jumpdrive] updating display @ " .. minetest.pos_to_string(pos))
|
||||
display_api.update_entities(pos)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
47
jumpdrive/compat/telemosaic.lua
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
local function unhash_pos(hash)
|
||||
local pos = {}
|
||||
local list = string.split(hash, ':')
|
||||
pos.x = tonumber(list[1])
|
||||
pos.y = tonumber(list[2])
|
||||
pos.z = tonumber(list[3])
|
||||
return pos
|
||||
end
|
||||
|
||||
local function hash_pos(pos)
|
||||
return math.floor(pos.x + 0.5) .. ':' ..
|
||||
math.floor(pos.y + 0.5) .. ':' ..
|
||||
math.floor(pos.z + 0.5)
|
||||
end
|
||||
|
||||
jumpdrive.telemosaic_compat = function(source_pos, target_pos)
|
||||
|
||||
-- delegate to compat
|
||||
minetest.log("action", "[jumpdrive] Trying to rewire telemosaic @ " ..
|
||||
target_pos.x .. "/" .. target_pos.y .. "/" .. target_pos.z)
|
||||
|
||||
local local_meta = minetest.get_meta(target_pos)
|
||||
local local_hash = local_meta:get_string('telemosaic:dest')
|
||||
|
||||
if local_hash ~= nil and local_hash ~= '' then
|
||||
local local_pos = unhash_pos(local_hash)
|
||||
|
||||
minetest.load_area(local_pos)
|
||||
local node = minetest.get_node(local_pos)
|
||||
|
||||
if node.name == "telemosaic:beacon" then
|
||||
local remote_hash = minetest.get_meta(local_pos):get_string('telemosaic:dest')
|
||||
|
||||
if remote_hash == hash_pos(source_pos) then
|
||||
-- remote beacon points to this beacon, update link
|
||||
local remote_pos = unhash_pos(remote_hash)
|
||||
local remote_meta = minetest.get_meta(remote_pos)
|
||||
|
||||
minetest.log("action", "[jumpdrive] rewiring telemosaic at " .. minetest.pos_to_string(remote_pos) ..
|
||||
" to " .. minetest.pos_to_string(target_pos))
|
||||
|
||||
remote_meta:set_string("telemosaic:dest", hash_pos(target_pos))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
47
jumpdrive/compat/teleporttube.lua
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
|
||||
if not pipeworks.tptube then
|
||||
minetest.log("warning", "[jumpdrive] pipeworks teleport patch not applied, tp-tubes don't work as expected!")
|
||||
end
|
||||
|
||||
|
||||
-- https://gitlab.com/VanessaE/pipeworks/blob/master/teleport_tube.lua
|
||||
jumpdrive.teleporttube_compat = function(from, to)
|
||||
if not pipeworks.tptube then
|
||||
-- only works with the patch from "./patches/pipeworks.patch"
|
||||
return
|
||||
end
|
||||
|
||||
local from_hash = pipeworks.tptube.hash(from)
|
||||
local to_hash = pipeworks.tptube.hash(to)
|
||||
|
||||
-- swap data
|
||||
local db = pipeworks.tptube.get_db()
|
||||
local data = db[from_hash]
|
||||
|
||||
if not data then
|
||||
minetest.log("warning", "[jumpdrive] no tp-tube data found at hash: " ..
|
||||
from_hash .. " / pos: " .. minetest.pos_to_string(from))
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log("action", "[jumpdrive] moving tp-tube data from " ..
|
||||
from_hash .. " to " .. to_hash .. " at pos: " .. minetest.pos_to_string(from))
|
||||
|
||||
data.x = to.x
|
||||
data.y = to.y
|
||||
data.z = to.z
|
||||
|
||||
db[from_hash] = nil
|
||||
db[to_hash] = data
|
||||
|
||||
end
|
||||
|
||||
jumpdrive.teleporttube_compat_commit = function()
|
||||
if not pipeworks.tptube then
|
||||
-- only works with the patch from "./patches/pipeworks.patch"
|
||||
return
|
||||
end
|
||||
|
||||
pipeworks.tptube.save_tube_db()
|
||||
end
|
25
jumpdrive/compat/travelnet.lua
Normal file
@ -0,0 +1,25 @@
|
||||
jumpdrive.travelnet_compat = function(pos1, pos2)
|
||||
|
||||
local pos_list = minetest.find_nodes_in_area(pos1, pos2, {"travelnet:travelnet"})
|
||||
if pos_list then
|
||||
for _,pos in pairs(pos_list) do
|
||||
local meta = minetest.get_meta(pos);
|
||||
minetest.log("action", "[jumpdrive] Restoring travelnet @ " .. pos.x .. "/" .. pos.y .. "/" .. pos.z)
|
||||
|
||||
local owner_name = meta:get_string( "owner" );
|
||||
local station_name = meta:get_string( "station_name" );
|
||||
local station_network = meta:get_string( "station_network" );
|
||||
|
||||
if (travelnet.targets[owner_name]
|
||||
and travelnet.targets[owner_name][station_network]
|
||||
and travelnet.targets[owner_name][station_network][station_name]) then
|
||||
|
||||
travelnet.targets[owner_name][station_network][station_name].pos = pos
|
||||
|
||||
end
|
||||
end
|
||||
if travelnet.save_data ~= nil then
|
||||
travelnet.save_data()
|
||||
end
|
||||
end
|
||||
end
|
84
jumpdrive/digiline.lua
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
--https://github.com/minetest-mods/technic/blob/master/technic/machines/HV/forcefield.lua
|
||||
|
||||
jumpdrive.digiline_effector = function(pos, _, channel, msg)
|
||||
local set_channel = "jumpdrive" -- static channel for now
|
||||
|
||||
local msgt = type(msg)
|
||||
|
||||
if msgt ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
if channel ~= set_channel then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
local radius = jumpdrive.get_radius(pos)
|
||||
local targetPos = jumpdrive.get_meta_pos(pos)
|
||||
|
||||
local distance = vector.distance(pos, targetPos)
|
||||
local power_req = jumpdrive.calculate_power(radius, distance, pos, targetPos)
|
||||
|
||||
if msg.command == "get" then
|
||||
digilines.receptor_send(pos, digilines.rules.default, set_channel, {
|
||||
powerstorage = meta:get_int("powerstorage"),
|
||||
radius = radius,
|
||||
position = pos,
|
||||
target = targetPos,
|
||||
distance = distance,
|
||||
power_req = power_req
|
||||
})
|
||||
|
||||
elseif msg.command == "reset" then
|
||||
meta:set_int("x", pos.x)
|
||||
meta:set_int("y", pos.y)
|
||||
meta:set_int("z", pos.z)
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
|
||||
elseif msg.command == "set" then
|
||||
local value = tonumber(msg.value)
|
||||
|
||||
if value == nil then
|
||||
-- not a number
|
||||
return
|
||||
end
|
||||
|
||||
if msg.key == "x" then
|
||||
meta:set_int("x", value)
|
||||
elseif msg.key == "y" then
|
||||
meta:set_int("y", value)
|
||||
elseif msg.key == "z" then
|
||||
meta:set_int("z", value)
|
||||
elseif msg.key == "radius" then
|
||||
if value >= 1 and value <= jumpdrive.config.max_radius then
|
||||
meta:set_int("radius", value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
elseif msg.command == "simulate" or msg.command == "show" then
|
||||
local success, resultmsg = jumpdrive.simulate_jump(pos)
|
||||
|
||||
digilines.receptor_send(pos, digilines.rules.default, set_channel, {
|
||||
success=success,
|
||||
msg=resultmsg
|
||||
})
|
||||
|
||||
elseif msg.command == "jump" then
|
||||
local success, time = jumpdrive.execute_jump(pos)
|
||||
|
||||
local send_pos = pos
|
||||
if success then
|
||||
-- send new message in target pos
|
||||
send_pos = targetPos
|
||||
end
|
||||
|
||||
digilines.receptor_send(send_pos, digilines.rules.default, set_channel, {
|
||||
success = success,
|
||||
time = time
|
||||
})
|
||||
end
|
||||
end
|
178
jumpdrive/engine.lua
Normal file
@ -0,0 +1,178 @@
|
||||
|
||||
minetest.register_node("jumpdrive:engine", {
|
||||
description = "Jumpdrive",
|
||||
|
||||
tiles = {"jumpdrive.png"},
|
||||
|
||||
tube = {
|
||||
insert_object = function(pos, node, stack, direction)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv:add_item("main", stack)
|
||||
end,
|
||||
can_insert = function(pos, node, stack, direction)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
stack = stack:peek_item(1)
|
||||
|
||||
return inv:room_for_item("main", stack)
|
||||
end,
|
||||
input_inventory = "main",
|
||||
connect_sides = {bottom = 1}
|
||||
},
|
||||
|
||||
connects_to = {"group:technic_hv_cable"},
|
||||
connect_sides = {"bottom", "top", "left", "right", "front", "back"},
|
||||
|
||||
light_source = 13,
|
||||
groups = {cracky=3,oddly_breakable_by_hand=3,tubedevice=1, tubedevice_receiver=1,technic_machine = 1, technic_hv = 1},
|
||||
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
|
||||
digiline = {
|
||||
receptor = {action = function() end},
|
||||
effector = {
|
||||
action = jumpdrive.digiline_effector
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("owner", placer:get_player_name() or "")
|
||||
end,
|
||||
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("x", pos.x)
|
||||
meta:set_int("y", pos.y)
|
||||
meta:set_int("z", pos.z)
|
||||
meta:set_int("radius", 5)
|
||||
meta:set_int("powerstorage", 0)
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 8)
|
||||
|
||||
meta:set_int("HV_EU_input", 0)
|
||||
meta:set_int("HV_EU_demand", 0)
|
||||
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
end,
|
||||
|
||||
can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory()
|
||||
local name = player:get_player_name()
|
||||
|
||||
return inv:is_empty("main") and not minetest.is_protected(pos, name)
|
||||
end,
|
||||
|
||||
technic_run = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local eu_input = meta:get_int("HV_EU_input")
|
||||
local demand = meta:get_int("HV_EU_demand")
|
||||
local store = meta:get_int("powerstorage")
|
||||
|
||||
meta:set_string("infotext", "Power: " .. eu_input .. "/" .. demand .. " Store: " .. store)
|
||||
|
||||
if store < jumpdrive.config.powerstorage then
|
||||
-- charge
|
||||
meta:set_int("HV_EU_demand", jumpdrive.config.powerrequirement)
|
||||
store = store + eu_input
|
||||
meta:set_int("powerstorage", math.min(store, jumpdrive.config.powerstorage))
|
||||
else
|
||||
-- charged
|
||||
meta:set_int("HV_EU_demand", 0)
|
||||
end
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
|
||||
if not sender then
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.is_protected(pos, sender:get_player_name()) then
|
||||
-- not allowed
|
||||
return
|
||||
end
|
||||
|
||||
if fields.read_book then
|
||||
jumpdrive.read_from_book(pos)
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.reset then
|
||||
jumpdrive.reset_coordinates(pos)
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.write_book then
|
||||
jumpdrive.write_to_book(pos, sender)
|
||||
return
|
||||
end
|
||||
|
||||
local x = tonumber(fields.x);
|
||||
local y = tonumber(fields.y);
|
||||
local z = tonumber(fields.z);
|
||||
local radius = tonumber(fields.radius);
|
||||
|
||||
if x == nil or y == nil or z == nil or radius == nil or radius < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local max_radius = jumpdrive.config.max_radius
|
||||
|
||||
if radius > max_radius then
|
||||
minetest.chat_send_player(sender:get_player_name(), "Invalid jump: max-radius=" .. max_radius)
|
||||
return
|
||||
end
|
||||
|
||||
-- update coords
|
||||
meta:set_int("x", jumpdrive.sanitize_coord(x))
|
||||
meta:set_int("y", jumpdrive.sanitize_coord(y))
|
||||
meta:set_int("z", jumpdrive.sanitize_coord(z))
|
||||
meta:set_int("radius", radius)
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
|
||||
if fields.jump then
|
||||
jumpdrive.execute_jump(pos, sender)
|
||||
end
|
||||
|
||||
if fields.show then
|
||||
local success, msg = jumpdrive.simulate_jump(pos, sender, true)
|
||||
if not success then
|
||||
minetest.chat_send_player(sender:get_player_name(), msg)
|
||||
return
|
||||
end
|
||||
minetest.chat_send_player(sender:get_player_name(), "Simulation successful")
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
on_punch = function(pos, node, puncher)
|
||||
|
||||
if minetest.is_protected(pos, puncher:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
local radius = meta:get_int("radius")
|
||||
|
||||
jumpdrive.show_marker(pos, radius, "green")
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'jumpdrive:engine',
|
||||
recipe = {
|
||||
{'jumpdrive:backbone', 'default:diamondblock', 'jumpdrive:backbone'},
|
||||
{'default:diamondblock', 'technic:blue_energy_crystal', 'default:diamondblock'},
|
||||
{'jumpdrive:backbone', 'technic:hv_transformer', 'jumpdrive:backbone'}
|
||||
}
|
||||
})
|
||||
|
||||
technic.register_machine("HV", "jumpdrive:engine", technic.receiver)
|
178
jumpdrive/engine.lua.ORIG
Normal file
@ -0,0 +1,178 @@
|
||||
|
||||
minetest.register_node("jumpdrive:engine", {
|
||||
description = "Jumpdrive",
|
||||
|
||||
tiles = {"jumpdrive.png"},
|
||||
|
||||
tube = {
|
||||
insert_object = function(pos, node, stack, direction)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
return inv:add_item("main", stack)
|
||||
end,
|
||||
can_insert = function(pos, node, stack, direction)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
stack = stack:peek_item(1)
|
||||
|
||||
return inv:room_for_item("main", stack)
|
||||
end,
|
||||
input_inventory = "main",
|
||||
connect_sides = {bottom = 1}
|
||||
},
|
||||
|
||||
connects_to = {"group:technic_hv_cable"},
|
||||
connect_sides = {"bottom", "top", "left", "right", "front", "back"},
|
||||
|
||||
light_source = 13,
|
||||
groups = {cracky=3,oddly_breakable_by_hand=3,tubedevice=1, tubedevice_receiver=1,technic_machine = 1, technic_hv = 1},
|
||||
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
|
||||
digiline = {
|
||||
receptor = {action = function() end},
|
||||
effector = {
|
||||
action = jumpdrive.digiline_effector
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("owner", placer:get_player_name() or "")
|
||||
end,
|
||||
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("x", pos.x)
|
||||
meta:set_int("y", pos.y)
|
||||
meta:set_int("z", pos.z)
|
||||
meta:set_int("radius", 5)
|
||||
meta:set_int("powerstorage", 0)
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 8)
|
||||
|
||||
meta:set_int("HV_EU_input", 0)
|
||||
meta:set_int("HV_EU_demand", 0)
|
||||
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
end,
|
||||
|
||||
can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory()
|
||||
local name = player:get_player_name()
|
||||
|
||||
return inv:is_empty("main") and not minetest.is_protected(pos, name)
|
||||
end,
|
||||
|
||||
technic_run = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local eu_input = meta:get_int("HV_EU_input")
|
||||
local demand = meta:get_int("HV_EU_demand")
|
||||
local store = meta:get_int("powerstorage")
|
||||
|
||||
meta:set_string("infotext", "Power: " .. eu_input .. "/" .. demand .. " Store: " .. store)
|
||||
|
||||
if store < jumpdrive.config.powerstorage then
|
||||
-- charge
|
||||
meta:set_int("HV_EU_demand", jumpdrive.config.powerrequirement)
|
||||
store = store + eu_input
|
||||
meta:set_int("powerstorage", math.min(store, jumpdrive.config.powerstorage))
|
||||
else
|
||||
-- charged
|
||||
meta:set_int("HV_EU_demand", 0)
|
||||
end
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
|
||||
if not sender then
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.is_protected(pos, sender:get_player_name()) then
|
||||
-- not allowed
|
||||
return
|
||||
end
|
||||
|
||||
if fields.read_book then
|
||||
jumpdrive.read_from_book(pos)
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.reset then
|
||||
jumpdrive.reset_coordinates(pos)
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.write_book then
|
||||
jumpdrive.write_to_book(pos, sender)
|
||||
return
|
||||
end
|
||||
|
||||
local x = tonumber(fields.x);
|
||||
local y = tonumber(fields.y);
|
||||
local z = tonumber(fields.z);
|
||||
local radius = tonumber(fields.radius);
|
||||
|
||||
if x == nil or y == nil or z == nil or radius == nil or radius < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local max_radius = jumpdrive.config.max_radius
|
||||
|
||||
if radius > max_radius then
|
||||
minetest.chat_send_player(sender:get_player_name(), "Invalid jump: max-radius=" .. max_radius)
|
||||
return
|
||||
end
|
||||
|
||||
-- update coords
|
||||
meta:set_int("x", jumpdrive.sanitize_coord(x))
|
||||
meta:set_int("y", jumpdrive.sanitize_coord(y))
|
||||
meta:set_int("z", jumpdrive.sanitize_coord(z))
|
||||
meta:set_int("radius", radius)
|
||||
jumpdrive.update_formspec(meta, pos)
|
||||
|
||||
if fields.jump then
|
||||
jumpdrive.execute_jump(pos, sender)
|
||||
end
|
||||
|
||||
if fields.show then
|
||||
local success, msg = jumpdrive.simulate_jump(pos, sender, true)
|
||||
if not success then
|
||||
minetest.chat_send_player(sender:get_player_name(), msg)
|
||||
return
|
||||
end
|
||||
minetest.chat_send_player(sender:get_player_name(), "Simulation successful")
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
on_punch = function(pos, node, puncher)
|
||||
|
||||
if minetest.is_protected(pos, puncher:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
local radius = meta:get_int("radius")
|
||||
|
||||
jumpdrive.show_marker(pos, radius, "green")
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'jumpdrive:engine',
|
||||
recipe = {
|
||||
{'jumpdrive:backbone', 'default:steelblock', 'jumpdrive:backbone'},
|
||||
{'default:steelblock', 'default:steelblock', 'default:steelblock'},
|
||||
{'jumpdrive:backbone', 'default:steelblock', 'jumpdrive:backbone'}
|
||||
}
|
||||
})
|
||||
|
||||
technic.register_machine("HV", "jumpdrive:engine", technic.receiver)
|
231
jumpdrive/fleet_controller.lua
Normal file
@ -0,0 +1,231 @@
|
||||
|
||||
local update_formspec = function(meta, pos)
|
||||
|
||||
local active = meta:get_int("active")
|
||||
|
||||
local button_line =
|
||||
"button_exit[0,2;2,1;jump;Jump]" ..
|
||||
"button_exit[2,2;2,1;show;Show]" ..
|
||||
"button_exit[4,2;2,1;save;Save]" ..
|
||||
"button[6,2;2,1;reset;Reset]"
|
||||
|
||||
if active == 1 then
|
||||
local jump_index = meta:get_int("jump_index")
|
||||
local jump_list = minetest.deserialize( meta:get_string("jump_list") )
|
||||
|
||||
meta:set_string("infotext", "Controller active: " .. jump_index .. "/" .. #jump_list)
|
||||
|
||||
button_line = "button_exit[0,2;8,1;stop;Stop]"
|
||||
else
|
||||
meta:set_string("infotext", "Ready")
|
||||
end
|
||||
|
||||
meta:set_string("formspec", "size[8,10;]" ..
|
||||
"field[0,1;2,1;x;X;" .. meta:get_int("x") .. "]" ..
|
||||
"field[3,1;2,1;y;Y;" .. meta:get_int("y") .. "]" ..
|
||||
"field[6,1;2,1;z;Z;" .. meta:get_int("z") .. "]" ..
|
||||
|
||||
button_line ..
|
||||
|
||||
"list[context;main;0,3;8,1;]" ..
|
||||
|
||||
"button[0,4;4,1;write_book;Write to book]" ..
|
||||
"button[4,4;4,1;read_book;Read from book]" ..
|
||||
|
||||
"list[current_player;main;0,5;8,4;]" ..
|
||||
|
||||
-- listring stuff
|
||||
"listring[]")
|
||||
end
|
||||
|
||||
minetest.register_node("jumpdrive:fleet_controller", {
|
||||
description = "Jumpdrive Fleet controller",
|
||||
|
||||
tiles = {"jumpdrive_fleet_controller_top.png", "jumpdrive_fleet_controller.png"},
|
||||
groups = {cracky=3,oddly_breakable_by_hand=3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
|
||||
light_source = 13,
|
||||
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("x", pos.x)
|
||||
meta:set_int("y", pos.y)
|
||||
meta:set_int("z", pos.z)
|
||||
|
||||
-- jumping active (1=active)
|
||||
meta:set_int("active", 0)
|
||||
-- if active, current index in jump list (1...n)
|
||||
meta:set_int("jump_index", 0)
|
||||
-- jump list
|
||||
meta:set_string("jump_list", "")
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 8)
|
||||
|
||||
update_formspec(meta, pos)
|
||||
end,
|
||||
|
||||
can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory()
|
||||
local name = player:get_player_name()
|
||||
|
||||
return inv:is_empty("main") and not minetest.is_protected(pos, name)
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
|
||||
if not sender then
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.is_protected(pos, sender:get_player_name()) then
|
||||
-- not allowed
|
||||
return
|
||||
end
|
||||
|
||||
if fields.read_book then
|
||||
jumpdrive.read_from_book(pos)
|
||||
update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.reset then
|
||||
jumpdrive.reset_coordinates(pos)
|
||||
update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.write_book then
|
||||
jumpdrive.write_to_book(pos, sender)
|
||||
return
|
||||
end
|
||||
|
||||
local x = tonumber(fields.x);
|
||||
local y = tonumber(fields.y);
|
||||
local z = tonumber(fields.z);
|
||||
|
||||
if x == nil or y == nil or z == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- update coords
|
||||
meta:set_int("x", x)
|
||||
meta:set_int("y", y)
|
||||
meta:set_int("z", z)
|
||||
update_formspec(meta, pos)
|
||||
|
||||
local t0 = minetest.get_us_time()
|
||||
local engines_pos_list = jumpdrive.fleet.find_engines(pos)
|
||||
local t1 = minetest.get_us_time()
|
||||
minetest.log("action", "[jumpdrive-fleet] backbone traversing took " ..
|
||||
(t1 - t0) .. " us @ " .. minetest.pos_to_string(pos))
|
||||
|
||||
local targetPos = {x=meta:get_int("x"),y=meta:get_int("y"),z=meta:get_int("z")}
|
||||
|
||||
-- sort by distance, farthes first
|
||||
jumpdrive.fleet.sort_engines(pos, engines_pos_list)
|
||||
|
||||
-- apply new coordinates
|
||||
jumpdrive.fleet.apply_coordinates(pos, targetPos, engines_pos_list)
|
||||
|
||||
if fields.jump then
|
||||
--TODO check overlapping engines/radius
|
||||
meta:set_int("active", 1)
|
||||
meta:set_int("jump_index", 1)
|
||||
meta:set_string("jump_list", minetest.serialize(engines_pos_list))
|
||||
update_formspec(meta, pos)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(2.0)
|
||||
end
|
||||
|
||||
if fields.stop then
|
||||
meta:set_int("active", 0)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:stop()
|
||||
update_formspec(meta, pos)
|
||||
end
|
||||
|
||||
if fields.show then
|
||||
local playername = sender:get_player_name()
|
||||
minetest.chat_send_player(playername, "Found " .. #engines_pos_list .. " jumpdrives")
|
||||
|
||||
if #engines_pos_list == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local index = 1
|
||||
local async_check
|
||||
async_check = function()
|
||||
local engine_pos = engines_pos_list[index]
|
||||
local success, msg = jumpdrive.simulate_jump(engine_pos, sender, true)
|
||||
if not success then
|
||||
minetest.chat_send_player(playername, msg .. " @ " .. minetest.pos_to_string(engine_pos))
|
||||
return
|
||||
end
|
||||
|
||||
minetest.chat_send_player(sender:get_player_name(), "Check passed for engine " .. index .. "/" .. #engines_pos_list)
|
||||
|
||||
if index < #engines_pos_list then
|
||||
-- more drives to check
|
||||
index = index + 1
|
||||
minetest.after(1, async_check)
|
||||
|
||||
elseif index >= #engines_pos_list then
|
||||
-- done
|
||||
minetest.chat_send_player(sender:get_player_name(), "Simulation successful")
|
||||
end
|
||||
end
|
||||
|
||||
minetest.after(1, async_check)
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
on_timer = function(pos, elapsed)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local jump_index = meta:get_int("jump_index")
|
||||
local jump_list = minetest.deserialize( meta:get_string("jump_list") )
|
||||
|
||||
if jump_list and jump_index and #jump_list >= jump_index then
|
||||
|
||||
local is_last = #jump_list == jump_index
|
||||
|
||||
local node_pos = jump_list[jump_index]
|
||||
local success, msg = jumpdrive.execute_jump(node_pos)
|
||||
|
||||
if success then
|
||||
-- at this point if it is the last engine the metadata does not exist anymore in the current location
|
||||
|
||||
if not is_last then
|
||||
meta:set_int("jump_index", jump_index+1)
|
||||
update_formspec(meta, pos)
|
||||
|
||||
-- re-schedule
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(2.0)
|
||||
end
|
||||
else
|
||||
meta:set_int("active", 0)
|
||||
update_formspec(meta, pos)
|
||||
meta:set_string("infotext", "Engine ".. minetest.pos_to_string(node_pos) .. " failed with: " .. msg)
|
||||
end
|
||||
else
|
||||
meta:set_int("active", 0)
|
||||
update_formspec(meta, pos)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'jumpdrive:fleet_controller',
|
||||
recipe = {
|
||||
{'jumpdrive:engine', 'jumpdrive:backbone', 'jumpdrive:engine'},
|
||||
{'jumpdrive:backbone', 'technic:control_logic_unit', 'jumpdrive:backbone'},
|
||||
{'jumpdrive:engine', 'jumpdrive:backbone', 'jumpdrive:engine'}
|
||||
}
|
||||
})
|
231
jumpdrive/fleet_controller.lua.ORIG
Normal file
@ -0,0 +1,231 @@
|
||||
|
||||
local update_formspec = function(meta, pos)
|
||||
|
||||
local active = meta:get_int("active")
|
||||
|
||||
local button_line =
|
||||
"button_exit[0,2;2,1;jump;Jump]" ..
|
||||
"button_exit[2,2;2,1;show;Show]" ..
|
||||
"button_exit[4,2;2,1;save;Save]" ..
|
||||
"button[6,2;2,1;reset;Reset]"
|
||||
|
||||
if active == 1 then
|
||||
local jump_index = meta:get_int("jump_index")
|
||||
local jump_list = minetest.deserialize( meta:get_string("jump_list") )
|
||||
|
||||
meta:set_string("infotext", "Controller active: " .. jump_index .. "/" .. #jump_list)
|
||||
|
||||
button_line = "button_exit[0,2;8,1;stop;Stop]"
|
||||
else
|
||||
meta:set_string("infotext", "Ready")
|
||||
end
|
||||
|
||||
meta:set_string("formspec", "size[8,10;]" ..
|
||||
"field[0,1;2,1;x;X;" .. meta:get_int("x") .. "]" ..
|
||||
"field[3,1;2,1;y;Y;" .. meta:get_int("y") .. "]" ..
|
||||
"field[6,1;2,1;z;Z;" .. meta:get_int("z") .. "]" ..
|
||||
|
||||
button_line ..
|
||||
|
||||
"list[context;main;0,3;8,1;]" ..
|
||||
|
||||
"button[0,4;4,1;write_book;Write to book]" ..
|
||||
"button[4,4;4,1;read_book;Read from book]" ..
|
||||
|
||||
"list[current_player;main;0,5;8,4;]" ..
|
||||
|
||||
-- listring stuff
|
||||
"listring[]")
|
||||
end
|
||||
|
||||
minetest.register_node("jumpdrive:fleet_controller", {
|
||||
description = "Jumpdrive Fleet controller",
|
||||
|
||||
tiles = {"jumpdrive_fleet_controller.png"},
|
||||
groups = {cracky=3,oddly_breakable_by_hand=3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
|
||||
light_source = 13,
|
||||
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int("x", pos.x)
|
||||
meta:set_int("y", pos.y)
|
||||
meta:set_int("z", pos.z)
|
||||
|
||||
-- jumping active (1=active)
|
||||
meta:set_int("active", 0)
|
||||
-- if active, current index in jump list (1...n)
|
||||
meta:set_int("jump_index", 0)
|
||||
-- jump list
|
||||
meta:set_string("jump_list", "")
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 8)
|
||||
|
||||
update_formspec(meta, pos)
|
||||
end,
|
||||
|
||||
can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory()
|
||||
local name = player:get_player_name()
|
||||
|
||||
return inv:is_empty("main") and not minetest.is_protected(pos, name)
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
|
||||
local meta = minetest.get_meta(pos);
|
||||
|
||||
if not sender then
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.is_protected(pos, sender:get_player_name()) then
|
||||
-- not allowed
|
||||
return
|
||||
end
|
||||
|
||||
if fields.read_book then
|
||||
jumpdrive.read_from_book(pos)
|
||||
update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.reset then
|
||||
jumpdrive.reset_coordinates(pos)
|
||||
update_formspec(meta, pos)
|
||||
return
|
||||
end
|
||||
|
||||
if fields.write_book then
|
||||
jumpdrive.write_to_book(pos, sender)
|
||||
return
|
||||
end
|
||||
|
||||
local x = tonumber(fields.x);
|
||||
local y = tonumber(fields.y);
|
||||
local z = tonumber(fields.z);
|
||||
|
||||
if x == nil or y == nil or z == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- update coords
|
||||
meta:set_int("x", x)
|
||||
meta:set_int("y", y)
|
||||
meta:set_int("z", z)
|
||||
update_formspec(meta, pos)
|
||||
|
||||
local t0 = minetest.get_us_time()
|
||||
local engines_pos_list = jumpdrive.fleet.find_engines(pos)
|
||||
local t1 = minetest.get_us_time()
|
||||
minetest.log("action", "[jumpdrive-fleet] backbone traversing took " ..
|
||||
(t1 - t0) .. " us @ " .. minetest.pos_to_string(pos))
|
||||
|
||||
local targetPos = {x=meta:get_int("x"),y=meta:get_int("y"),z=meta:get_int("z")}
|
||||
|
||||
-- sort by distance, farthes first
|
||||
jumpdrive.fleet.sort_engines(pos, engines_pos_list)
|
||||
|
||||
-- apply new coordinates
|
||||
jumpdrive.fleet.apply_coordinates(pos, targetPos, engines_pos_list)
|
||||
|
||||
if fields.jump then
|
||||
--TODO check overlapping engines/radius
|
||||
meta:set_int("active", 1)
|
||||
meta:set_int("jump_index", 1)
|
||||
meta:set_string("jump_list", minetest.serialize(engines_pos_list))
|
||||
update_formspec(meta, pos)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(2.0)
|
||||
end
|
||||
|
||||
if fields.stop then
|
||||
meta:set_int("active", 0)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:stop()
|
||||
update_formspec(meta, pos)
|
||||
end
|
||||
|
||||
if fields.show then
|
||||
local playername = sender:get_player_name()
|
||||
minetest.chat_send_player(playername, "Found " .. #engines_pos_list .. " jumpdrives")
|
||||
|
||||
if #engines_pos_list == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local index = 1
|
||||
local async_check
|
||||
async_check = function()
|
||||
local engine_pos = engines_pos_list[index]
|
||||
local success, msg = jumpdrive.simulate_jump(engine_pos, sender, true)
|
||||
if not success then
|
||||
minetest.chat_send_player(playername, msg .. " @ " .. minetest.pos_to_string(engine_pos))
|
||||
return
|
||||
end
|
||||
|
||||
minetest.chat_send_player(sender:get_player_name(), "Check passed for engine " .. index .. "/" .. #engines_pos_list)
|
||||
|
||||
if index < #engines_pos_list then
|
||||
-- more drives to check
|
||||
index = index + 1
|
||||
minetest.after(1, async_check)
|
||||
|
||||
elseif index >= #engines_pos_list then
|
||||
-- done
|
||||
minetest.chat_send_player(sender:get_player_name(), "Simulation successful")
|
||||
end
|
||||
end
|
||||
|
||||
minetest.after(1, async_check)
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
on_timer = function(pos, elapsed)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local jump_index = meta:get_int("jump_index")
|
||||
local jump_list = minetest.deserialize( meta:get_string("jump_list") )
|
||||
|
||||
if jump_list and jump_index and #jump_list >= jump_index then
|
||||
|
||||
local is_last = #jump_list == jump_index
|
||||
|
||||
local node_pos = jump_list[jump_index]
|
||||
local success, msg = jumpdrive.execute_jump(node_pos)
|
||||
|
||||
if success then
|
||||
-- at this point if it is the last engine the metadata does not exist anymore in the current location
|
||||
|
||||
if not is_last then
|
||||
meta:set_int("jump_index", jump_index+1)
|
||||
update_formspec(meta, pos)
|
||||
|
||||
-- re-schedule
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(2.0)
|
||||
end
|
||||
else
|
||||
meta:set_int("active", 0)
|
||||
update_formspec(meta, pos)
|
||||
meta:set_string("infotext", "Engine ".. minetest.pos_to_string(node_pos) .. " failed with: " .. msg)
|
||||
end
|
||||
else
|
||||
meta:set_int("active", 0)
|
||||
update_formspec(meta, pos)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'jumpdrive:fleet_controller',
|
||||
recipe = {
|
||||
{'jumpdrive:engine', 'default:steelblock', 'jumpdrive:engine'},
|
||||
{'default:steelblock', 'default:steelblock', 'default:steelblock'},
|
||||
{'jumpdrive:engine', 'default:steelblock', 'jumpdrive:engine'}
|
||||
}
|
||||
})
|
71
jumpdrive/fleet_functions.lua
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
jumpdrive.fleet = {}
|
||||
|
||||
-- applies the new coordinates derived from the relative position of the controller
|
||||
jumpdrive.fleet.apply_coordinates = function(controllerPos, targetPos, engine_pos_list)
|
||||
-- delta between source and target
|
||||
local delta_vector = vector.subtract(targetPos, controllerPos)
|
||||
minetest.log("action", "[jumpdrive-fleet] delta-vector: " .. minetest.pos_to_string(delta_vector))
|
||||
|
||||
for _,node_pos in pairs(engine_pos_list) do
|
||||
local new_pos = vector.add(node_pos, delta_vector)
|
||||
minetest.log("action", "[jumpdrive-fleet] calculated vector: " .. minetest.pos_to_string(new_pos))
|
||||
jumpdrive.set_meta_pos(node_pos, new_pos)
|
||||
end
|
||||
end
|
||||
|
||||
-- sort list by distance, farthest first
|
||||
jumpdrive.fleet.sort_engines = function(pos, engine_pos_list)
|
||||
table.sort(engine_pos_list, function(a,b)
|
||||
local a_distance = vector.distance(a, pos)
|
||||
local b_distance = vector.distance(b, pos)
|
||||
return a_distance > b_distance
|
||||
end)
|
||||
end
|
||||
|
||||
-- traverses the backbone and returns a list of engines
|
||||
jumpdrive.fleet.find_engines = function(pos, visited_hashes, engine_pos_list)
|
||||
|
||||
-- minetest.hash_node_position(pos)
|
||||
visited_hashes = visited_hashes or {}
|
||||
engine_pos_list = engine_pos_list or {}
|
||||
|
||||
local pos1 = vector.subtract(pos, 1)
|
||||
local pos2 = vector.add(pos,1)
|
||||
|
||||
-- load far-away areas
|
||||
local manip = minetest.get_voxel_manip()
|
||||
manip:read_from_map(pos1, pos2)
|
||||
|
||||
local engine_nodes = minetest.find_nodes_in_area(pos1, pos2, {"jumpdrive:engine"})
|
||||
|
||||
for _,node_pos in pairs(engine_nodes) do
|
||||
local hash = minetest.hash_node_position(node_pos)
|
||||
|
||||
if not visited_hashes[hash] then
|
||||
-- pos not yet visited
|
||||
visited_hashes[hash] = true
|
||||
minetest.log("action", "[jumpdrive-fleet] adding engine @ " .. minetest.pos_to_string(node_pos))
|
||||
table.insert(engine_pos_list, node_pos)
|
||||
|
||||
jumpdrive.fleet.find_engines(node_pos, visited_hashes, engine_pos_list)
|
||||
end
|
||||
end
|
||||
|
||||
local backbone_nodes = minetest.find_nodes_in_area(pos1, pos2, {"jumpdrive:backbone"})
|
||||
|
||||
for _,node_pos in pairs(backbone_nodes) do
|
||||
local hash = minetest.hash_node_position(node_pos)
|
||||
|
||||
if not visited_hashes[hash] then
|
||||
-- pos not yet visited
|
||||
visited_hashes[hash] = true
|
||||
|
||||
jumpdrive.fleet.find_engines(node_pos, visited_hashes, engine_pos_list)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
return engine_pos_list
|
||||
end
|
43
jumpdrive/init.lua
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
jumpdrive = {
|
||||
config = {
|
||||
-- technic EU storage value
|
||||
powerstorage = tonumber(minetest.settings:get("jumpdrive.powerstorage")) or 250000,
|
||||
|
||||
-- charge value in EU
|
||||
powerrequirement = tonumber(minetest.settings:get("jumpdrive.power_requirement")) or 2500,
|
||||
|
||||
-- allowed radius
|
||||
max_radius = tonumber(minetest.settings:get("jumpdrive.maxradius")) or 15
|
||||
},
|
||||
|
||||
blacklist = {}
|
||||
}
|
||||
|
||||
local MP = minetest.get_modpath("jumpdrive")
|
||||
|
||||
dofile(MP.."/marker.lua")
|
||||
dofile(MP.."/compat/compat.lua")
|
||||
dofile(MP.."/is_area_empty.lua")
|
||||
dofile(MP.."/is_area_protected.lua")
|
||||
|
||||
dofile(MP.."/move_objects.lua")
|
||||
dofile(MP.."/move_metadata.lua")
|
||||
dofile(MP.."/move_nodetimers.lua")
|
||||
dofile(MP.."/move.lua")
|
||||
|
||||
dofile(MP.."/mapgen.lua")
|
||||
dofile(MP.."/common.lua")
|
||||
dofile(MP.."/digiline.lua")
|
||||
dofile(MP.."/engine.lua")
|
||||
dofile(MP.."/backbone.lua")
|
||||
dofile(MP.."/fleet_functions.lua")
|
||||
dofile(MP.."/fleet_controller.lua")
|
||||
dofile(MP.."/blacklist.lua")
|
||||
|
||||
if minetest.get_modpath("monitoring") then
|
||||
-- enable metrics
|
||||
dofile(MP.."/metrics.lua")
|
||||
end
|
||||
|
||||
print("[OK] Jumpdrive")
|
43
jumpdrive/init.lua.ORIG
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
jumpdrive = {
|
||||
config = {
|
||||
-- technic EU storage value
|
||||
powerstorage = tonumber(minetest.settings:get("jumpdrive.powerstorage")) or 1000000,
|
||||
|
||||
-- charge value in EU
|
||||
powerrequirement = tonumber(minetest.settings:get("jumpdrive.power_requirement")) or 2500,
|
||||
|
||||
-- allowed radius
|
||||
max_radius = tonumber(minetest.settings:get("jumpdrive.maxradius")) or 15
|
||||
},
|
||||
|
||||
blacklist = {}
|
||||
}
|
||||
|
||||
local MP = minetest.get_modpath("jumpdrive")
|
||||
|
||||
dofile(MP.."/marker.lua")
|
||||
dofile(MP.."/compat/compat.lua")
|
||||
dofile(MP.."/is_area_empty.lua")
|
||||
dofile(MP.."/is_area_protected.lua")
|
||||
|
||||
dofile(MP.."/move_objects.lua")
|
||||
dofile(MP.."/move_metadata.lua")
|
||||
dofile(MP.."/move_nodetimers.lua")
|
||||
dofile(MP.."/move.lua")
|
||||
|
||||
dofile(MP.."/mapgen.lua")
|
||||
dofile(MP.."/common.lua")
|
||||
dofile(MP.."/digiline.lua")
|
||||
dofile(MP.."/engine.lua")
|
||||
dofile(MP.."/backbone.lua")
|
||||
dofile(MP.."/fleet_functions.lua")
|
||||
dofile(MP.."/fleet_controller.lua")
|
||||
dofile(MP.."/blacklist.lua")
|
||||
|
||||
if minetest.get_modpath("monitoring") then
|
||||
-- enable metrics
|
||||
dofile(MP.."/metrics.lua")
|
||||
end
|
||||
|
||||
print("[OK] Jumpdrive")
|
47
jumpdrive/is_area_empty.lua
Normal file
@ -0,0 +1,47 @@
|
||||
local c_ignore = minetest.get_content_id("ignore")
|
||||
|
||||
local buildable_to_nodes = {}
|
||||
|
||||
minetest.after(4, function()
|
||||
local count = 0
|
||||
for name, node in pairs(minetest.registered_nodes) do
|
||||
if node.buildable_to then
|
||||
count = count + 1
|
||||
local id = minetest.get_content_id(name)
|
||||
buildable_to_nodes[id] = true
|
||||
end
|
||||
end
|
||||
minetest.log("action", "[jumpdrive] collected " .. count .. " nodes that are buildable_to")
|
||||
end)
|
||||
|
||||
|
||||
|
||||
jumpdrive.is_area_empty = function(pos1, pos2)
|
||||
local manip = minetest.get_voxel_manip()
|
||||
local e1, e2 = manip:read_from_map(pos1, pos2)
|
||||
local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
|
||||
local data = manip:get_data()
|
||||
|
||||
for z=pos1.z, pos2.z do
|
||||
for y=pos1.y, pos2.y do
|
||||
for x=pos1.x, pos2.x do
|
||||
|
||||
local index = area:index(x, y, z)
|
||||
local id = data[index]
|
||||
|
||||
if id == c_ignore then
|
||||
return false, "Uncharted"
|
||||
end
|
||||
|
||||
if not buildable_to_nodes[id] then
|
||||
-- not buildable_to
|
||||
return false, "Occupied"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- only buildable_to nodes found
|
||||
return true, ""
|
||||
end
|
||||
|
42
jumpdrive/is_area_protected.lua
Normal file
@ -0,0 +1,42 @@
|
||||
local has_areas_mod = minetest.get_modpath("areas")
|
||||
local has_protector_mod = minetest.get_modpath("protector")
|
||||
|
||||
local protector_radius = (tonumber(minetest.settings:get("protector_radius")) or 30)
|
||||
|
||||
jumpdrive.is_area_protected = function(pos1, pos2, playername)
|
||||
|
||||
|
||||
if minetest.is_area_protected then
|
||||
-- use area protection check
|
||||
if minetest.is_area_protected(pos1, pos2, playername, 8) then
|
||||
return true
|
||||
end
|
||||
|
||||
elseif has_protector_mod then
|
||||
-- use improvised find_nodes check
|
||||
local radius_vector = {x=protector_radius, y=protector_radius, z=protector_radius}
|
||||
local protectors = minetest.find_nodes_in_area(
|
||||
vector.subtract(pos1, radius_vector),
|
||||
vector.add(pos2, radius_vector),
|
||||
{"protector:protect", "protector:protect2"}
|
||||
)
|
||||
|
||||
if protectors then
|
||||
for _,pos in pairs(protectors) do
|
||||
if minetest.is_protected(pos, playername) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if has_areas_mod then
|
||||
if not areas:canInteractInArea(pos1, pos2, playername, true) then
|
||||
-- player can't interact
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- no protection
|
||||
return false
|
||||
end
|
42
jumpdrive/is_area_protected.lua.ORIG
Normal file
@ -0,0 +1,42 @@
|
||||
local has_areas_mod = minetest.get_modpath("areas")
|
||||
local has_protector_mod = minetest.get_modpath("protector")
|
||||
|
||||
local protector_radius = (tonumber(minetest.settings:get("protector_radius")) or 5)
|
||||
|
||||
jumpdrive.is_area_protected = function(pos1, pos2, playername)
|
||||
|
||||
|
||||
if minetest.is_area_protected then
|
||||
-- use area protection check
|
||||
if minetest.is_area_protected(pos1, pos2, playername, 8) then
|
||||
return true
|
||||
end
|
||||
|
||||
elseif has_protector_mod then
|
||||
-- use improvised find_nodes check
|
||||
local radius_vector = {x=protector_radius, y=protector_radius, z=protector_radius}
|
||||
local protectors = minetest.find_nodes_in_area(
|
||||
vector.subtract(pos1, radius_vector),
|
||||
vector.add(pos2, radius_vector),
|
||||
{"protector:protect", "protector:protect2"}
|
||||
)
|
||||
|
||||
if protectors then
|
||||
for _,pos in pairs(protectors) do
|
||||
if minetest.is_protected(pos, playername) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if has_areas_mod then
|
||||
if not areas:canInteractInArea(pos1, pos2, playername, true) then
|
||||
-- player can't interact
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- no protection
|
||||
return false
|
||||
end
|
14
jumpdrive/license.txt
Normal file
@ -0,0 +1,14 @@
|
||||
Copyright (C) 2018 Thomas Rudin / Buckaroo Banzay
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
63
jumpdrive/mapgen.lua
Normal file
@ -0,0 +1,63 @@
|
||||
local metric_mapgen_events_count
|
||||
|
||||
|
||||
if minetest.get_modpath("monitoring") then
|
||||
metric_mapgen_events_count = monitoring.gauge(
|
||||
"jumpdrive_mapgen_events_count",
|
||||
"number of events in the mapgen cache"
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
|
||||
local events = {} -- list of {minp, maxp, time}
|
||||
|
||||
-- update last mapgen event time
|
||||
minetest.register_on_generated(function(minp, maxp, seed)
|
||||
table.insert(events, {
|
||||
minp = minp,
|
||||
maxp = maxp,
|
||||
time = minetest.get_us_time()
|
||||
})
|
||||
end)
|
||||
|
||||
|
||||
-- cleanup
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer < 5 then return end
|
||||
timer=0
|
||||
|
||||
local time = minetest.get_us_time()
|
||||
local delay_seconds = 20
|
||||
|
||||
local copied_events = events
|
||||
events = {}
|
||||
|
||||
local count = 0
|
||||
for _, event in ipairs(copied_events) do
|
||||
if event.time > (time - (delay_seconds * 1000000)) then
|
||||
-- still recent
|
||||
table.insert(events, event)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
if metric_mapgen_events_count then
|
||||
metric_mapgen_events_count.set(count)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
|
||||
-- true = mapgen recently active in that area
|
||||
jumpdrive.check_mapgen = function(pos)
|
||||
for _, event in ipairs(events) do
|
||||
if vector.distance(pos, event.minp) < 200 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
54
jumpdrive/marker.lua
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
jumpdrive.show_marker = function(pos, radius, color, center_color)
|
||||
local entity = "jumpdrive:marker_" .. color
|
||||
local center_entity = "jumpdrive:marker_" .. (center_color or "blue")
|
||||
|
||||
minetest.add_entity(pos, center_entity)
|
||||
minetest.add_entity({x=pos.x+radius, y=pos.y+radius, z=pos.z+radius}, entity)
|
||||
minetest.add_entity({x=pos.x-radius, y=pos.y+radius, z=pos.z+radius}, entity)
|
||||
minetest.add_entity({x=pos.x+radius, y=pos.y+radius, z=pos.z-radius}, entity)
|
||||
minetest.add_entity({x=pos.x-radius, y=pos.y+radius, z=pos.z-radius}, entity)
|
||||
minetest.add_entity({x=pos.x+radius, y=pos.y-radius, z=pos.z+radius}, entity)
|
||||
minetest.add_entity({x=pos.x-radius, y=pos.y-radius, z=pos.z+radius}, entity)
|
||||
minetest.add_entity({x=pos.x+radius, y=pos.y-radius, z=pos.z-radius}, entity)
|
||||
minetest.add_entity({x=pos.x-radius, y=pos.y-radius, z=pos.z-radius}, entity)
|
||||
|
||||
end
|
||||
|
||||
local register_marker = function(color)
|
||||
local texture = "marker_" .. color .. ".png"
|
||||
|
||||
minetest.register_entity("jumpdrive:marker_" .. color, {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
visual_size = {x=1.05, y=1.05},
|
||||
static_save = false,
|
||||
textures = {
|
||||
texture,
|
||||
texture,
|
||||
texture,
|
||||
texture,
|
||||
texture,
|
||||
texture
|
||||
},
|
||||
collisionbox = {-0.525, -0.525, -0.525, 0.525, 0.525, 0.525},
|
||||
physical = false,
|
||||
},
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
minetest.after(8.0, function() self.object:remove() end)
|
||||
end,
|
||||
|
||||
on_rightclick=function(self, clicker)
|
||||
self.object:remove()
|
||||
end,
|
||||
|
||||
on_punch = function(self, hitter)
|
||||
self.object:remove()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
register_marker("red")
|
||||
register_marker("green")
|
||||
register_marker("blue")
|
4
jumpdrive/metrics.lua
Normal file
@ -0,0 +1,4 @@
|
||||
local metric = monitoring.counter("jumpdrive_move_calls", "number of jumpdrive.move calls")
|
||||
local metric_time = monitoring.counter("jumpdrive_move_time", "time usage in microseconds for jumpdrive.move calls")
|
||||
|
||||
jumpdrive.move = metric.wrap(metric_time.wrap(jumpdrive.move))
|
3
jumpdrive/mod.conf
Normal file
@ -0,0 +1,3 @@
|
||||
name = jumpdrive
|
||||
depends = default, technic
|
||||
optional_depends = mesecons, travelnet, telemosaic, elevator, vacuum, locator, areas, protector, digilines, display_api, pipeworks, monitoring, beds, ropes
|
145
jumpdrive/move.lua
Normal file
@ -0,0 +1,145 @@
|
||||
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
|
||||
|
||||
-- moves the source to the target area
|
||||
-- no protection- or overlap checking is done here
|
||||
jumpdrive.move = function(source_pos1, source_pos2, target_pos1, target_pos2)
|
||||
|
||||
minetest.log("action", "[jumpdrive] initiating jump (" ..
|
||||
minetest.pos_to_string(source_pos1) .. "-" .. minetest.pos_to_string(source_pos2) ..
|
||||
") (" .. minetest.pos_to_string(target_pos1) .. "-" .. minetest.pos_to_string(target_pos2) .. ")")
|
||||
|
||||
-- step 1: copy via voxel manip
|
||||
-- https://dev.minetest.net/VoxelManip#Examples
|
||||
|
||||
-- delta between source and target
|
||||
local delta_vector = vector.subtract(target_pos1, source_pos1)
|
||||
|
||||
-- center of source
|
||||
local source_center = vector.add(source_pos1, vector.divide(vector.subtract(source_pos2, source_pos1), 2))
|
||||
minetest.log("action", "[jumpdrive] source-center: " .. minetest.pos_to_string(source_center))
|
||||
|
||||
local t0 = minetest.get_us_time()
|
||||
|
||||
|
||||
-- load areas (just a precaution)
|
||||
if minetest.load_area then
|
||||
minetest.load_area(source_pos1, source_pos2)
|
||||
minetest.load_area(target_pos1, target_pos2)
|
||||
end
|
||||
|
||||
-- read source
|
||||
local manip = minetest.get_voxel_manip()
|
||||
local e1, e2 = manip:read_from_map(source_pos1, source_pos2)
|
||||
local source_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
|
||||
local source_data = manip:get_data()
|
||||
local source_param1 = manip:get_light_data()
|
||||
local source_param2 = manip:get_param2_data()
|
||||
|
||||
minetest.log("action", "[jumpdrive] read source-data")
|
||||
|
||||
-- write target
|
||||
manip = minetest.get_voxel_manip()
|
||||
e1, e2 = manip:read_from_map(target_pos1, target_pos2)
|
||||
local target_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
|
||||
local target_data = manip:get_data()
|
||||
local target_param1 = manip:get_light_data()
|
||||
local target_param2 = manip:get_param2_data()
|
||||
|
||||
minetest.log("action", "[jumpdrive] read target-data");
|
||||
|
||||
for z=source_pos1.z, source_pos2.z do
|
||||
for y=source_pos1.y, source_pos2.y do
|
||||
for x=source_pos1.x, source_pos2.x do
|
||||
|
||||
local source_index = source_area:index(x, y, z)
|
||||
local target_index = target_area:index(x+delta_vector.x, y+delta_vector.y, z+delta_vector.z)
|
||||
|
||||
-- copy block id
|
||||
target_data[target_index] = source_data[source_index]
|
||||
|
||||
-- copy params
|
||||
target_param1[target_index] = source_param1[source_index]
|
||||
target_param2[target_index] = source_param2[source_index]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
manip:set_data(target_data)
|
||||
manip:set_light_data(target_param1)
|
||||
manip:set_param2_data(target_param2)
|
||||
manip:write_to_map()
|
||||
manip:update_map()
|
||||
|
||||
local t1 = minetest.get_us_time()
|
||||
minetest.log("action", "[jumpdrive] step I took " .. (t1 - t0) .. " us")
|
||||
|
||||
-- step 2: check meta/timers and copy if needed
|
||||
t0 = minetest.get_us_time()
|
||||
jumpdrive.move_metadata(source_pos1, source_pos2, delta_vector)
|
||||
jumpdrive.move_nodetimers(source_pos1, source_pos2, delta_vector)
|
||||
t1 = minetest.get_us_time()
|
||||
minetest.log("action", "[jumpdrive] step II took " .. (t1 - t0) .. " us")
|
||||
|
||||
|
||||
-- step 3: execute target region compat code
|
||||
t0 = minetest.get_us_time()
|
||||
jumpdrive.target_region_compat(target_pos1, target_pos2, delta_vector)
|
||||
t1 = minetest.get_us_time()
|
||||
minetest.log("action", "[jumpdrive] step III took " .. (t1 - t0) .. " us")
|
||||
|
||||
|
||||
-- step 4: move objects
|
||||
t0 = minetest.get_us_time()
|
||||
jumpdrive.move_objects(source_center, source_pos1, source_pos2, delta_vector)
|
||||
|
||||
-- move players
|
||||
for _,player in ipairs(minetest.get_connected_players()) do
|
||||
local playerPos = player:get_pos()
|
||||
|
||||
local xMatch = playerPos.x >= (source_pos1.x-0.5) and playerPos.x <= (source_pos2.x+0.5)
|
||||
local yMatch = playerPos.y >= (source_pos1.y-0.5) and playerPos.y <= (source_pos2.y+0.5)
|
||||
local zMatch = playerPos.z >= (source_pos1.z-0.5) and playerPos.z <= (source_pos2.z+0.5)
|
||||
|
||||
if xMatch and yMatch and zMatch and player:is_player() then
|
||||
minetest.log("action", "[jumpdrive] moving player: " .. player:get_player_name())
|
||||
local new_player_pos = vector.add(playerPos, delta_vector)
|
||||
player:set_pos( new_player_pos );
|
||||
end
|
||||
end
|
||||
|
||||
t1 = minetest.get_us_time()
|
||||
minetest.log("action", "[jumpdrive] step IV took " .. (t1 - t0) .. " us")
|
||||
|
||||
|
||||
-- step 5: clear source area with voxel manip
|
||||
t0 = minetest.get_us_time()
|
||||
manip = minetest.get_voxel_manip()
|
||||
e1, e2 = manip:read_from_map(source_pos1, source_pos2)
|
||||
source_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
|
||||
source_data = manip:get_data()
|
||||
|
||||
|
||||
for z=source_pos1.z, source_pos2.z do
|
||||
for y=source_pos1.y, source_pos2.y do
|
||||
for x=source_pos1.x, source_pos2.x do
|
||||
|
||||
local source_index = source_area:index(x, y, z)
|
||||
source_data[source_index] = c_air
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
manip:set_data(source_data)
|
||||
manip:write_to_map()
|
||||
manip:update_map()
|
||||
|
||||
t1 = minetest.get_us_time()
|
||||
minetest.log("action", "[jumpdrive] step V took " .. (t1 - t0) .. " us")
|
||||
|
||||
|
||||
|
||||
end
|
36
jumpdrive/move_metadata.lua
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
-- invoked from move.lua
|
||||
jumpdrive.move_metadata = function(source_pos1, source_pos2, delta_vector)
|
||||
|
||||
|
||||
local target_pos1 = vector.add(source_pos1, delta_vector)
|
||||
local target_pos2 = vector.add(source_pos2, delta_vector)
|
||||
|
||||
local target_meta_pos_list = minetest.find_nodes_with_meta(target_pos1, target_pos2)
|
||||
for _,target_pos in pairs(target_meta_pos_list) do
|
||||
minetest.log("warning", "[jumpdrive] clearing spurious meta in " .. minetest.pos_to_string(target_pos))
|
||||
local target_meta = minetest.get_meta(target_pos)
|
||||
target_meta:from_table(nil)
|
||||
end
|
||||
|
||||
local meta_pos_list = minetest.find_nodes_with_meta(source_pos1, source_pos2)
|
||||
for _,source_pos in pairs(meta_pos_list) do
|
||||
local target_pos = vector.add(source_pos, delta_vector)
|
||||
|
||||
local source_meta = minetest.get_meta(source_pos)
|
||||
local source_table = source_meta:to_table()
|
||||
|
||||
-- copy metadata to target
|
||||
minetest.get_meta(target_pos):from_table(source_table)
|
||||
|
||||
local node = minetest.get_node(source_pos)
|
||||
|
||||
jumpdrive.node_compat(node.name, source_pos, target_pos)
|
||||
|
||||
-- clear metadata in source
|
||||
source_meta:from_table(nil)
|
||||
end
|
||||
|
||||
jumpdrive.commit_node_compat()
|
||||
|
||||
end
|
42
jumpdrive/move_nodetimers.lua
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
-- collect nodes with on_timer attributes
|
||||
local node_names_with_timer = {}
|
||||
minetest.after(4, function()
|
||||
for _,node in pairs(minetest.registered_nodes) do
|
||||
if node.on_timer then
|
||||
table.insert(node_names_with_timer, node.name)
|
||||
end
|
||||
end
|
||||
minetest.log("action", "[jumpdrive] collected " .. #node_names_with_timer .. " items with node timers")
|
||||
end)
|
||||
|
||||
|
||||
-- invoked from move.lua
|
||||
jumpdrive.move_nodetimers = function(source_pos1, source_pos2, delta_vector)
|
||||
|
||||
if #node_names_with_timer == 0 then
|
||||
-- no node timer-nodes or not collected yet
|
||||
return
|
||||
end
|
||||
|
||||
local list = minetest.find_nodes_in_area(source_pos1, source_pos2, node_names_with_timer)
|
||||
|
||||
for _,source_pos in pairs(list) do
|
||||
local target_pos = vector.add(source_pos, delta_vector)
|
||||
|
||||
local source_timer = minetest.get_node_timer(source_pos)
|
||||
local target_timer = minetest.get_node_timer(target_pos)
|
||||
|
||||
if source_timer:is_started() then
|
||||
-- set target timer
|
||||
target_timer:set(
|
||||
source_timer:get_timeout(),
|
||||
source_timer:get_elapsed()
|
||||
)
|
||||
|
||||
-- clear source timer
|
||||
source_timer:stop()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
39
jumpdrive/move_objects.lua
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
-- invoked from move.lua
|
||||
jumpdrive.move_objects = function(source_center, source_pos1, source_pos2, delta_vector)
|
||||
|
||||
local all_objects = minetest.get_objects_inside_radius(source_center, 20);
|
||||
for _,obj in ipairs(all_objects) do
|
||||
|
||||
local objPos = obj:get_pos()
|
||||
|
||||
local xMatch = objPos.x >= source_pos1.x and objPos.x <= source_pos2.x
|
||||
local yMatch = objPos.y >= source_pos1.y and objPos.y <= source_pos2.y
|
||||
local zMatch = objPos.z >= source_pos1.z and objPos.z <= source_pos2.z
|
||||
|
||||
local isPlayer = obj:is_player()
|
||||
|
||||
if xMatch and yMatch and zMatch and not isPlayer then
|
||||
minetest.log("action", "[jumpdrive] object: @ " .. minetest.pos_to_string(objPos))
|
||||
|
||||
-- coords in range
|
||||
local entity = obj:get_luaentity()
|
||||
|
||||
if not entity then
|
||||
minetest.log("action", "[jumpdrive] moving object")
|
||||
obj:set_pos( vector.add(objPos, delta_vector) )
|
||||
|
||||
elseif entity.name == "__builtin:item" then
|
||||
minetest.log("action", "[jumpdrive] moving dropped item")
|
||||
obj:set_pos( vector.add(objPos, delta_vector) )
|
||||
|
||||
else
|
||||
minetest.log("action", "[jumpdrive] removing entity: " .. entity.name)
|
||||
obj:remove()
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
21
jumpdrive/patches/pipeworks.patch
Normal file
@ -0,0 +1,21 @@
|
||||
diff --git a/teleport_tube.lua b/teleport_tube.lua
|
||||
index f4bad74..d236f04 100644
|
||||
--- a/teleport_tube.lua
|
||||
+++ b/teleport_tube.lua
|
||||
@@ -50,6 +50,16 @@ local function read_tube_db()
|
||||
return tp_tube_db
|
||||
end
|
||||
|
||||
+
|
||||
+-- expose for external batch use (jumpdrive)
|
||||
+pipeworks.tptube = {
|
||||
+ hash = hash,
|
||||
+ save_tube_db = save_tube_db,
|
||||
+ get_db = function() return tp_tube_db or read_tube_db() end,
|
||||
+ tp_tube_db_version = tp_tube_db_version
|
||||
+}
|
||||
+
|
||||
+
|
||||
-- debug formatter for coordinates used below
|
||||
local fmt = function(pos)
|
||||
return pos.x..", "..pos.y..", "..pos.z
|
24
jumpdrive/patches/readme.md
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
# Various patches for proper jumpdrive integration
|
||||
|
||||
## pipeworks
|
||||
|
||||
Teleport tube compat
|
||||
|
||||
```
|
||||
cat ../jumpdrive/patches/pipeworks.patch | patch -p1
|
||||
```
|
||||
|
||||
Adds the following interface:
|
||||
```lua
|
||||
-- expose for external batch use (jumpdrive)
|
||||
pipeworks.tptube = {
|
||||
hash = hash,
|
||||
save_tube_db = save_tube_db,
|
||||
tp_tube_db = tp_tube_db,
|
||||
tp_tube_db_version = tp_tube_db_version
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
* `tp_tube_db_version` should be 2.0
|
148
jumpdrive/readme.md
Normal file
@ -0,0 +1,148 @@
|
||||
Minetest jumpdrive
|
||||
======
|
||||
|
||||
A simple [Jumpdrive](https://en.wikipedia.org/wiki/Jump_drive) for minetest
|
||||
|
||||
Take your buildings with you on your journey
|
||||
|
||||
* Github: [https://github.com/thomasrudin-mt/jumpdrive](https://github.com/thomasrudin-mt/jumpdrive)
|
||||
* Forum topic: [https://forum.minetest.net/viewtopic.php?f=9&t=20073](https://forum.minetest.net/viewtopic.php?f=9&t=20073)
|
||||
|
||||
# Operation
|
||||
|
||||
* Place a 'jumpdrive:engine' into the center of your creation.
|
||||
* Connect the engine to a technic HV network
|
||||
* Let the engine charge
|
||||
* Choose your target coordinates (should be air or ignore blocks)
|
||||
* Select your cube-radius
|
||||
* Click "show" and check the green (source) and red (target) destination markers if everything is in range
|
||||
* Click "jump"
|
||||
|
||||
# Compatibility
|
||||
|
||||
Optional dependencies:
|
||||
* Mesecon interaction (execute jump on signal)
|
||||
* Technic rechargeable (HV)
|
||||
* Travelnet box (gets rewired after jump)
|
||||
* Elevator (on_place gets called after jump)
|
||||
* Locator (gets removed and added after each jump)
|
||||
* Pipeworks teleport tubes (with a patch to pipeworks)
|
||||
* Beds (thx to @tuedel)
|
||||
* Ropes (thx to @tuedel)
|
||||
* Mission-wand as coordinate bookmark (thx to @SwissalpS)
|
||||
|
||||
# Fuel
|
||||
|
||||
The engine connects to a technic hv network.
|
||||
The energy requirements formula looks like this: **10 x radius x distance**
|
||||
|
||||
For example:
|
||||
* Distance: 100 blocks
|
||||
* Radius: 5 blocks
|
||||
* Required energy: 10 x 5 x 100 = 5000
|
||||
|
||||
# Protection
|
||||
|
||||
The source and destination areas are checked for protection so you can't remove and jump into someone else's buildings.
|
||||
There are currently no checks for plain populated areas (normal terrain) so you can jump happily into the mountains and make swiss cheese :)
|
||||
A possible solution against this would be a global height or area restriction (see Preflight check).
|
||||
|
||||
|
||||
# Screenshots
|
||||
|
||||
Interface:
|
||||
|
||||
![](screenshots/screenshot_20180507_200309.png?raw=true)
|
||||
|
||||
Example:
|
||||
|
||||
![](screenshots/screenshot_20180507_200203.png?raw=true)
|
||||
|
||||
# Advanced operation
|
||||
|
||||
## Coordinate bookmarking
|
||||
|
||||
You can place empty books into the drive inventory and write the coordinates to it with the "Write to book" button
|
||||
The "Read from book" reads the coordinates from the next book in the inventory
|
||||
|
||||
# Settings
|
||||
|
||||
Settings in minetest.conf:
|
||||
|
||||
* **jumpdrive.maxradius** max radius of the jumpdrive (default: *15*)
|
||||
* **jumpdrive.powerstorage** power storage of the drive (default: *1000000*)
|
||||
* **jumpdrive.power_requirement** power requirement for chargin (default: *2500*)
|
||||
|
||||
# Lua api
|
||||
|
||||
## Preflight check
|
||||
|
||||
The preflight check can be overriden to execute additional checks:
|
||||
|
||||
```lua
|
||||
jumpdrive.preflight_check = function(source, destination, radius, player)
|
||||
-- check for height limit, only space travel allowed
|
||||
if destination.y < 1000 then
|
||||
return { success=false, message="Atmospheric travel not allowed!" }
|
||||
end
|
||||
|
||||
-- everything ok
|
||||
return { success=true }
|
||||
end
|
||||
```
|
||||
|
||||
## Fuel calc
|
||||
|
||||
The default fuel calc can be overwritten by a depending mod:
|
||||
|
||||
```lua
|
||||
-- calculates the power requirements for a jump
|
||||
jumpdrive.calculate_power = function(radius, distance, sourcePos, targetPos)
|
||||
return 10 * distance * radius
|
||||
end
|
||||
```
|
||||
|
||||
# Sources
|
||||
|
||||
* jumprive_engine.ogg: https://freesound.org/people/kaboose102/sounds/340257/
|
||||
|
||||
# Contributors
|
||||
|
||||
* @tuedel
|
||||
* @SwissalpS
|
||||
* @Panquesito7
|
||||
|
||||
# History
|
||||
|
||||
## Next
|
||||
|
||||
## 2.0
|
||||
|
||||
* various fixes and optimizations
|
||||
* Fleetcontroller
|
||||
* Digiline interface
|
||||
* mod.conf (minetest >= 5.0)
|
||||
* Beds,ropes,missions compatibility
|
||||
* calculate_power() override
|
||||
* overlap check
|
||||
* No fuel consumption if creative
|
||||
* Protection checks for source and destination
|
||||
* preflight check with custom override
|
||||
* Settings in minetest.conf
|
||||
* vacuum compatibility (jump into vacuum with air filled vessel)
|
||||
|
||||
## 1.1
|
||||
|
||||
* improved performance
|
||||
* Documentation
|
||||
* Removed complicated cascade function
|
||||
|
||||
## 1.0
|
||||
|
||||
* Initial version
|
||||
* Cascade operation (with issues)
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
jumpdrive/screenshots/screenshot_20180507_200203.png
Normal file
After Width: | Height: | Size: 1.8 MiB |
BIN
jumpdrive/screenshots/screenshot_20180507_200309.png
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
jumpdrive/sounds/jumpdrive_engine.ogg
Normal file
BIN
jumpdrive/textures/jumpdrive.png
Normal file
After Width: | Height: | Size: 483 B |
BIN
jumpdrive/textures/jumpdrive1.png
Normal file
After Width: | Height: | Size: 297 B |
BIN
jumpdrive/textures/jumpdrive_air.png
Normal file
After Width: | Height: | Size: 144 B |
BIN
jumpdrive/textures/jumpdrive_backbone.png
Normal file
After Width: | Height: | Size: 204 B |
BIN
jumpdrive/textures/jumpdrive_blue_mese_crystal.png
Normal file
After Width: | Height: | Size: 420 B |
BIN
jumpdrive/textures/jumpdrive_fleet_controller.png
Normal file
After Width: | Height: | Size: 437 B |
BIN
jumpdrive/textures/jumpdrive_fleet_controller_top.png
Normal file
After Width: | Height: | Size: 513 B |
BIN
jumpdrive/textures/jumpdrive_raw_blue_mese_crystal.png
Normal file
After Width: | Height: | Size: 390 B |
BIN
jumpdrive/textures/jumpdrive_remote.png
Normal file
After Width: | Height: | Size: 267 B |
BIN
jumpdrive/textures/marker_blue.png
Normal file
After Width: | Height: | Size: 163 B |
BIN
jumpdrive/textures/marker_green.png
Normal file
After Width: | Height: | Size: 163 B |
BIN
jumpdrive/textures/marker_red.png
Normal file
After Width: | Height: | Size: 163 B |
BIN
jumpdrive/textures/spark.png
Normal file
After Width: | Height: | Size: 253 B |
@ -50,6 +50,16 @@ local function read_tube_db()
|
||||
return tp_tube_db
|
||||
end
|
||||
|
||||
|
||||
-- expose for external batch use (jumpdrive)
|
||||
pipeworks.tptube = {
|
||||
hash = hash,
|
||||
save_tube_db = save_tube_db,
|
||||
get_db = function() return tp_tube_db or read_tube_db() end,
|
||||
tp_tube_db_version = tp_tube_db_version
|
||||
}
|
||||
|
||||
|
||||
-- debug formatter for coordinates used below
|
||||
local fmt = function(pos)
|
||||
return pos.x..", "..pos.y..", "..pos.z
|
||||
|