├── .github
└── workflows
│ ├── luacheck.yml
│ └── test.yml
├── .luacheckrc
├── backbone.lua
├── blacklist.lua
├── bookmark.lua
├── common.lua
├── compat
├── anchor.lua
├── areas.lua
├── beds.lua
├── compat.lua
├── drawers.lua
├── elevator.lua
├── locator.lua
├── ropes.lua
├── sethome.lua
├── signs.lua
├── technic_networks.lua
├── telemosaic.lua
├── teleporttube.lua
├── textline.lua
└── travelnet.lua
├── crafts.lua
├── digiline.lua
├── doc
└── digiline.md
├── engine.lua
├── fleet
├── fleet_controller.lua
├── fleet_digiline.lua
├── fleet_formspec.lua
└── fleet_functions.lua
├── formspec.lua
├── fuel.lua
├── hooks.lua
├── infotext.lua
├── init.lua
├── is_area_empty.lua
├── is_area_protected.lua
├── jump.lua
├── license.txt
├── mapgen.lua
├── metrics.lua
├── migrate.lua
├── mod.conf
├── move
├── move.lua
├── move_mapdata.lua
├── move_metadata.lua
├── move_nodetimers.lua
├── move_objects.lua
└── move_players.lua
├── mtt.lua
├── readme.md
├── screenshots
├── screenshot_20180507_200203.png
├── screenshot_20180507_200309.png
└── screenshot_20220305_161502.png
├── settingtypes.txt
├── sounds
└── jumpdrive_engine.ogg
├── technic_run.lua
├── testship.we
├── textures
├── jumpdrive.png
├── jumpdrive_air.png
├── jumpdrive_area.png
├── jumpdrive_backbone.png
├── jumpdrive_blue_mese_crystal.png
├── jumpdrive_fleet_controller.png
├── jumpdrive_raw_blue_mese_crystal.png
├── jumpdrive_remote.png
├── jumpdrive_warpdevice.png
├── marker_blue.png
├── marker_green.png
├── marker_red.png
└── spark.png
├── upgrade.lua
└── warp_device.lua
/.github/workflows/luacheck.yml:
--------------------------------------------------------------------------------
1 | name: luacheck
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@master
12 | - name: apt
13 | run: sudo apt-get install -y luarocks
14 | - name: luacheck install
15 | run: luarocks install --local luacheck
16 | - name: luacheck run
17 | run: $HOME/.luarocks/bin/luacheck ./
18 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - uses: buckaroobanzay/mtt@main
12 | with:
13 | modname: jumpdrive
14 | git_dependencies: |
15 | https://github.com/minetest-mods/areas.git
16 |
--------------------------------------------------------------------------------
/.luacheckrc:
--------------------------------------------------------------------------------
1 |
2 | globals = {
3 | "jumpdrive",
4 |
5 | -- write
6 | "travelnet",
7 | "pipeworks",
8 | "beds"
9 | }
10 |
11 | read_globals = {
12 | -- Stdlib
13 | string = {fields = {"split"}},
14 | table = {fields = {"copy", "getn"}},
15 | "VoxelManip",
16 |
17 | -- Minetest
18 | "core",
19 | "minetest",
20 | "vector", "ItemStack",
21 | "dump", "VoxelArea",
22 |
23 | -- Deps
24 | "unified_inventory", "default", "monitoring",
25 | "digilines",
26 | "mesecons",
27 | "mesecon",
28 | "technic",
29 | "locator",
30 | "display_api",
31 | "areas",
32 | "ropes",
33 | "sethome",
34 | "drawers",
35 | "player_monoids",
36 | "vizlib",
37 | "mcl_sounds",
38 | "mcl_formspec",
39 | "mtt"
40 | }
41 |
--------------------------------------------------------------------------------
/backbone.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 | minetest.register_node("jumpdrive:backbone", {
4 | description = "Jumpdrive Backbone",
5 |
6 | tiles = {"jumpdrive_backbone.png"},
7 | groups = {cracky=3,oddly_breakable_by_hand=3,handy=1,pickaxey=1},
8 | _mcl_blast_resistance = 2,
9 | _mcl_hardness = 0.9,
10 | sounds = jumpdrive.sounds.node_sound_glass_defaults(),
11 | is_ground_content = false,
12 | light_source = 13
13 | })
14 |
--------------------------------------------------------------------------------
/blacklist.lua:
--------------------------------------------------------------------------------
1 |
2 | if minetest.get_modpath("technic") then
3 | table.insert(jumpdrive.blacklist, "technic:forcefield_emitter_on")
4 | end
5 |
6 | -- TODO bedrock, advtrains tracks
7 |
--------------------------------------------------------------------------------
/bookmark.lua:
--------------------------------------------------------------------------------
1 |
2 | local book_item, book_written = ""
3 |
4 | if minetest.get_modpath("default") then
5 | book_item = "default:book"
6 | book_written = "default:book_written"
7 | end
8 |
9 | if minetest.get_modpath("mcl_books") then
10 | book_item = "mcl_books:book"
11 | book_written = "mcl_books:written_book"
12 | end
13 |
14 | jumpdrive.write_to_book = function(pos, sender)
15 | local meta = minetest.get_meta(pos)
16 | local inv = meta:get_inventory()
17 |
18 | if inv:contains_item("main", {name=book_item, count=1}) then
19 | local stack = inv:remove_item("main", {name=book_item, count=1})
20 |
21 | local new_stack = ItemStack(book_written)
22 |
23 | local data = {}
24 |
25 | data.owner = sender:get_player_name()
26 | data.title = "Jumpdrive coordinates"
27 | data.description = "Jumpdrive coordinates"
28 | data.text = minetest.serialize(jumpdrive.get_meta_pos(pos))
29 | data.page = 1
30 | data.page_max = 1
31 |
32 | new_stack:get_meta():from_table({ fields = data })
33 |
34 | if inv:room_for_item("main", new_stack) then
35 | -- put written book back
36 | inv:add_item("main", new_stack)
37 | else
38 | -- put back old stack
39 | inv:add_item("main", stack)
40 | end
41 |
42 | end
43 |
44 | end
45 |
46 | local function has_nil(pos)
47 | if nil == pos
48 | or nil == pos.x
49 | or nil == pos.y
50 | or nil == pos.z
51 | then
52 | return true
53 | end
54 | return false
55 | end
56 |
57 | local function sanitize_and_set_coordinates(meta, pos)
58 | meta:set_int("x", jumpdrive.sanitize_coord(pos.x))
59 | meta:set_int("y", jumpdrive.sanitize_coord(pos.y))
60 | meta:set_int("z", jumpdrive.sanitize_coord(pos.z))
61 | end
62 |
63 | jumpdrive.read_from_book = function(pos)
64 | local meta = minetest.get_meta(pos)
65 | local inv = meta:get_inventory()
66 | local player_name = meta:get_string("owner")
67 |
68 | local inv_size = inv:get_size("main")
69 | local stack
70 | local stack_name
71 | local stack_meta
72 | local text
73 | local target_pos
74 | for i = inv_size, 1, -1 do
75 | stack = inv:get_stack("main", i)
76 | stack_name = stack:get_name()
77 | if book_written == stack_name then
78 | -- remove item from inventory
79 | inv:set_stack("main", i, ItemStack())
80 | stack_meta = stack:get_meta()
81 | text = stack_meta:get_string("text")
82 | local data = minetest.deserialize(text)
83 | if has_nil(data) then
84 | -- put book back where it was, it may contain other information
85 | inv:set_stack("main", i, stack)
86 | else
87 |
88 | target_pos = {
89 | x = tonumber(data.x),
90 | y = tonumber(data.y),
91 | z = tonumber(data.z)
92 | }
93 |
94 | if has_nil(target_pos) then
95 | -- put book back where it was, it may contain other information
96 | inv:set_stack("main", i, stack)
97 | -- alert player
98 | if nil ~= player_name then
99 | minetest.chat_send_player(player_name, "Invalid coordinates")
100 | end
101 | return
102 | end
103 | sanitize_and_set_coordinates(meta, target_pos)
104 | -- put book back to next free slot
105 | inv:add_item("main", stack)
106 | return
107 | end
108 |
109 | elseif "missions:wand_position" == stack_name then
110 | -- remove item from inventory
111 | inv:set_stack("main", i, ItemStack())
112 | stack_meta = stack:get_meta()
113 |
114 | text = stack_meta:get_string("pos")
115 | target_pos = minetest.string_to_pos(text)
116 |
117 | if has_nil(target_pos) then
118 | -- put wand back where it was.
119 | -- In singleplayer/creative you can get an invalid position wand
120 | inv:set_stack("main", i, stack)
121 | else
122 | -- don't know how you could get unsanitary coords in a wand,
123 | -- let's just be safe
124 | sanitize_and_set_coordinates(meta, target_pos)
125 | -- put wand back to next free slot
126 | inv:add_item("main", stack)
127 | return
128 | end
129 |
130 | elseif "ccompass:" == stack_name:sub(1, 9)
131 | or "compass:" == stack_name:sub(1, 8) then
132 | -- remove item from inventory
133 | inv:set_stack("main", i, ItemStack())
134 | stack_meta = stack:get_meta()
135 |
136 | text = stack_meta:get_string("target_pos")
137 | target_pos = minetest.string_to_pos(text)
138 |
139 | if has_nil(target_pos) then
140 | -- put compass back, it is probably not calibrated
141 | -- we put it at same position as we did not actually use it
142 | inv:set_stack("main", i, stack)
143 | else
144 | sanitize_and_set_coordinates(meta, target_pos)
145 | -- put compass back to next free slot
146 | inv:add_item("main", stack)
147 | return
148 | end
149 | end -- switch item type
150 | end -- loop inventory
151 | -- if we got here, there was nothing.
152 | -- should we or should we not message user?
153 | --[[
154 | if nil ~= player_name then
155 | minetest.chat_send_player(player_name, "No valid bookmark item found.")
156 | end
157 | --]]
158 | end
159 |
160 |
--------------------------------------------------------------------------------
/common.lua:
--------------------------------------------------------------------------------
1 |
2 | local c_air = minetest.get_content_id("air")
3 |
4 | function jumpdrive.clear_area(pos1, pos2)
5 | local manip = minetest.get_voxel_manip()
6 | local e1, e2 = manip:read_from_map(pos1, pos2)
7 | local source_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
8 | local source_data = manip:get_data()
9 |
10 |
11 | for z=pos1.z, pos2.z do
12 | for y=pos1.y, pos2.y do
13 | for x=pos1.x, pos2.x do
14 |
15 | local source_index = source_area:index(x, y, z)
16 | source_data[source_index] = c_air
17 | end
18 | end
19 | end
20 |
21 | manip:set_data(source_data)
22 | manip:write_to_map()
23 |
24 | -- remove metadata
25 | local target_meta_pos_list = minetest.find_nodes_with_meta(pos1, pos2)
26 | for _,target_pos in pairs(target_meta_pos_list) do
27 | local target_meta = minetest.get_meta(target_pos)
28 | target_meta:from_table(nil)
29 | end
30 | end
31 |
32 | function jumpdrive.sanitize_coord(coord)
33 | return math.max( math.min( coord, 31000 ), -31000 )
34 | end
35 |
36 | -- get pos object from pos
37 | function jumpdrive.get_meta_pos(pos)
38 | local meta = minetest.get_meta(pos);
39 | return {x=meta:get_int("x"), y=meta:get_int("y"), z=meta:get_int("z")}
40 | end
41 |
42 | -- set pos object from pos
43 | function jumpdrive.set_meta_pos(pos, target)
44 | local meta = minetest.get_meta(pos);
45 | meta:set_int("x", target.x)
46 | meta:set_int("y", target.y)
47 | meta:set_int("z", target.z)
48 | end
49 |
50 | -- get offset from meta
51 | function jumpdrive.get_radius(pos)
52 | local meta = minetest.get_meta(pos);
53 | return math.max(math.min(meta:get_int("radius"), jumpdrive.config.max_radius), 1)
54 | end
55 |
56 | -- calculates the power requirements for a jump
57 | -- params: radius, distance, sourcePos, targetPos
58 | function jumpdrive.calculate_power(radius, distance)
59 | return 10 * distance * radius
60 | end
61 |
62 |
63 | -- preflight check, for overriding
64 | -- params: source, destination, radius, playername
65 | function jumpdrive.preflight_check()
66 | return { success=true }
67 | end
68 |
69 | function jumpdrive.reset_coordinates(pos)
70 | local meta = minetest.get_meta(pos)
71 |
72 | meta:set_int("x", pos.x)
73 | meta:set_int("y", pos.y)
74 | meta:set_int("z", pos.z)
75 |
76 | end
77 |
78 | function jumpdrive.get_mapblock_from_pos(pos)
79 | return {
80 | x = math.floor(pos.x / 16),
81 | y = math.floor(pos.y / 16),
82 | z = math.floor(pos.z / 16)
83 | }
84 | end
85 |
86 | jumpdrive.digiline_rules = {
87 | -- digilines.rules.default
88 | {x= 1,y= 0,z= 0},{x=-1,y= 0,z= 0}, -- along x beside
89 | {x= 0,y= 0,z= 1},{x= 0,y= 0,z=-1}, -- along z beside
90 | {x= 1,y= 1,z= 0},{x=-1,y= 1,z= 0}, -- 1 node above along x diagonal
91 | {x= 0,y= 1,z= 1},{x= 0,y= 1,z=-1}, -- 1 node above along z diagonal
92 | {x= 1,y=-1,z= 0},{x=-1,y=-1,z= 0}, -- 1 node below along x diagonal
93 | {x= 0,y=-1,z= 1},{x= 0,y=-1,z=-1}, -- 1 node below along z diagonal
94 | -- added rules for digi cable
95 | {x= 0,y= 1,z= 0},{x= 0,y=-1,z= 0}, -- along y above and below
96 | }
97 |
--------------------------------------------------------------------------------
/compat/anchor.lua:
--------------------------------------------------------------------------------
1 | -- stolen from technic / anchor.lua
2 |
3 | local function compute_forceload_positions(pos, meta)
4 | local radius = meta:get_int("radius")
5 | local minpos = vector.subtract(pos, vector.new(radius, radius, radius))
6 | local maxpos = vector.add(pos, vector.new(radius, radius, radius))
7 | local minbpos = {}
8 | local maxbpos = {}
9 | for _, coord in ipairs({"x","y","z"}) do
10 | minbpos[coord] = math.floor(minpos[coord] / 16) * 16
11 | maxbpos[coord] = math.floor(maxpos[coord] / 16) * 16
12 | end
13 | local flposes = {}
14 | for x = minbpos.x, maxbpos.x, 16 do
15 | for y = minbpos.y, maxbpos.y, 16 do
16 | for z = minbpos.z, maxbpos.z, 16 do
17 | table.insert(flposes, vector.new(x, y, z))
18 | end
19 | end
20 | end
21 | return flposes
22 | end
23 |
24 | local function currently_forceloaded_positions(meta)
25 | local ser = meta:get_string("forceloaded")
26 | return ser == "" and {} or minetest.deserialize(ser)
27 | end
28 |
29 | local function forceload_off(meta)
30 | local flposes = currently_forceloaded_positions(meta)
31 | meta:set_string("forceloaded", "")
32 | for _, p in ipairs(flposes) do
33 | minetest.forceload_free_block(p)
34 | end
35 | end
36 |
37 | local function forceload_on(pos, meta)
38 | local want_flposes = compute_forceload_positions(pos, meta)
39 | local have_flposes = {}
40 | for _, p in ipairs(want_flposes) do
41 | if minetest.forceload_block(p) then
42 | table.insert(have_flposes, p)
43 | end
44 | end
45 | meta:set_string("forceloaded", #have_flposes == 0 and "" or minetest.serialize(have_flposes))
46 | end
47 |
48 | minetest.override_item("technic:admin_anchor", {
49 | on_movenode = function(from_pos, to_pos)
50 | local to_meta = minetest.get_meta(to_pos)
51 | local from_meta = minetest.get_meta(from_pos)
52 |
53 | if from_meta:get_int("enabled") ~= 0 then
54 | -- anchor enabled
55 | forceload_off(from_meta)
56 | forceload_on(to_pos, to_meta)
57 | end
58 | end
59 | })
60 |
--------------------------------------------------------------------------------
/compat/areas.lua:
--------------------------------------------------------------------------------
1 | jumpdrive.register_after_jump(function(from_area, to_area)
2 | local delta_vector = vector.subtract(to_area.pos1, from_area.pos1)
3 | local pos1 = from_area.pos1
4 | local pos2 = from_area.pos2
5 |
6 | local list = areas:getAreasIntersectingArea(pos1, pos2)
7 | local dirty = false
8 |
9 | for id, area in pairs(list) do
10 | local xMatch = area.pos1.x >= pos1.x and area.pos2.x <= pos2.x
11 | local yMatch = area.pos1.y >= pos1.y and area.pos2.y <= pos2.y
12 | local zMatch = area.pos1.z >= pos1.z and area.pos2.z <= pos2.z
13 |
14 | if xMatch and yMatch and zMatch then
15 | dirty = true
16 | minetest.log("action", "[jumpdrive] moving area " .. id)
17 |
18 | areas:move(
19 | id,
20 | area,
21 | vector.add(area.pos1, delta_vector),
22 | vector.add(area.pos2, delta_vector)
23 | )
24 | end
25 | end
26 |
27 | if dirty then
28 | areas:save()
29 | end
30 | end)
31 |
--------------------------------------------------------------------------------
/compat/beds.lua:
--------------------------------------------------------------------------------
1 | local bed_bottoms = { "beds:bed_bottom", "beds:fancy_bed_bottom" }
2 |
3 | -- Sanity checks
4 | assert(beds, "global `beds` not found")
5 | assert(beds.spawn, "field `spawn` doesn't exist in `beds`")
6 | assert(beds.save_spawns, "field `save_spawns` doesn't exist in `beds`")
7 |
8 | -- Calculate a bed's middle position (where players would spawn)
9 | local function calc_bed_middle(bed_pos, facedir)
10 | local dir = core.facedir_to_dir(facedir)
11 | local bed_middle = {
12 | x = bed_pos.x + dir.x / 2,
13 | y = bed_pos.y,
14 | z = bed_pos.z + dir.z / 2
15 | }
16 | return bed_middle
17 | end
18 |
19 | local bed_from_positions = {}
20 |
21 | for _, nodename in ipairs(bed_bottoms) do
22 | -- Override bed definitions
23 | core.override_item(nodename, {
24 | on_movenode = function(from_pos)
25 | -- Collect bed positions while jumping
26 | table.insert(bed_from_positions, from_pos)
27 | end
28 | })
29 | end
30 |
31 | -- Executed after jump
32 | jumpdrive.register_after_jump(function(from_area, to_area)
33 | local delta_vector = vector.subtract(to_area.pos1, from_area.pos1)
34 | local modified = false
35 |
36 | -- Go over all collected bed positions
37 | for _, bed_pos in ipairs(bed_from_positions) do
38 | local facedir = core.get_node(bed_pos).param2
39 | local sleep_pos = calc_bed_middle(bed_pos, facedir)
40 | -- Sleep position in target area
41 | local new_sleep_pos = vector.add(sleep_pos, delta_vector)
42 | local sleep_pos_floor = vector.floor(sleep_pos)
43 |
44 | for player_name, player_pos in pairs(beds.spawn) do
45 | if vector.equals(sleep_pos_floor, vector.floor(player_pos)) then
46 | -- Player sleeps here, move position
47 | beds.spawn[player_name] = new_sleep_pos
48 | core.log("action",
49 | "[jumpdrive] Updated bed spawn for player " .. player_name)
50 |
51 | -- Set modified flag to save afterwards
52 | modified = true
53 | end
54 | end
55 | end
56 |
57 | if modified then
58 | -- Tell beds mod to save the new spawns.
59 | beds.save_spawns()
60 | end
61 |
62 | -- Clear collected bed positions
63 | bed_from_positions = {}
64 | end)
65 |
--------------------------------------------------------------------------------
/compat/compat.lua:
--------------------------------------------------------------------------------
1 | local MP = minetest.get_modpath("jumpdrive")
2 |
3 | local has_technic_mod = minetest.get_modpath("technic")
4 | local has_locator_mod = minetest.get_modpath("locator")
5 | local has_display_mod = minetest.get_modpath("display_api")
6 | local has_pipeworks_mod = minetest.get_modpath("pipeworks")
7 | local has_beds_mod = minetest.get_modpath("beds")
8 | local has_ropes_mod = minetest.get_modpath("ropes")
9 | local has_sethome_mod = minetest.get_modpath("sethome")
10 | local has_areas_mod = minetest.get_modpath("areas")
11 | local has_drawers_mod = minetest.get_modpath("drawers")
12 | local has_textline_mod = minetest.get_modpath("textline")
13 |
14 | if minetest.get_modpath("travelnet") then
15 | dofile(MP.."/compat/travelnet.lua")
16 | end
17 |
18 | if minetest.get_modpath("elevator") then
19 | dofile(MP.."/compat/elevator.lua")
20 | end
21 |
22 | if has_technic_mod then
23 | dofile(MP.."/compat/anchor.lua")
24 | dofile(MP.."/compat/technic_networks.lua")
25 | end
26 |
27 | if has_locator_mod then
28 | dofile(MP.."/compat/locator.lua")
29 | end
30 |
31 | if has_drawers_mod then
32 | dofile(MP.."/compat/drawers.lua")
33 | end
34 |
35 | if has_display_mod then
36 | dofile(MP.."/compat/signs.lua")
37 | end
38 |
39 | if has_textline_mod then
40 | dofile(MP.."/compat/textline.lua")
41 | end
42 |
43 | if has_areas_mod then
44 | dofile(MP.."/compat/areas.lua")
45 | end
46 |
47 | if has_sethome_mod then
48 | dofile(MP.."/compat/sethome.lua")
49 | end
50 |
51 | if has_ropes_mod then
52 | dofile(MP.."/compat/ropes.lua")
53 | end
54 |
55 | if has_beds_mod then
56 | dofile(MP.."/compat/beds.lua")
57 | end
58 |
59 | dofile(MP.."/compat/telemosaic.lua")
60 |
61 | if has_pipeworks_mod then
62 | dofile(MP.."/compat/teleporttube.lua")
63 | end
64 |
65 | jumpdrive.node_compat = function(name, source_pos, target_pos, source_pos1, source_pos2, delta_vector)
66 |
67 | if has_pipeworks_mod and string.find(name, "^pipeworks:teleport_tube") then
68 | jumpdrive.teleporttube_compat(source_pos, target_pos)
69 |
70 | elseif name == "telemosaic:beacon" or name == "telemosaic:beacon_err"
71 | or name == "telemosaic:beacon_disabled" or name == "telemosaic:beacon_protected"
72 | or name == "telemosaic:beacon_err_protected" or name == "telemosaic:beacon_disabled_protected" then
73 | jumpdrive.telemosaic_compat(source_pos, target_pos, source_pos1, source_pos2, delta_vector)
74 |
75 | end
76 | end
77 |
78 | jumpdrive.commit_node_compat = function()
79 | -- Nothing to do here
80 | end
81 |
--------------------------------------------------------------------------------
/compat/drawers.lua:
--------------------------------------------------------------------------------
1 |
2 | assert(type(drawers.spawn_visuals) == "function")
3 |
4 | -- refresh drawers in new area after jump
5 | minetest.register_on_mods_loaded(function()
6 | for nodename, nodedef in pairs(minetest.registered_nodes) do
7 | if nodedef.groups and nodedef.groups.drawer then
8 | minetest.override_item(nodename, {
9 | on_movenode = function(_, to_pos)
10 | minetest.after(1, function()
11 | drawers.spawn_visuals(to_pos)
12 | end)
13 | end
14 | })
15 | end
16 | end
17 | end)
18 |
--------------------------------------------------------------------------------
/compat/elevator.lua:
--------------------------------------------------------------------------------
1 |
2 | local nodedef = minetest.registered_nodes["elevator:motor"]
3 |
4 | minetest.override_item("elevator:motor", {
5 | on_movenode = function(_, to_pos)
6 | minetest.log("action", "[jumpdrive] Restoring elevator @ " .. to_pos.x .. "/" .. to_pos.y .. "/" .. to_pos.z)
7 | nodedef.after_place_node(to_pos, nil, nil)
8 | end
9 | })
10 |
--------------------------------------------------------------------------------
/compat/locator.lua:
--------------------------------------------------------------------------------
1 |
2 | for i=1,3 do
3 | minetest.override_item("locator:beacon_" .. i, {
4 | on_movenode = function(from_pos, to_pos)
5 | local meta = minetest.get_meta(to_pos)
6 | locator.remove_beacon(from_pos)
7 | locator.update_beacon(to_pos, meta)
8 | end
9 | })
10 | end
11 |
--------------------------------------------------------------------------------
/compat/ropes.lua:
--------------------------------------------------------------------------------
1 | local rope_nodes = { -- Top, middle, bottom
2 | {"ropes:rope_top", "ropes:rope", "ropes:rope_bottom"}, -- Rope boxes
3 | {"ropes:ropeladder_falling", "ropes:ropeladder", "ropes:ropeladder_bottom"}, -- Rope ladders
4 | }
5 |
6 | jumpdrive.register_after_jump(function(from_area, to_area)
7 | local delta_vector = vector.subtract(to_area.pos1, from_area.pos1)
8 | local target_pos1 = to_area.pos1
9 | local target_pos2 = to_area.pos2
10 |
11 | if ropes == nil or
12 | ropes.destroy_rope == nil then
13 | -- Something is wrong. Don't do anything
14 | return
15 | end
16 |
17 | -- Bottom slice of the target area
18 | local target_bottom_pos1 = target_pos1
19 | local target_bottom_pos2 = {
20 | x = target_pos2.x,
21 | y = target_pos1.y,
22 | z = target_pos2.z
23 | }
24 |
25 | -- Top slice of the target area
26 | local target_top_pos1 = {
27 | x = target_pos1.x,
28 | y = target_pos2.y,
29 | z = target_pos1.z
30 | }
31 | local target_top_pos2 = target_pos2
32 |
33 |
34 |
35 | -- For every type of rope
36 | for _, rope_type_nodes in ipairs(rope_nodes) do
37 |
38 | -- Look for ropes hanging out of the jump area
39 | local ropes_hanging_out = minetest.find_nodes_in_area(
40 | target_bottom_pos1, target_bottom_pos2,
41 | {rope_type_nodes[1], rope_type_nodes[2]})
42 |
43 | for _, pos in ipairs(ropes_hanging_out) do
44 | -- Swap with a proper end node, keeping param2
45 | local end_node = minetest.get_node(pos)
46 | minetest.swap_node(pos, {
47 | name=rope_type_nodes[3],
48 | param2=end_node.param2
49 | })
50 |
51 | -- Destroy remainder of the rope below the source area
52 | local remainder_pos = {
53 | x = pos.x - delta_vector.x,
54 | y = pos.y - delta_vector.y - 1,
55 | z = pos.z - delta_vector.z
56 | }
57 | ropes.destroy_rope(remainder_pos, rope_type_nodes)
58 | end
59 |
60 |
61 | -- Look for ropes hanging into the jump area
62 | local ropes_hanging_in = minetest.find_nodes_in_area(
63 | target_top_pos1, target_top_pos2,
64 | rope_type_nodes)
65 |
66 | for _, pos in ipairs(ropes_hanging_in) do
67 | -- Probably there is a loose end above the source area
68 | local end_pos = {
69 | x = pos.x - delta_vector.x,
70 | y = pos.y - delta_vector.y + 1,
71 | z = pos.z - delta_vector.z
72 | }
73 | local end_node = minetest.get_node(end_pos)
74 |
75 | if end_node and
76 | (end_node.name == rope_type_nodes[1] or
77 | end_node.name == rope_type_nodes[2]) then
78 |
79 | -- Swap with a proper end node, keeping param2
80 | minetest.swap_node(end_pos, {
81 | name=rope_type_nodes[3],
82 | param2=end_node.param2
83 | })
84 | end
85 |
86 | -- Destroy remainder of the rope in the target area
87 | ropes.destroy_rope(pos, rope_type_nodes)
88 | end
89 | end
90 | end)
91 |
--------------------------------------------------------------------------------
/compat/sethome.lua:
--------------------------------------------------------------------------------
1 |
2 | jumpdrive.register_after_jump(function(from_area, to_area)
3 | local delta_vector = vector.subtract(to_area.pos1, from_area.pos1)
4 | local pos1 = from_area.pos1
5 | local pos2 = from_area.pos2
6 |
7 | -- move /home positions of online players
8 | for _,player in ipairs(minetest.get_connected_players()) do
9 | local name = player:get_player_name()
10 |
11 | local home_pos = sethome.get(name)
12 | if home_pos then
13 | local xMatch = home_pos.x >= pos1.x and home_pos.x <= pos2.x
14 | local yMatch = home_pos.y >= pos1.y and home_pos.y <= pos2.y
15 | local zMatch = home_pos.z >= pos1.z and home_pos.z <= pos2.z
16 |
17 | if xMatch and yMatch and zMatch then
18 | local new_pos = vector.add(home_pos, delta_vector)
19 | sethome.set(name, new_pos)
20 | end
21 | end
22 | end
23 | end)
24 |
--------------------------------------------------------------------------------
/compat/signs.lua:
--------------------------------------------------------------------------------
1 | assert(type(display_api.update_entities) == "function")
2 |
3 | -- refresh signs in new area after jump
4 | minetest.register_on_mods_loaded(function()
5 | for nodename, nodedef in pairs(minetest.registered_nodes) do
6 | if nodedef.groups and nodedef.groups.display_api then
7 | minetest.override_item(nodename, {
8 | on_movenode = function(_, to_pos)
9 | minetest.after(1, function()
10 | display_api.update_entities(to_pos)
11 | end)
12 | end
13 | })
14 | end
15 | end
16 | end)
17 |
--------------------------------------------------------------------------------
/compat/technic_networks.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- Compatibility hacks for technic plus new network system
3 | --
4 | -- More information:
5 | -- https://github.com/mt-mods/technic/issues/100
6 | --
7 | -- See also proposal draft to actually move networks instead of rebuilding:
8 | -- https://github.com/mt-mods/jumpdrive/pull/79
9 | --
10 |
11 | -- Check for technic mod version compatibility
12 | if technic.remove_network and technic.pos2network and technic.machines then
13 |
14 | local function on_movenode(from_pos, to_pos, info)
15 | -- Destroy network caches at source location, inside jump area
16 | local src_net_id = technic.pos2network(from_pos)
17 | if src_net_id then
18 | technic.remove_network(src_net_id)
19 | end
20 |
21 | -- Destroy network caches at target location, outside jump area
22 | local edge = info.edge
23 | for axis, value in pairs(edge) do
24 | if value ~= 0 then
25 | local axis_dir = {x=0,y=0,z=0}
26 | axis_dir[axis] = value
27 | local edge_pos = vector.add(to_pos, axis_dir)
28 | local dst_net_id = technic.pos2network(edge_pos)
29 | if dst_net_id then
30 | technic.remove_network(dst_net_id)
31 | end
32 | end
33 | end
34 | end
35 |
36 | -- Collect groups for registered technic cables
37 | local cable_groups = {}
38 | for tier,_ in pairs(technic.machines) do
39 | cable_groups[("technic_%s_cable"):format(tier:lower())] = 1
40 | end
41 |
42 | local function is_network_node(_, def)
43 | if not def.groups then return end
44 | for group,_ in pairs(cable_groups) do
45 | if def.groups[group] then return true end
46 | end
47 | return def.groups["technic_machine"]
48 | end
49 |
50 | -- Inject on_movenode functionality but only if node does not already implement it
51 | for name, def in pairs(minetest.registered_nodes) do
52 | if not def.on_movenode and is_network_node(name, def) then
53 | minetest.override_item(name, { on_movenode = on_movenode })
54 | end
55 | end
56 |
57 | end
58 |
--------------------------------------------------------------------------------
/compat/telemosaic.lua:
--------------------------------------------------------------------------------
1 |
2 | local function unhash_pos(hash)
3 | local pos = {}
4 | local list = string.split(hash, ':')
5 | pos.x = tonumber(list[1])
6 | pos.y = tonumber(list[2])
7 | pos.z = tonumber(list[3])
8 | return pos
9 | end
10 |
11 | local function hash_pos(pos)
12 | return math.floor(pos.x + 0.5) .. ':' ..
13 | math.floor(pos.y + 0.5) .. ':' ..
14 | math.floor(pos.z + 0.5)
15 | end
16 |
17 | local function is_valid_beacon(name)
18 | if name == "telemosaic:beacon"
19 | or name == "telemosaic:beacon_err"
20 | or name == "telemosaic:beacon_disabled"
21 | or name == "telemosaic:beacon_protected"
22 | or name == "telemosaic:beacon_err_protected"
23 | or name == "telemosaic:beacon_disabled_protected" then
24 | return true
25 | end
26 | return false
27 | end
28 |
29 | jumpdrive.telemosaic_compat = function(source_pos, target_pos, source_pos1, source_pos2, delta_vector)
30 |
31 | -- delegate to compat
32 | minetest.log("action", "[jumpdrive] Trying to rewire telemosaic at " .. minetest.pos_to_string(target_pos))
33 |
34 | local local_meta = minetest.get_meta(target_pos)
35 | local remote_hash = local_meta:get_string('telemosaic:dest')
36 |
37 | if remote_hash ~= nil and remote_hash ~= '' then
38 | local remote_pos = unhash_pos(remote_hash)
39 |
40 | minetest.load_area(remote_pos)
41 | local node = minetest.get_node(remote_pos)
42 |
43 | if not is_valid_beacon(node.name) then
44 | -- no beacon found, check if it was moved
45 | local xMatch = remote_pos.x >= source_pos1.x and remote_pos.x <= source_pos2.x
46 | local yMatch = remote_pos.y >= source_pos1.y and remote_pos.y <= source_pos2.y
47 | local zMatch = remote_pos.z >= source_pos1.z and remote_pos.z <= source_pos2.z
48 |
49 | if not (xMatch and yMatch and zMatch) then
50 | return -- outside of moved area
51 | end
52 |
53 | remote_pos = vector.add(remote_pos, delta_vector)
54 | minetest.load_area(remote_pos)
55 | node = minetest.get_node(remote_pos)
56 |
57 | if not is_valid_beacon(node.name) then
58 | return -- no beacon anywhere
59 | end
60 | end
61 |
62 | local remote_meta = minetest.get_meta(remote_pos)
63 | local remote_dest = remote_meta:get_string('telemosaic:dest')
64 |
65 | if remote_dest == hash_pos(source_pos) then
66 | -- remote beacon points to this beacon, update link
67 | minetest.log("action", "[jumpdrive] rewiring telemosaic at " .. minetest.pos_to_string(remote_pos) ..
68 | " to " .. minetest.pos_to_string(target_pos))
69 |
70 | remote_meta:set_string("telemosaic:dest", hash_pos(target_pos))
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/compat/teleporttube.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 | if not pipeworks.tptube then
4 | minetest.log("warning", "[jumpdrive] pipeworks teleport patch not applied, tp-tubes don't work as expected!")
5 | end
6 |
7 | local is_compatible = pipeworks.tptube and pipeworks.tptube.remove_tube
8 | if not is_compatible then
9 | minetest.log("warning", "[jumpdrive] tp-tube api not comptible, consider upgrading the pipeworks mod")
10 | end
11 |
12 | function jumpdrive.teleporttube_compat(from, to)
13 | if not is_compatible then
14 | return
15 | end
16 |
17 | local from_hash = pipeworks.tptube.hash(from)
18 | local to_hash = pipeworks.tptube.hash(to)
19 |
20 | -- swap data
21 | local db = pipeworks.tptube.get_db()
22 | local data = db[from_hash]
23 |
24 | if not data then
25 | minetest.log("warning", "[jumpdrive] no tp-tube data found at hash: " ..
26 | from_hash .. " / pos: " .. minetest.pos_to_string(from))
27 | return
28 | end
29 |
30 | minetest.log("action", "[jumpdrive] moving tp-tube data from " ..
31 | from_hash .. " to " .. to_hash .. " at pos: " .. minetest.pos_to_string(from))
32 |
33 | data.x = to.x
34 | data.y = to.y
35 | data.z = to.z
36 |
37 | -- remove source-entry
38 | pipeworks.tptube.remove_tube(from)
39 |
40 | -- set target entry
41 | db[to_hash] = data
42 | pipeworks.tptube.save_tube(to_hash)
43 | end
44 |
--------------------------------------------------------------------------------
/compat/textline.lua:
--------------------------------------------------------------------------------
1 |
2 | local textline_def = minetest.registered_nodes["textline:lcd"]
3 | assert(textline_def)
4 |
5 | -- refresh textline entities after the jump
6 | minetest.override_item("textline:lcd", {
7 | on_movenode = function(from_pos, to_pos)
8 | local delta_vector = vector.subtract(to_pos, from_pos)
9 | local objects = minetest.get_objects_inside_radius(from_pos, 0.5)
10 | for _,object in ipairs(objects) do
11 | local entity = object:get_luaentity()
12 | if entity and entity.name == "textline:text" then
13 | object:set_pos(vector.add(object:get_pos(), delta_vector))
14 | end
15 | end
16 | end
17 | })
18 |
--------------------------------------------------------------------------------
/compat/travelnet.lua:
--------------------------------------------------------------------------------
1 |
2 | assert(type(travelnet.get_travelnets) == "function", "old travelnet-api found, please update the travelnet mod")
3 |
4 | minetest.register_on_mods_loaded(function()
5 | for node, def in pairs(minetest.registered_nodes) do
6 | if def.groups and def.groups.travelnet == 1 then
7 | minetest.override_item(node, {
8 | on_movenode = function(_, to_pos)
9 | local meta = minetest.get_meta(to_pos);
10 | minetest.log("action", "[jumpdrive] Restoring travelnet @ " .. to_pos.x .. "/" .. to_pos.y .. "/" .. to_pos.z)
11 |
12 | local owner_name = meta:get_string( "owner" );
13 | local station_name = meta:get_string( "station_name" );
14 | local station_network = meta:get_string( "station_network" );
15 |
16 | local stations = travelnet.get_travelnets(owner_name)
17 | if (stations[station_network]
18 | and stations[station_network][station_name]) then
19 | -- update station with new position
20 | stations[station_network][station_name].pos = to_pos
21 | travelnet.set_travelnets(owner_name, stations)
22 | end
23 | end
24 | })
25 | end
26 | end
27 | end)
28 |
29 | jumpdrive.register_after_jump(function()
30 | if travelnet.save_data ~= nil then
31 | -- write data back to files
32 | travelnet.save_data()
33 | end
34 | end)
35 |
--------------------------------------------------------------------------------
/crafts.lua:
--------------------------------------------------------------------------------
1 |
2 | if minetest.get_modpath("technic") then
3 | -- technic enabled crafts
4 | minetest.register_craft({
5 | output = 'jumpdrive:engine',
6 | recipe = {
7 | {'jumpdrive:backbone', 'technic:blue_energy_crystal', 'jumpdrive:backbone'},
8 | {'jumpdrive:warp_device', 'technic:hv_transformer', 'jumpdrive:warp_device'},
9 | {'technic:copper_coil', 'technic:hv_cable', 'technic:copper_coil'}
10 | }
11 | })
12 |
13 | minetest.register_craft({
14 | output = 'jumpdrive:backbone',
15 | recipe = {
16 | {'default:mese', 'default:steelblock', 'default:mese'},
17 | {'default:steelblock', 'default:steelblock', 'default:steelblock'},
18 | {'default:mese', 'default:steelblock', 'default:mese'}
19 | }
20 | })
21 |
22 | minetest.register_craft({
23 | output = 'jumpdrive:warp_device',
24 | recipe = {
25 | {'technic:composite_plate', 'technic:wrought_iron_dust', 'technic:composite_plate'},
26 | {'default:mese', 'technic:machine_casing', 'default:mese'},
27 | {'technic:copper_coil', 'technic:hv_cable', 'technic:copper_coil'}
28 | }
29 | })
30 | minetest.register_craft({
31 | output = 'jumpdrive:fleet_controller',
32 | recipe = {
33 | {'technic:carbon_plate', 'mesecons_luacontroller:luacontroller0000', 'technic:control_logic_unit'},
34 | {'jumpdrive:backbone', 'technic:machine_casing', 'jumpdrive:backbone'},
35 | {'basic_materials:stainless_steel_wire', 'default:steelblock', 'basic_materials:stainless_steel_wire'}
36 | }
37 | })
38 |
39 | elseif minetest.get_modpath("mcl_core") then
40 | -- mineclone crafts
41 | minetest.register_craft({
42 | output = 'jumpdrive:engine',
43 | recipe = {
44 | {'jumpdrive:backbone', 'mcl_core:ironblock', 'jumpdrive:backbone'},
45 | {'mcl_core:ironblock', 'mcl_core:ironblock', 'mcl_core:ironblock'},
46 | {'jumpdrive:backbone', 'mcl_core:ironblock', 'jumpdrive:backbone'}
47 | }
48 | })
49 |
50 | minetest.register_craft({
51 | output = 'jumpdrive:backbone',
52 | recipe = {
53 | {'mesecons_torch:redstoneblock', 'mcl_core:ironblock', 'mesecons_torch:redstoneblock'},
54 | {'mcl_core:ironblock', 'mcl_core:ironblock', 'mcl_core:ironblock'},
55 | {'mesecons_torch:redstoneblock', 'mcl_core:ironblock', 'mesecons_torch:redstoneblock'}
56 | }
57 | })
58 |
59 | minetest.register_craft({
60 | output = 'jumpdrive:warp_device',
61 | recipe = {
62 | {'mesecons:wire_00000000_off', 'mcl_core:diamond', 'mesecons:wire_00000000_off'},
63 | {'mesecons_torch:redstoneblock', 'mcl_core:ironblock', 'mesecons_torch:redstoneblock'},
64 | {'mesecons:wire_00000000_off', 'mcl_core:diamond', 'mesecons:wire_00000000_off'}
65 | }
66 | })
67 |
68 | minetest.register_craft({
69 | output = 'jumpdrive:fleet_controller',
70 | recipe = {
71 | {'jumpdrive:engine', 'mcl_core:ironblock', 'jumpdrive:engine'},
72 | {'mcl_core:ironblock', 'mcl_core:ironblock', 'mcl_core:ironblock'},
73 | {'jumpdrive:engine', 'mcl_core:ironblock', 'jumpdrive:engine'}
74 | }
75 | })
76 | elseif minetest.get_modpath("default") then
77 | -- minetest_game crafts
78 | minetest.register_craft({
79 | output = 'jumpdrive:engine',
80 | recipe = {
81 | {'jumpdrive:backbone', 'default:steelblock', 'jumpdrive:backbone'},
82 | {'default:steelblock', 'default:steelblock', 'default:steelblock'},
83 | {'jumpdrive:backbone', 'default:steelblock', 'jumpdrive:backbone'}
84 | }
85 | })
86 |
87 | minetest.register_craft({
88 | output = 'jumpdrive:backbone',
89 | recipe = {
90 | {'default:mese', 'default:steelblock', 'default:mese'},
91 | {'default:steelblock', 'default:steelblock', 'default:steelblock'},
92 | {'default:mese', 'default:steelblock', 'default:mese'}
93 | }
94 | })
95 |
96 | minetest.register_craft({
97 | output = 'jumpdrive:warp_device',
98 | recipe = {
99 | {'default:mese_crystal', 'default:diamond', 'default:mese_crystal'},
100 | {'default:mese', 'default:steelblock', 'default:mese'},
101 | {'default:mese_crystal', 'default:diamond', 'default:mese_crystal'}
102 | }
103 | })
104 |
105 | minetest.register_craft({
106 | output = 'jumpdrive:fleet_controller',
107 | recipe = {
108 | {'jumpdrive:engine', 'default:steelblock', 'jumpdrive:engine'},
109 | {'default:steelblock', 'default:steelblock', 'default:steelblock'},
110 | {'jumpdrive:engine', 'default:steelblock', 'jumpdrive:engine'}
111 | }
112 | })
113 | end
114 |
--------------------------------------------------------------------------------
/digiline.lua:
--------------------------------------------------------------------------------
1 |
2 | --https://github.com/minetest-mods/technic/blob/master/technic/machines/HV/forcefield.lua
3 |
4 | local is_int = function(value)
5 | return type(value) == 'number' and math.floor(value) == value
6 | end
7 |
8 | jumpdrive.digiline_effector = function(pos, _, channel, msg)
9 |
10 | local msgt = type(msg)
11 | if msgt ~= "table" then
12 | return
13 | end
14 |
15 | local meta = minetest.get_meta(pos)
16 |
17 | local set_channel = meta:get_string("channel")
18 | if set_channel == "" then
19 | -- backward compatibility with old static channel
20 | set_channel = "jumpdrive"
21 | end
22 |
23 | if channel ~= set_channel then
24 | return
25 | end
26 |
27 | local radius = jumpdrive.get_radius(pos)
28 | local targetPos = jumpdrive.get_meta_pos(pos)
29 |
30 | local distance = vector.distance(pos, targetPos)
31 | local power_req = jumpdrive.calculate_power(radius, distance, pos, targetPos)
32 |
33 | if msg.command == "get" then
34 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, {
35 | powerstorage = meta:get_int("powerstorage"),
36 | radius = radius,
37 | position = pos,
38 | target = targetPos,
39 | distance = distance,
40 | power_req = power_req
41 | })
42 |
43 | elseif msg.command == "reset" then
44 | meta:set_int("x", pos.x)
45 | meta:set_int("y", pos.y)
46 | meta:set_int("z", pos.z)
47 | jumpdrive.update_formspec(meta, pos)
48 |
49 | elseif msg.command == "set" then
50 |
51 | if msg.key and msg.value then
52 | local value = tonumber(msg.value)
53 |
54 | if value == nil then
55 | -- not a number
56 | return
57 | end
58 | -- backward compatibility with old less flexible set command
59 | if msg.key == "x" then
60 | meta:set_int("x", jumpdrive.sanitize_coord(value))
61 | elseif msg.key == "y" then
62 | meta:set_int("y", jumpdrive.sanitize_coord(value))
63 | elseif msg.key == "z" then
64 | meta:set_int("z", jumpdrive.sanitize_coord(value))
65 | elseif msg.key == "radius" then
66 | if value >= 1 and value <= jumpdrive.config.max_radius then
67 | meta:set_int("radius", value)
68 | end
69 | end
70 | else
71 | -- API requires integers for coord values, noop for everything else
72 | if is_int(msg.x) then meta:set_int("x", jumpdrive.sanitize_coord(msg.x)) end
73 | if is_int(msg.y) then meta:set_int("y", jumpdrive.sanitize_coord(msg.y)) end
74 | if is_int(msg.z) then meta:set_int("z", jumpdrive.sanitize_coord(msg.z)) end
75 | if is_int(msg.r) and msg.r <= jumpdrive.config.max_radius then
76 | meta:set_int("radius", msg.r)
77 | end
78 | if msg.formupdate then
79 | jumpdrive.update_formspec(meta, pos)
80 | end
81 | end
82 |
83 | elseif msg.command == "simulate" or msg.command == "show" then
84 | local success, resultmsg = jumpdrive.simulate_jump(pos)
85 |
86 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, {
87 | success=success,
88 | msg=resultmsg
89 | })
90 |
91 | elseif msg.command == "jump" then
92 | local success, timeormsg = jumpdrive.execute_jump(pos)
93 |
94 | if success then
95 | -- send new message in target pos
96 | -- defer sending to allow the environment to "settle" first
97 | minetest.after(0.5, function()
98 | digilines.receptor_send(targetPos, jumpdrive.digiline_rules, set_channel, {
99 | success = success,
100 | time = timeormsg
101 | })
102 | end)
103 | else
104 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, {
105 | success = success,
106 | msg = timeormsg
107 | })
108 | end
109 | end
110 | end
111 |
--------------------------------------------------------------------------------
/doc/digiline.md:
--------------------------------------------------------------------------------
1 | # Digilines interface
2 |
3 | Digiline commands if the `digilines` mod is available
4 |
5 | ## Engine
6 |
7 | ### Query current status/coords
8 |
9 | Request coordinates and engine status
10 |
11 | ```lua
12 | -- request
13 | digiline_send("jumpdrive", {
14 | command = "get"
15 | })
16 |
17 | -- response sent back on the same channel
18 | if event.type == "digiline" and event.channel == "jumpdrive" then
19 | event.msg = {
20 | powerstorage = 1000000,
21 | radius = 10,
22 | position = {x=0, y=0, z=0},
23 | target = {x=0, y=0, z=0},
24 | distance = 100,
25 | power_req = 150000
26 | }
27 | end
28 | ```
29 |
30 | ### Reset target coordinates
31 |
32 | Resets the target coordinates
33 |
34 | ```lua
35 | -- request
36 | digiline_send("jumpdrive", {
37 | command = "reset"
38 | })
39 | ```
40 |
41 | ### Set target coordinates
42 |
43 | Set the target coordinates
44 |
45 | ```lua
46 | -- request
47 | digiline_send("jumpdrive", { command = "set", key = "x", value = 1024 })
48 | digiline_send("jumpdrive", { command = "set", key = "y", value = 1024 })
49 | digiline_send("jumpdrive", { command = "set", key = "z", value = 2048 })
50 | digiline_send("jumpdrive", { command = "set", key = "radius", value = 15 })
51 | ```
52 |
53 | Alternate way to set coordinates
54 |
55 | ```lua
56 | -- request
57 | digiline_send("jumpdrive", { command = "set", x = 1024, y = 1024, z = 2048, r = 15, formupdate = false })
58 | ```
59 | Where
60 | * `x` sets x coordinate
61 | * `y` sets y coordinate
62 | * `z` sets z coordinate
63 | * `r` sets radius
64 | * `formupdate` updates coordinates on formspec
65 |
66 | Every value is optional. `x`, `y`, `z` and `r` must be integers. `formupdate` is truth value.
67 |
68 | ### Simulate jump
69 |
70 | Simulate a jump
71 |
72 | ```lua
73 | -- request
74 | digiline_send("jumpdrive", {
75 | command = "simulate"
76 | })
77 |
78 | -- response sent back on the same channel
79 | if event.type == "digiline" and event.channel == "jumpdrive" then
80 | event.msg = {
81 | success = false, -- true if successful
82 | msg = "Protected by xyz!"
83 | }
84 | end
85 | ```
86 |
87 | ### Execute jump
88 |
89 | Execute a jump
90 |
91 | ```lua
92 | -- request
93 | digiline_send("jumpdrive", {
94 | command = "jump"
95 | })
96 |
97 | -- response sent back on the same channel
98 | if event.type == "digiline" and event.channel == "jumpdrive" then
99 | event.msg = {
100 | success = true,
101 | time = 1234 -- time used in microseconds
102 | }
103 | end
104 | ```
105 |
106 | ## Fleetcontroller
107 |
108 | Fleetcontroller interface
109 |
110 | ### Query current status/coords
111 |
112 | Request coordinates and status
113 |
114 | ```lua
115 | -- request
116 | digiline_send("fleetcontroller", {
117 | command = "get"
118 | })
119 |
120 | -- response sent back on the same channel
121 | if event.type == "digiline" and event.channel == "fleetcontroller" then
122 | event.msg = {
123 | active = true,
124 | engines = {
125 | {
126 | power_req = 10000,
127 | powerstorage = 125000,
128 | radius = 10,
129 | position = { x=0, y=0, z=0 },
130 | target = { x=0, y=0, z=0 },
131 | distance = 2500,
132 | },{
133 | -- etc
134 | }
135 | },
136 | max_power_req = 100000, -- max power of an engine
137 | total_power_req = 12500000, -- total power of all engines
138 | position = { x=0, y=0, z=0 },
139 | target = { x=0, y=0, z=0 },
140 | distance = 2500,
141 | }
142 | end
143 | ```
144 |
145 |
146 | ### Reset coordinates
147 |
148 | Resets the target coordinates
149 |
150 | ```lua
151 | -- request
152 | digiline_send("fleetcontroller", {
153 | command = "reset"
154 | })
155 |
156 | -- response sent back on the same channel
157 | if event.type == "digiline" and event.channel == "fleetcontroller" then
158 | -- sent if the jump is still in progress
159 | event.msg = {
160 | success = false,
161 | msg = "Operation not completed"
162 | }
163 | end
164 | ```
165 |
166 |
167 | ### Set coordinates
168 |
169 | Resets the target coordinates
170 |
171 | Where
172 | * `x` sets x coordinate
173 | * `y` sets y coordinate
174 | * `z` sets z coordinate
175 | * `formupdate` updates coordinates on formspec
176 |
177 | Every value is optional. `x`, `y` and `z` must be integers. `formupdate` is truth value.
178 |
179 | ```lua
180 | -- request
181 | digiline_send("fleetcontroller", {
182 | command = "set",
183 | x = 0,
184 | y = 100,
185 | z = 1024,
186 | formupdate = false
187 | })
188 |
189 | -- response sent back on the same channel
190 | if event.type == "digiline" and event.channel == "fleetcontroller" then
191 | -- sent if the jump is still in progress
192 | event.msg = {
193 | success = false,
194 | msg = "Operation not completed"
195 | }
196 | end
197 | ```
198 |
199 | Response is only sent when operation fails due to another operation is in progress like simulation or jump.
200 | Error will not be sent for invalid values or missing values because every value is optional.
201 |
202 | ### Simulate jump
203 |
204 | Simulates a jump
205 |
206 | ```lua
207 | -- request
208 | digiline_send("fleetcontroller", {
209 | command = "simulate"
210 | })
211 |
212 | -- response sent back on the same channel
213 | if event.type == "digiline" and event.channel == "fleetcontroller" then
214 | -- sent if the jump is still in progress
215 | event.msg = {
216 | success = false,
217 | msg = "Operation not completed"
218 | }
219 |
220 | -- sent on abort
221 | event.msg {
222 | success = false,
223 | index = 1,
224 | count = 10,
225 | msg = "simulation aborted"
226 | }
227 |
228 | -- sent if an error occured
229 | event.msg = {
230 | success = false,
231 | pos = { x=0, y=0, z=0 },
232 | msg = "Protected by xyz!"
233 | }
234 |
235 | -- sent on success
236 | event.msg = {
237 | success = true,
238 | count = 10,
239 | msgs = {
240 | -- possible warning messages for engines like target in vacuum warning
241 | }
242 | }
243 | end
244 | ```
245 |
246 |
247 | ### Execute jump
248 |
249 | Executes a jump
250 |
251 | ```lua
252 | -- request
253 | digiline_send("fleetcontroller", {
254 | command = "jump"
255 | })
256 |
257 | -- response sent back on the same channel
258 | if event.type == "digiline" and event.channel == "fleetcontroller" then
259 | -- sent if the jump is still in progress
260 | event.msg = {
261 | success = false,
262 | msg = "Operation not completed"
263 | }
264 |
265 | -- sent on abort
266 | event.msg {
267 | success = false,
268 | index = 1,
269 | count = 10,
270 | msg = "jump aborted"
271 | }
272 |
273 | -- sent if an error occured
274 | event.msg = {
275 | success = false,
276 | count = 1,
277 | msg = "Protected by xyz!",
278 | msgs = {
279 | -- messages
280 | }
281 | }
282 |
283 | -- sent on success
284 | event.msg = {
285 | success = true,
286 | count = 10,
287 | msgs = {
288 | -- messages
289 | },
290 | time = 1234 -- microseconds used
291 | }
292 | end
293 | ```
294 |
--------------------------------------------------------------------------------
/engine.lua:
--------------------------------------------------------------------------------
1 | local has_technic = minetest.get_modpath("technic")
2 | local has_vizlib = minetest.get_modpath("vizlib")
3 |
4 | minetest.register_node("jumpdrive:engine", {
5 | description = "Jumpdrive",
6 |
7 | tiles = {"jumpdrive.png"},
8 |
9 | tube = {
10 | insert_object = function(pos, _, stack)
11 | local meta = minetest.get_meta(pos)
12 | local inv = meta:get_inventory()
13 | return inv:add_item("main", stack)
14 | end,
15 | can_insert = function(pos, _, stack)
16 | local meta = minetest.get_meta(pos)
17 | local inv = meta:get_inventory()
18 | stack = stack:peek_item(1)
19 |
20 | return inv:room_for_item("main", stack)
21 | end,
22 | input_inventory = "main",
23 | connect_sides = {bottom = 1}
24 | },
25 |
26 | connects_to = {"group:technic_hv_cable"},
27 | connect_sides = {"bottom", "top", "left", "right", "front", "back"},
28 |
29 | is_ground_content = false,
30 | light_source = 13,
31 | groups = {
32 | cracky = 3,
33 | oddly_breakable_by_hand = 3,
34 | tubedevice = 1,
35 | tubedevice_receiver = 1,
36 | technic_machine = 1,
37 | technic_hv = 1,
38 | handy=1,
39 | pickaxey=1
40 | },
41 | _mcl_blast_resistance = 2,
42 | _mcl_hardness = 0.9,
43 |
44 | sounds = jumpdrive.sounds.node_sound_glass_defaults(),
45 |
46 | digiline = {
47 | receptor = {
48 | rules = jumpdrive.digiline_rules,
49 | action = function() end
50 | },
51 | effector = {
52 | rules = jumpdrive.digiline_rules,
53 | action = jumpdrive.digiline_effector
54 | }
55 | },
56 |
57 | after_place_node = function(pos, placer)
58 | local meta = minetest.get_meta(pos)
59 | meta:set_string("owner", placer:get_player_name() or "")
60 | -- default digiline channel
61 | meta:set_string("channel", "jumpdrive")
62 | end,
63 |
64 | on_construct = function(pos)
65 | local meta = minetest.get_meta(pos)
66 | meta:set_int("x", pos.x)
67 | meta:set_int("y", pos.y)
68 | meta:set_int("z", pos.z)
69 | meta:set_int("radius", 5)
70 | meta:set_int("powerstorage", 0)
71 | jumpdrive.migrate_engine_meta(pos, meta)
72 |
73 | meta:set_int("HV_EU_input", 0)
74 | meta:set_int("HV_EU_demand", 0)
75 |
76 | -- With [vizlib] when showing radius/simulation
77 | --meta:set_int("simulation_expiry", 0)
78 |
79 | jumpdrive.update_formspec(meta, pos)
80 | end,
81 |
82 | can_dig = function(pos,player)
83 | local meta = minetest.get_meta(pos);
84 | local inv = meta:get_inventory()
85 | local name = player:get_player_name()
86 |
87 | return inv:is_empty("main") and
88 | inv:is_empty("upgrade") and
89 | not minetest.is_protected(pos, name)
90 | end,
91 |
92 | on_timer = function(pos)
93 | local meta = minetest.get_meta(pos)
94 |
95 | local store = meta:get_int("powerstorage")
96 | local max_store = meta:get_int("max_powerstorage")
97 |
98 | if store >= max_store then
99 | -- internal store is full
100 | return true
101 | end
102 |
103 | local inv = meta:get_inventory()
104 | for i=1, inv:get_size("main") do
105 | local stack = inv:get_stack("main", i)
106 | if not stack:is_empty() then
107 | local burn_value = jumpdrive.fuel.get_value(stack:get_name())
108 | if burn_value > 0 then
109 | local store_space = max_store - store
110 | local fuel_value = burn_value * stack:get_count()
111 | if fuel_value > store_space then
112 | stack:set_count(stack:get_count() - math.ceil(store_space / burn_value))
113 | store = max_store
114 | else
115 | stack:clear()
116 | store = store + fuel_value
117 | end
118 | inv:set_stack("main", i, stack)
119 | end
120 | end
121 | end
122 | meta:set_int("powerstorage", store)
123 |
124 | if not has_technic then
125 | jumpdrive.update_infotext(meta, pos)
126 | end
127 |
128 | -- restart timer
129 | return true
130 | end,
131 |
132 | technic_run = jumpdrive.technic_run,
133 |
134 | on_receive_fields = function(pos, _, fields, sender)
135 |
136 | local meta = minetest.get_meta(pos);
137 | jumpdrive.migrate_engine_meta(pos, meta)
138 |
139 | if not sender then
140 | return
141 | end
142 |
143 | if minetest.is_protected(pos, sender:get_player_name()) then
144 | -- not allowed
145 | return
146 | end
147 |
148 | if fields.read_book then
149 | jumpdrive.read_from_book(pos)
150 | jumpdrive.update_formspec(meta, pos)
151 | return
152 | end
153 |
154 | if fields.reset then
155 | jumpdrive.reset_coordinates(pos)
156 | jumpdrive.update_formspec(meta, pos)
157 | return
158 | end
159 |
160 | if fields.write_book then
161 | jumpdrive.write_to_book(pos, sender)
162 | return
163 | end
164 |
165 | if fields.set_digiline_channel and fields.digiline_channel then
166 | meta:set_string("channel", fields.digiline_channel)
167 | jumpdrive.update_formspec(meta, pos)
168 | return
169 | end
170 |
171 | local x = tonumber(fields.x);
172 | local y = tonumber(fields.y);
173 | local z = tonumber(fields.z);
174 | local radius = tonumber(fields.radius);
175 |
176 | if x == nil or y == nil or z == nil or radius == nil or radius < 1 then
177 | return
178 | end
179 |
180 | local max_radius = jumpdrive.config.max_radius
181 |
182 | if radius > max_radius then
183 | minetest.chat_send_player(sender:get_player_name(), "Invalid jump: max-radius=" .. max_radius)
184 | return
185 | end
186 |
187 | -- update coords
188 | meta:set_int("x", jumpdrive.sanitize_coord(x))
189 | meta:set_int("y", jumpdrive.sanitize_coord(y))
190 | meta:set_int("z", jumpdrive.sanitize_coord(z))
191 | meta:set_int("radius", radius)
192 | jumpdrive.update_formspec(meta, pos)
193 |
194 | if fields.jump then
195 | local success, msg = jumpdrive.execute_jump(pos, sender)
196 | if success then
197 | local time_millis = math.floor(msg / 1000)
198 | minetest.chat_send_player(sender:get_player_name(), "Jump executed in " .. time_millis .. " ms")
199 | else
200 | minetest.chat_send_player(sender:get_player_name(), msg)
201 | end
202 | end
203 |
204 | if fields.show then
205 | local success, msg = jumpdrive.simulate_jump(pos, sender, true)
206 | if not success then
207 | minetest.chat_send_player(sender:get_player_name(), msg)
208 | return
209 | end
210 | minetest.chat_send_player(sender:get_player_name(), "Simulation successful")
211 | end
212 |
213 | end,
214 |
215 | -- inventory protection
216 | allow_metadata_inventory_move = function(pos, _, _, _, _, count, player)
217 | if (not player)
218 | or (not player:is_player())
219 | or minetest.is_protected(pos, player:get_player_name())
220 | then return 0 end
221 |
222 | return count
223 | end,
224 |
225 | allow_metadata_inventory_take = function(pos, _, _, stack, player)
226 | if (not player)
227 | or (not player:is_player())
228 | or minetest.is_protected(pos, player:get_player_name())
229 | then return 0 end
230 |
231 | return stack:get_count()
232 | end,
233 |
234 | allow_metadata_inventory_put = function(pos, _, _, stack, player)
235 | if (not player)
236 | or (not player:is_player())
237 | or minetest.is_protected(pos, player:get_player_name())
238 | then return 0 end
239 |
240 | return stack:get_count()
241 | end,
242 |
243 | -- upgrade re-calculation
244 | on_metadata_inventory_put = function(pos, listname)
245 | if listname == "upgrade" then
246 | jumpdrive.upgrade.calculate(pos)
247 | end
248 | end,
249 |
250 | on_metadata_inventory_take = function(pos, listname)
251 | if listname == "upgrade" then
252 | jumpdrive.upgrade.calculate(pos)
253 | end
254 | end,
255 |
256 | on_metadata_inventory_move = function(pos, from_list, _, to_list)
257 | if from_list == "upgrade" or to_list == "upgrade" then
258 | jumpdrive.upgrade.calculate(pos)
259 | end
260 | end,
261 |
262 | on_punch = has_vizlib and function(pos, _, player)
263 | if not player or player:get_wielded_item():get_name() ~= "" then
264 | -- Only show jump area when using an empty hand
265 | return
266 | end
267 | local radius = minetest.get_meta(pos):get_int("radius")
268 | vizlib.draw_cube(pos, radius + 0.5, { color = "#00ff00", player = player })
269 | end or nil,
270 | })
271 |
272 | if minetest.get_modpath("technic") then
273 | technic.register_machine("HV", "jumpdrive:engine", technic.receiver)
274 | end
275 |
276 |
--------------------------------------------------------------------------------
/fleet/fleet_controller.lua:
--------------------------------------------------------------------------------
1 |
2 | minetest.register_node("jumpdrive:fleet_controller", {
3 | description = "Jumpdrive Fleet controller",
4 |
5 | tiles = {"jumpdrive_fleet_controller.png"},
6 | groups = {cracky=3,oddly_breakable_by_hand=3,handy=1,pickaxey=1},
7 | _mcl_blast_resistance = 2,
8 | _mcl_hardness = 0.9,
9 | sounds = jumpdrive.sounds.node_sound_glass_defaults(),
10 |
11 | is_ground_content = false,
12 | light_source = 13,
13 |
14 | digiline = {
15 | receptor = {
16 | rules = jumpdrive.digiline_rules,
17 | action = function() end
18 | },
19 | effector = {
20 | rules = jumpdrive.digiline_rules,
21 | action = jumpdrive.fleet.digiline_effector
22 | }
23 | },
24 |
25 | after_place_node = function(pos, placer)
26 | local meta = minetest.get_meta(pos)
27 | -- owner of fleet_controller
28 | meta:set_string("owner", placer:get_player_name() or "")
29 | -- default digiline channel
30 | meta:set_string("channel", "fleetcontroller")
31 |
32 | jumpdrive.fleet.update_formspec(meta, pos)
33 | end,
34 |
35 | on_construct = function(pos)
36 | local meta = minetest.get_meta(pos)
37 | meta:set_int("x", pos.x)
38 | meta:set_int("y", pos.y)
39 | meta:set_int("z", pos.z)
40 |
41 | -- jumping active (1=active)
42 | meta:set_int("active", 0)
43 | -- if active, current index in jump list (1...n)
44 | meta:set_int("jump_index", 0)
45 | -- jump list
46 | meta:set_string("jump_list", "")
47 |
48 | local inv = meta:get_inventory()
49 | inv:set_size("main", 8)
50 |
51 | jumpdrive.fleet.update_formspec(meta, pos)
52 | end,
53 |
54 | can_dig = function(pos,player)
55 | local meta = minetest.get_meta(pos);
56 | local inv = meta:get_inventory()
57 | local name = player:get_player_name()
58 |
59 | return inv:is_empty("main") and not minetest.is_protected(pos, name)
60 | end,
61 |
62 | on_receive_fields = function(pos, _, fields, sender)
63 |
64 | local meta = minetest.get_meta(pos);
65 |
66 | if not sender then
67 | return
68 | end
69 |
70 | if minetest.is_protected(pos, sender:get_player_name()) then
71 | -- not allowed
72 | return
73 | end
74 |
75 | if fields.read_book then
76 | jumpdrive.read_from_book(pos)
77 | jumpdrive.fleet.update_formspec(meta, pos)
78 | return
79 | end
80 |
81 | if fields.reset then
82 | jumpdrive.reset_coordinates(pos)
83 | jumpdrive.fleet.update_formspec(meta, pos)
84 | return
85 | end
86 |
87 | if fields.write_book then
88 | jumpdrive.write_to_book(pos, sender)
89 | return
90 | end
91 |
92 | if fields.set_digiline_channel and fields.digiline_channel then
93 | meta:set_string("channel", fields.digiline_channel)
94 | jumpdrive.fleet.update_formspec(meta, pos)
95 | return
96 | end
97 |
98 | local x = tonumber(fields.x);
99 | local y = tonumber(fields.y);
100 | local z = tonumber(fields.z);
101 |
102 | if x == nil or y == nil or z == nil then
103 | return
104 | end
105 |
106 | -- update coords
107 | meta:set_int("x", jumpdrive.sanitize_coord(x))
108 | meta:set_int("y", jumpdrive.sanitize_coord(y))
109 | meta:set_int("z", jumpdrive.sanitize_coord(z))
110 | jumpdrive.fleet.update_formspec(meta, pos)
111 |
112 | local t0 = minetest.get_us_time()
113 | local engines_pos_list = jumpdrive.fleet.find_engines(pos)
114 | local t1 = minetest.get_us_time()
115 | minetest.log("action", "[jumpdrive-fleet] backbone traversing took " ..
116 | (t1 - t0) .. " us @ " .. minetest.pos_to_string(pos))
117 |
118 | local targetPos = {x=meta:get_int("x"),y=meta:get_int("y"),z=meta:get_int("z")}
119 |
120 | -- sort by distance, farthes first
121 | jumpdrive.fleet.sort_engines(pos, engines_pos_list)
122 |
123 | -- apply new coordinates
124 | jumpdrive.fleet.apply_coordinates(pos, targetPos, engines_pos_list)
125 |
126 | if fields.jump then
127 | --TODO check overlapping engines/radius
128 | meta:set_int("active", 1)
129 | meta:set_int("jump_index", 1)
130 | meta:set_string("jump_list", minetest.serialize(engines_pos_list))
131 | jumpdrive.fleet.update_formspec(meta, pos)
132 |
133 | local timer = minetest.get_node_timer(pos)
134 | timer:start(2.0)
135 | end
136 |
137 | if fields.stop then
138 | meta:set_int("active", 0)
139 | local timer = minetest.get_node_timer(pos)
140 | timer:stop()
141 | jumpdrive.fleet.update_formspec(meta, pos)
142 | end
143 |
144 | if fields.show then
145 | local playername = sender:get_player_name()
146 | minetest.chat_send_player(playername, "Found " .. #engines_pos_list .. " jumpdrives")
147 |
148 | if #engines_pos_list == 0 then
149 | return
150 | end
151 |
152 | local index = 1
153 | local async_check
154 | async_check = function()
155 | local engine_pos = engines_pos_list[index]
156 | local success, msg = jumpdrive.simulate_jump(engine_pos, sender, true)
157 | if not success then
158 | minetest.chat_send_player(playername, msg .. " @ " .. minetest.pos_to_string(engine_pos))
159 | return
160 | end
161 |
162 | minetest.chat_send_player(sender:get_player_name(), "Check passed for engine " .. index .. "/" .. #engines_pos_list)
163 |
164 | if index < #engines_pos_list then
165 | -- more drives to check
166 | index = index + 1
167 | minetest.after(1, async_check)
168 |
169 | elseif index >= #engines_pos_list then
170 | -- done
171 | minetest.chat_send_player(sender:get_player_name(), "Simulation successful")
172 | end
173 | end
174 |
175 | minetest.after(1, async_check)
176 | end
177 |
178 | end,
179 |
180 | on_timer = function(pos)
181 | local meta = minetest.get_meta(pos)
182 | local jump_index = meta:get_int("jump_index")
183 | local jump_list = minetest.deserialize( meta:get_string("jump_list") )
184 |
185 | if jump_list and jump_index and #jump_list >= jump_index then
186 |
187 | local is_last = #jump_list == jump_index
188 | local node_pos = jump_list[jump_index]
189 | local success, msg = jumpdrive.execute_jump(node_pos)
190 |
191 | local playername = meta:get_string("owner")
192 | if not playername then
193 | local node_meta = minetest.get_meta(node_pos)
194 | playername = node_meta:get_string("owner")
195 | end
196 |
197 | if success then
198 | -- at this point if it is the last engine the metadata does not exist anymore in the current location
199 |
200 | if not is_last then
201 | meta:set_int("jump_index", jump_index+1)
202 | jumpdrive.fleet.update_formspec(meta, pos)
203 |
204 | -- re-schedule
205 | local timer = minetest.get_node_timer(pos)
206 | timer:start(2.0)
207 | end
208 | if playername then
209 | local time_millis = math.floor(msg / 1000)
210 | minetest.chat_send_player(playername, "Jump executed in " .. time_millis .. " ms")
211 | end
212 | else
213 | meta:set_int("active", 0)
214 | jumpdrive.fleet.update_formspec(meta, pos)
215 | meta:set_string("infotext", "Engine ".. minetest.pos_to_string(node_pos) .. " failed with: " .. msg)
216 | if playername then
217 | minetest.chat_send_player(playername, msg)
218 | end
219 | end
220 | else
221 | meta:set_int("active", 0)
222 | jumpdrive.fleet.update_formspec(meta, pos)
223 | end
224 | end
225 | })
226 |
--------------------------------------------------------------------------------
/fleet/fleet_digiline.lua:
--------------------------------------------------------------------------------
1 |
2 | local is_int = function(value)
3 | return type(value) == 'number' and math.floor(value) == value
4 | end
5 |
6 | jumpdrive.fleet.is_active = function(pos)
7 | local meta = minetest.get_meta(pos)
8 | return meta:get_int("active") > 0
9 | end
10 |
11 | jumpdrive.fleet.get_fleet_data = function(pos, target_pos, engines_pos_list)
12 | local t0 = minetest.get_us_time()
13 |
14 | -- get some more or less useful data from fleet
15 | local engines = {}
16 | local max_power_req = 0
17 | local total_power_req = 0
18 | local distance = nil
19 | local active = jumpdrive.fleet.is_active(pos)
20 |
21 | local delta_vector = nil
22 | if target_pos then
23 | delta_vector = vector.subtract(target_pos, pos)
24 | distance = vector.distance(pos, target_pos)
25 | end
26 |
27 | if not active then
28 | for _,engine_pos in ipairs(engines_pos_list) do
29 | local engine_meta = minetest.get_meta(engine_pos)
30 | local powerstorage = engine_meta:get_int("powerstorage")
31 | local radius = jumpdrive.get_radius(engine_pos)
32 | local engine_target_pos = nil
33 | local engine_distance = nil
34 | local engine_power_req = 0
35 | if target_pos then
36 | engine_target_pos = vector.add(engine_pos, delta_vector)
37 | engine_distance = vector.distance(engine_pos, engine_target_pos)
38 | engine_power_req = jumpdrive.calculate_power(radius, engine_distance, engine_pos, engine_target_pos)
39 | if engine_power_req > max_power_req then
40 | max_power_req = engine_power_req
41 | end
42 | total_power_req = total_power_req + engine_power_req
43 | end
44 | table.insert(engines, {
45 | power_req = engine_power_req,
46 | powerstorage = powerstorage,
47 | radius = radius,
48 | position = engine_pos,
49 | target = engine_target_pos,
50 | distance = engine_distance,
51 | })
52 | end
53 | end
54 |
55 | local t1 = minetest.get_us_time()
56 | minetest.log("action", "[jumpdrive-fleet] fleet data collection took " ..
57 | (t1 - t0) .. " us @ " .. minetest.pos_to_string(pos))
58 |
59 | return {
60 | active = active,
61 | engines = engines,
62 | max_power_req = max_power_req,
63 | total_power_req = total_power_req,
64 | position = pos,
65 | target = target_pos,
66 | distance = distance,
67 | }
68 | end
69 |
70 | jumpdrive.fleet.get_engines_sorted = function(pos)
71 | local t0 = minetest.get_us_time()
72 | local engines_pos_list = jumpdrive.fleet.find_engines(pos)
73 | local t1 = minetest.get_us_time()
74 | minetest.log("action", "[jumpdrive-fleet] backbone traversing took " ..
75 | (t1 - t0) .. " us @ " .. minetest.pos_to_string(pos))
76 |
77 | -- sort by distance, farthes first
78 | jumpdrive.fleet.sort_engines(pos, engines_pos_list)
79 |
80 | return engines_pos_list
81 | end
82 |
83 | jumpdrive.fleet.digiline_async_simulate = function(pos, channel, owner, engines)
84 | local index = 1
85 | local meta = minetest.get_meta(pos)
86 | local msglist = {}
87 | local async_check
88 | async_check = function()
89 | if meta:get_int("active") < 1 then
90 | -- operation aborted by user while there's still work to do
91 | digilines.receptor_send(pos, jumpdrive.digiline_rules, channel, {
92 | success = false,
93 | index = index,
94 | count = #engines,
95 | msg = "simulation aborted",
96 | })
97 | return
98 | end
99 |
100 | local engine_pos = engines[index]
101 | local success, msg = jumpdrive.simulate_jump(engine_pos, owner, false)
102 |
103 | if not success then
104 | digilines.receptor_send(pos, jumpdrive.digiline_rules, channel, {
105 | success=false,
106 | pos=engine_pos,
107 | msg=msg,
108 | })
109 | meta:set_int("active", 0)
110 | jumpdrive.fleet.update_formspec(meta, pos)
111 | return
112 | end
113 | table.insert(msglist, msg)
114 |
115 | if index < #engines then
116 | -- more drives to check
117 | index = index + 1
118 | minetest.after(1, async_check)
119 |
120 | elseif index >= #engines then
121 | -- done
122 | digilines.receptor_send(pos, jumpdrive.digiline_rules, channel, {
123 | success=true,
124 | count=index,
125 | msgs=msglist,
126 | })
127 | meta:set_int("active", 0)
128 | jumpdrive.fleet.update_formspec(meta, pos)
129 | end
130 | end
131 | meta:set_string("jump_list", minetest.serialize(engines))
132 | meta:set_int("active", 1)
133 | jumpdrive.fleet.update_formspec(meta, pos)
134 | minetest.after(1, async_check)
135 | end
136 |
137 | jumpdrive.fleet.digiline_async_jump = function(pos, target_pos, channel, _, engines)
138 | local t0 = minetest.get_us_time()
139 | local meta = minetest.get_meta(pos)
140 | local all_success = false
141 | local msglist = {}
142 | local index = 1
143 | local async_jump
144 | async_jump = function()
145 | if engines and index and #engines >= index then
146 | if meta:get_int("active") < 1 then
147 | -- operation aborted by user while there's still work to do
148 | digilines.receptor_send(pos, jumpdrive.digiline_rules, channel, {
149 | success = false,
150 | index = index,
151 | count = #engines,
152 | msg = "jump aborted",
153 | })
154 | return
155 | end
156 |
157 | local node_pos = engines[index]
158 | local success, msg = jumpdrive.execute_jump(node_pos)
159 | table.insert(msglist, msg)
160 |
161 | if success then
162 | -- at this point if it is the last engine the metadata does not exist anymore in the current location
163 |
164 | if #engines == index then
165 | -- last engine jumped successfully
166 | all_success = true
167 | else
168 | meta:set_int("jump_index", index)
169 | end
170 | -- execute for each engine and once after last engine jumped
171 | index = index + 1
172 | minetest.after(1, async_jump)
173 | else
174 | digilines.receptor_send(pos, jumpdrive.digiline_rules, channel, {
175 | success = false,
176 | count = index,
177 | msg = msg,
178 | msgs = msglist,
179 | })
180 | meta:set_int("active", 0)
181 | jumpdrive.fleet.update_formspec(meta, pos)
182 | end
183 | else
184 | local targetmeta = minetest.get_meta(target_pos)
185 | local t1 = minetest.get_us_time()
186 | digilines.receptor_send(target_pos, jumpdrive.digiline_rules, channel, {
187 | success = all_success, -- in case someone calls with zero engines should it be success or not?
188 | count = index,
189 | msgs = msglist,
190 | time = t1 - t0
191 | })
192 | targetmeta:set_int("active", 0)
193 | jumpdrive.fleet.update_formspec(targetmeta, target_pos)
194 | end
195 | end
196 | meta:set_string("jump_list", minetest.serialize(engines))
197 | meta:set_int("active", 1)
198 | jumpdrive.fleet.update_formspec(meta, pos)
199 | minetest.after(1, async_jump)
200 | end
201 |
202 | jumpdrive.fleet.digiline_effector = function(pos, _, channel, msg)
203 |
204 | if type(msg) ~= "table" then
205 | return
206 | end
207 |
208 | local meta = minetest.get_meta(pos)
209 |
210 | local set_channel = meta:get_string("channel")
211 | if channel ~= set_channel then
212 | return
213 | end
214 |
215 | local playername = meta:get_string("owner")
216 | if not playername then
217 | return
218 | end
219 |
220 | local targetPos = jumpdrive.get_meta_pos(pos)
221 |
222 | if msg.command == "get" then
223 |
224 | local engines_pos_list = jumpdrive.fleet.find_engines(pos)
225 | local fleetdata = jumpdrive.fleet.get_fleet_data(pos, targetPos, engines_pos_list)
226 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, fleetdata)
227 |
228 | elseif msg.command == "reset" then
229 |
230 | if jumpdrive.fleet.is_active(pos) then
231 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, {
232 | success = false,
233 | msg = "Operation not completed",
234 | })
235 | return
236 | end
237 |
238 | meta:set_int("x", pos.x)
239 | meta:set_int("y", pos.y)
240 | meta:set_int("z", pos.z)
241 | jumpdrive.fleet.update_formspec(meta, pos)
242 |
243 | elseif msg.command == "set" then
244 |
245 | if jumpdrive.fleet.is_active(pos) then
246 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, {
247 | success = false,
248 | msg = "Operation not completed",
249 | })
250 | return
251 | end
252 |
253 | -- API requires integers for coord values, noop for everything else
254 | if is_int(msg.x) then meta:set_int("x", jumpdrive.sanitize_coord(msg.x)) end
255 | if is_int(msg.y) then meta:set_int("y", jumpdrive.sanitize_coord(msg.y)) end
256 | if is_int(msg.z) then meta:set_int("z", jumpdrive.sanitize_coord(msg.z)) end
257 | if msg.formupdate then
258 | jumpdrive.fleet.update_formspec(meta, pos)
259 | end
260 |
261 | elseif msg.command == "simulate" or msg.command == "show" then
262 |
263 | if jumpdrive.fleet.is_active(pos) then
264 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, {
265 | success = false,
266 | msg = "Operation not completed",
267 | })
268 | return
269 | end
270 |
271 | local engines_pos_list = jumpdrive.fleet.get_engines_sorted(pos)
272 |
273 | if #engines_pos_list == 0 then
274 | return
275 | end
276 |
277 | -- apply new coordinates
278 | jumpdrive.fleet.apply_coordinates(pos, targetPos, engines_pos_list)
279 |
280 | local owner = minetest.get_player_by_name(playername)
281 | jumpdrive.fleet.digiline_async_simulate(pos, channel, owner, engines_pos_list)
282 |
283 | elseif msg.command == "jump" then
284 |
285 | if jumpdrive.fleet.is_active(pos) then
286 | digilines.receptor_send(pos, jumpdrive.digiline_rules, set_channel, {
287 | success = false,
288 | msg = "Operation not completed",
289 | })
290 | return
291 | end
292 |
293 | local engines_pos_list = jumpdrive.fleet.get_engines_sorted(pos)
294 |
295 | if #engines_pos_list == 0 then
296 | return
297 | end
298 |
299 | -- apply new coordinates
300 | jumpdrive.fleet.apply_coordinates(pos, targetPos, engines_pos_list)
301 |
302 | local owner = minetest.get_player_by_name(playername)
303 | jumpdrive.fleet.digiline_async_jump(pos, targetPos, channel, owner, engines_pos_list)
304 |
305 | end
306 | end
307 |
--------------------------------------------------------------------------------
/fleet/fleet_formspec.lua:
--------------------------------------------------------------------------------
1 |
2 | local inv_width = 8
3 | local inv_height = 10
4 |
5 | local player_inv_fs = "list[current_player;main;0,5;8,4;]"
6 | local listring_fs = "listring[]"
7 | local mcl_fs = ""
8 |
9 | if minetest.get_modpath("mcl_formspec") then
10 | inv_width = 9
11 | inv_height = 10.5
12 | mcl_fs = mcl_formspec.get_itemslot_bg(0,3.75,8,1)
13 | player_inv_fs = ""..
14 | "list[current_player;main;0,4.9;9,3;9]"..
15 | mcl_formspec.get_itemslot_bg(0,4.9,9,3)..
16 | "list[current_player;main;0,8.05;9,1;]"..
17 | mcl_formspec.get_itemslot_bg(0,8.05,9,1)
18 | listring_fs = "listring[current_player;main]"
19 | end
20 |
21 | jumpdrive.fleet.update_formspec = function(meta)
22 |
23 | local button_line =
24 | "button_exit[0,1.5;2,1;jump;Jump]" ..
25 | "button_exit[2,1.5;2,1;show;Show]" ..
26 | "button_exit[4,1.5;2,1;save;Save]" ..
27 | "button[6,1.5;2,1;reset;Reset]"
28 |
29 | if meta:get_int("active") == 1 then
30 | local jump_index = meta:get_int("jump_index")
31 | local jump_list = minetest.deserialize( meta:get_string("jump_list") )
32 |
33 | meta:set_string("infotext", "Controller active: " .. jump_index .. "/" .. #jump_list)
34 |
35 | button_line = "button_exit[0,1.5;8,1;stop;Stop]"
36 | else
37 | meta:set_string("infotext", "Ready")
38 | end
39 |
40 | meta:set_string("formspec", "size["..inv_width..","..inv_height..";]" ..
41 | "field[0.3,0.5;2,1;x;X;" .. meta:get_int("x") .. "]" ..
42 | "field[3.3,0.5;2,1;y;Y;" .. meta:get_int("y") .. "]" ..
43 | "field[6.3,0.5;2,1;z;Z;" .. meta:get_int("z") .. "]" ..
44 |
45 | button_line ..
46 |
47 | "button[0,2.5;4,1;write_book;Write to book]" ..
48 | "button[4,2.5;4,1;read_book;Read from bookmark]" ..
49 |
50 | "list[context;main;0,3.75;8,1;]" ..
51 |
52 | player_inv_fs..
53 |
54 | "field[4.3,9.52;3.2,1;digiline_channel;Digiline channel;" .. (meta:get_string("channel") or "") .. "]" ..
55 | "button_exit[7,9.2;1,1;set_digiline_channel;Set]" ..
56 |
57 | -- listring stuff
58 | listring_fs..
59 |
60 | -- mcl
61 | mcl_fs)
62 | end
63 |
64 |
--------------------------------------------------------------------------------
/fleet/fleet_functions.lua:
--------------------------------------------------------------------------------
1 |
2 | jumpdrive.fleet = {}
3 |
4 | -- applies the new coordinates derived from the relative position of the controller
5 | jumpdrive.fleet.apply_coordinates = function(controllerPos, targetPos, engine_pos_list)
6 | -- delta between source and target
7 | local delta_vector = vector.subtract(targetPos, controllerPos)
8 | minetest.log("action", "[jumpdrive-fleet] delta-vector: " .. minetest.pos_to_string(delta_vector))
9 |
10 | for _,node_pos in pairs(engine_pos_list) do
11 | local new_pos = vector.add(node_pos, delta_vector)
12 | minetest.log("action", "[jumpdrive-fleet] calculated vector: " .. minetest.pos_to_string(new_pos))
13 |
14 | -- set destination position
15 | jumpdrive.set_meta_pos(node_pos, new_pos)
16 | -- update formspec to reflect new positions
17 | jumpdrive.update_formspec(minetest.get_meta(node_pos), node_pos)
18 | end
19 | end
20 |
21 | -- sort list by distance, farthest first
22 | jumpdrive.fleet.sort_engines = function(pos, engine_pos_list)
23 | table.sort(engine_pos_list, function(a,b)
24 | local a_distance = vector.distance(a, pos)
25 | local b_distance = vector.distance(b, pos)
26 | return a_distance > b_distance
27 | end)
28 | end
29 |
30 | -- traverses the backbone and returns a list of engines
31 | jumpdrive.fleet.find_engines = function(pos, visited_hashes, engine_pos_list)
32 |
33 | -- minetest.hash_node_position(pos)
34 | visited_hashes = visited_hashes or {}
35 | engine_pos_list = engine_pos_list or {}
36 |
37 | local pos1 = vector.subtract(pos, 1)
38 | local pos2 = vector.add(pos,1)
39 |
40 | -- load far-away areas
41 | local manip = minetest.get_voxel_manip()
42 | manip:read_from_map(pos1, pos2)
43 |
44 | local engine_nodes = minetest.find_nodes_in_area(pos1, pos2, {"jumpdrive:engine"})
45 |
46 | for _,node_pos in pairs(engine_nodes) do
47 | local hash = minetest.hash_node_position(node_pos)
48 |
49 | if not visited_hashes[hash] then
50 | -- pos not yet visited
51 | visited_hashes[hash] = true
52 | minetest.log("action", "[jumpdrive-fleet] adding engine @ " .. minetest.pos_to_string(node_pos))
53 | table.insert(engine_pos_list, node_pos)
54 |
55 | jumpdrive.fleet.find_engines(node_pos, visited_hashes, engine_pos_list)
56 | end
57 | end
58 |
59 | local backbone_nodes = minetest.find_nodes_in_area(pos1, pos2, {"jumpdrive:backbone"})
60 |
61 | for _,node_pos in pairs(backbone_nodes) do
62 | local hash = minetest.hash_node_position(node_pos)
63 |
64 | if not visited_hashes[hash] then
65 | -- pos not yet visited
66 | visited_hashes[hash] = true
67 |
68 | jumpdrive.fleet.find_engines(node_pos, visited_hashes, engine_pos_list)
69 | end
70 | end
71 |
72 |
73 |
74 | return engine_pos_list
75 | end
76 |
--------------------------------------------------------------------------------
/formspec.lua:
--------------------------------------------------------------------------------
1 | local has_technic = minetest.get_modpath("technic")
2 |
3 | local inv_offset = 0
4 | if has_technic then
5 | inv_offset = 1.25
6 | end
7 |
8 | local inv_width = 8
9 |
10 | local mcl_fs = ""
11 | local player_inv_fs = "list[current_player;main;0,".. 4.5+inv_offset .. ";8,4;]"
12 |
13 | if minetest.get_modpath("mcl_formspec") then
14 | inv_width = 9
15 | mcl_fs = mcl_formspec.get_itemslot_bg(0,3.25,8,1)
16 | player_inv_fs = ""..
17 | "list[current_player;main;0,5.6;9,3;9]"..
18 | mcl_formspec.get_itemslot_bg(0,5.6,9,3)..
19 | "list[current_player;main;0,8.74;9,1;]"..
20 | mcl_formspec.get_itemslot_bg(0,8.74,9,1)
21 | if has_technic then
22 | mcl_fs = mcl_fs..
23 | mcl_formspec.get_itemslot_bg(4,4.5,4,1)
24 | end
25 | end
26 |
27 | jumpdrive.update_formspec = function(meta)
28 | local formspec =
29 | "size["..inv_width.."," .. 9.3+inv_offset .. ";]" ..
30 |
31 | "field[0.3,0.5;2,1;x;X;" .. meta:get_int("x") .. "]" ..
32 | "field[2.3,0.5;2,1;y;Y;" .. meta:get_int("y") .. "]" ..
33 | "field[4.3,0.5;2,1;z;Z;" .. meta:get_int("z") .. "]" ..
34 | "field[6.3,0.5;2,1;radius;Radius;" .. meta:get_int("radius") .. "]" ..
35 |
36 | "button_exit[0,1;2,1;jump;Jump]" ..
37 | "button_exit[2,1;2,1;show;Show]" ..
38 | "button_exit[4,1;2,1;save;Save]" ..
39 | "button[6,1;2,1;reset;Reset]" ..
40 |
41 | "button[0,2;4,1;write_book;Write to book]" ..
42 | "button[4,2;4,1;read_book;Read from bookmark]" ..
43 |
44 | -- main inventory for fuel and books
45 | "list[context;main;0,3.25;8,1;]" ..
46 |
47 | -- player inventory
48 | player_inv_fs..
49 |
50 | -- digiline channel
51 | "field[4.3," .. 9.02+inv_offset ..";3.2,1;digiline_channel;Digiline channel;" ..
52 | (meta:get_string("channel") or "") .. "]" ..
53 | "button_exit[7," .. 8.7+inv_offset .. ";1,1;set_digiline_channel;Set]" ..
54 |
55 | -- listring stuff
56 | "listring[context;main]" ..
57 | "listring[current_player;main]"..
58 |
59 | -- mcl
60 | mcl_fs
61 |
62 | if has_technic then
63 | formspec = formspec ..
64 | -- technic upgrades
65 | "label[3,4.7;Upgrades]" ..
66 | "list[context;upgrade;4,4.5;4,1;]"
67 | end
68 |
69 | meta:set_string("formspec", formspec)
70 | end
71 |
72 |
--------------------------------------------------------------------------------
/fuel.lua:
--------------------------------------------------------------------------------
1 |
2 | local fuel_list = {}
3 |
4 | jumpdrive.fuel = {}
5 |
6 | jumpdrive.fuel.register = function(item_name, value)
7 | fuel_list[item_name] = value
8 | end
9 |
10 | jumpdrive.fuel.get_value = function(item_name)
11 | if not item_name then
12 | return 0
13 | end
14 | return fuel_list[item_name] or 0
15 | end
16 |
17 | if minetest.get_modpath("default") then
18 | jumpdrive.fuel.register("default:mese_crystal_fragment", 100)
19 | jumpdrive.fuel.register("default:mese_crystal", 900)
20 | jumpdrive.fuel.register("default:mese", 8100)
21 | end
22 |
23 | if minetest.get_modpath("mcl_core") and minetest.get_modpath("mesecons") and minetest.get_modpath("mesecons_torch") then
24 | jumpdrive.fuel.register("mesecons:wire_00000000_off", 900)
25 | jumpdrive.fuel.register("mesecons_torch:redstoneblock", 8100)
26 | end
27 |
--------------------------------------------------------------------------------
/hooks.lua:
--------------------------------------------------------------------------------
1 |
2 | -- callback for after-jump actions
3 |
4 | local after_jump_callbacks = {}
5 |
6 | function jumpdrive.register_after_jump(callback)
7 | table.insert(after_jump_callbacks, callback)
8 | end
9 |
10 | function jumpdrive.fire_after_jump(from_area, to_area)
11 | for _, callback in ipairs(after_jump_callbacks) do
12 | callback(from_area, to_area)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/infotext.lua:
--------------------------------------------------------------------------------
1 | local has_technic = minetest.get_modpath("technic")
2 |
3 | jumpdrive.update_infotext = function(meta)
4 | local store = meta:get_int("powerstorage")
5 | local max_store = meta:get_int("max_powerstorage")
6 |
7 | if has_technic then
8 | local eu_input = meta:get_int("HV_EU_input")
9 | local demand = meta:get_int("HV_EU_demand")
10 |
11 | meta:set_string("infotext", "Power: " .. eu_input .. "/" .. demand .. " Store: " .. store .. "/" .. max_store)
12 | else
13 | meta:set_string("infotext", "Store: " .. store .. "/" .. max_store)
14 | end
15 | end
--------------------------------------------------------------------------------
/init.lua:
--------------------------------------------------------------------------------
1 |
2 | jumpdrive = {
3 | config = {
4 | -- allowed radius
5 | max_radius = tonumber(minetest.settings:get("jumpdrive.max_radius")) or 15,
6 | max_area_radius = tonumber(minetest.settings:get("jumpdrive.max_area_radius")) or 25,
7 |
8 | -- max volume in nodes ( ((radius*2) + 1) ^ 3 )
9 | max_area_volume = tonumber(minetest.settings:get("jumpdrive.max_area_volume")) or 29791,
10 |
11 | -- base storage value
12 | powerstorage = tonumber(minetest.settings:get("jumpdrive.powerstorage")) or 1000000,
13 |
14 | -- base technic power requirement
15 | powerrequirement = tonumber(minetest.settings:get("jumpdrive.power_requirement")) or 2500,
16 |
17 | -- allow emerging area on "uncharted" error
18 | emerge_uncharted = core.settings:get_bool("jumpdrive.allow_emerge", false),
19 | },
20 |
21 | -- blacklisted nodes
22 | blacklist = {}
23 | }
24 |
25 | jumpdrive.sounds = {}
26 |
27 | if minetest.get_modpath("default") then
28 | jumpdrive.sounds = default
29 | end
30 |
31 | if minetest.get_modpath("mcl_sounds") then
32 | jumpdrive.sounds = mcl_sounds
33 | end
34 |
35 | local MP = minetest.get_modpath("jumpdrive")
36 |
37 | if minetest.get_modpath("technic") then
38 | dofile(MP.."/technic_run.lua")
39 | end
40 |
41 | -- common functions
42 | dofile(MP.."/fuel.lua")
43 | dofile(MP.."/upgrade.lua")
44 | dofile(MP.."/bookmark.lua")
45 | dofile(MP.."/infotext.lua")
46 | dofile(MP.."/migrate.lua")
47 | dofile(MP.."/hooks.lua")
48 | dofile(MP.."/compat/compat.lua")
49 | dofile(MP.."/is_area_empty.lua")
50 | dofile(MP.."/is_area_protected.lua")
51 |
52 | -- move logic
53 | dofile(MP.."/move/move_objects.lua")
54 | dofile(MP.."/move/move_mapdata.lua")
55 | dofile(MP.."/move/move_metadata.lua")
56 | dofile(MP.."/move/move_nodetimers.lua")
57 | dofile(MP.."/move/move_players.lua")
58 | dofile(MP.."/move/move.lua")
59 |
60 | dofile(MP.."/mapgen.lua")
61 | dofile(MP.."/common.lua")
62 | dofile(MP.."/digiline.lua")
63 | dofile(MP.."/backbone.lua")
64 | dofile(MP.."/warp_device.lua")
65 | dofile(MP.."/crafts.lua")
66 |
67 | -- engine
68 | dofile(MP.."/engine.lua")
69 | dofile(MP.."/formspec.lua")
70 | dofile(MP.."/jump.lua")
71 |
72 | -- fleet
73 | dofile(MP.."/fleet/fleet_functions.lua")
74 | dofile(MP.."/fleet/fleet_digiline.lua")
75 | dofile(MP.."/fleet/fleet_controller.lua")
76 | dofile(MP.."/fleet/fleet_formspec.lua")
77 |
78 | -- blacklist nodes
79 | dofile(MP.."/blacklist.lua")
80 |
81 |
82 | if minetest.get_modpath("monitoring") then
83 | -- enable metrics
84 | dofile(MP.."/metrics.lua")
85 | end
86 |
87 | if minetest.get_modpath("mtt") and mtt.enabled then
88 | dofile(MP.."/mtt.lua")
89 | end
90 |
91 | print("[OK] Jumpdrive")
92 |
--------------------------------------------------------------------------------
/is_area_empty.lua:
--------------------------------------------------------------------------------
1 | local c_ignore = minetest.get_content_id("ignore")
2 |
3 | local buildable_to_nodes = {}
4 |
5 | minetest.after(4, function()
6 | local count = 0
7 | for name, node in pairs(minetest.registered_nodes) do
8 | if node.buildable_to then
9 | count = count + 1
10 | local id = minetest.get_content_id(name)
11 | buildable_to_nodes[id] = true
12 | end
13 | end
14 | minetest.log("action", "[jumpdrive] collected " .. count .. " nodes that are buildable_to")
15 | end)
16 |
17 |
18 |
19 | jumpdrive.is_area_empty = function(pos1, pos2)
20 | local manip = minetest.get_voxel_manip()
21 | local e1, e2 = manip:read_from_map(pos1, pos2)
22 | local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
23 | local data = manip:get_data()
24 |
25 | for z=pos1.z, pos2.z do
26 | for y=pos1.y, pos2.y do
27 | for x=pos1.x, pos2.x do
28 |
29 | local index = area:index(x, y, z)
30 | local id = data[index]
31 |
32 | if id == c_ignore then
33 | return false, "uncharted"
34 | end
35 |
36 | if not buildable_to_nodes[id] then
37 | -- not buildable_to
38 | return false, "occupied"
39 | end
40 | end
41 | end
42 | end
43 |
44 | -- only buildable_to nodes found
45 | return true, ""
46 | end
47 |
48 |
--------------------------------------------------------------------------------
/is_area_protected.lua:
--------------------------------------------------------------------------------
1 | local has_areas_mod = minetest.get_modpath("areas")
2 | local has_protector_mod = minetest.get_modpath("protector")
3 |
4 | local protector_radius = (tonumber(minetest.settings:get("protector_radius")) or 5)
5 |
6 | jumpdrive.is_area_protected = function(pos1, pos2, playername)
7 |
8 | local radius_vector = {x=protector_radius, y=protector_radius, z=protector_radius}
9 | local check_pos1 = vector.subtract(pos1, radius_vector)
10 | local check_pos2 = vector.add(pos2, radius_vector)
11 |
12 | -- preload area with voxel manip
13 | minetest.get_voxel_manip(check_pos1, check_pos2)
14 |
15 | if minetest.is_area_protected then
16 | -- use area protection check
17 | if minetest.is_area_protected(pos1, pos2, playername, 8) then
18 | return true
19 | end
20 |
21 | elseif has_protector_mod then
22 | -- use improvised find_nodes check
23 | local protectors = minetest.find_nodes_in_area(
24 | check_pos1, check_pos2, {
25 | "protector:protect",
26 | "protector:protect2",
27 | "priv_protector:protector",
28 | "xp_redo:protector"
29 | }
30 | )
31 |
32 | if protectors then
33 | for _,pos in pairs(protectors) do
34 | if minetest.is_protected(pos, playername) then
35 | return true
36 | end
37 | end
38 | end
39 | end
40 |
41 | if has_areas_mod then
42 | if not areas:canInteractInArea(pos1, pos2, playername, true) then
43 | -- player can't interact
44 | return true
45 | end
46 | end
47 |
48 | -- no protection
49 | return false
50 | end
51 |
--------------------------------------------------------------------------------
/jump.lua:
--------------------------------------------------------------------------------
1 | local has_vizlib = minetest.get_modpath("vizlib")
2 |
3 | jumpdrive.simulate_jump = function(pos, player, show_marker)
4 |
5 | local targetPos = jumpdrive.get_meta_pos(pos)
6 |
7 | local mapgen_distance = jumpdrive.check_mapgen(pos)
8 | if mapgen_distance then
9 | return false, "Error: mapgen was active "..math.floor(mapgen_distance)
10 | .. " / 200 nodes away, please try again later for your own safety!"
11 | end
12 |
13 | local meta = minetest.get_meta(pos)
14 |
15 | if show_marker and has_vizlib and os.time() < meta:get_int("simulation_expiry") then
16 | return false, "Error: simulation is still active! please wait before simulating again"
17 | end
18 |
19 | local radius = jumpdrive.get_radius(pos)
20 | local distance = vector.distance(pos, targetPos)
21 |
22 | local playername = meta:get_string("owner")
23 |
24 | if player ~= nil then
25 | playername = player:get_player_name()
26 | end
27 |
28 | local radius_vector = {x=radius, y=radius, z=radius}
29 | local source_pos1 = vector.subtract(pos, radius_vector)
30 | local source_pos2 = vector.add(pos, radius_vector)
31 | local target_pos1 = vector.subtract(targetPos, radius_vector)
32 | local target_pos2 = vector.add(targetPos, radius_vector)
33 |
34 | local x_overlap = (target_pos1.x <= source_pos2.x and target_pos1.x >= source_pos1.x) or
35 | (target_pos2.x <= source_pos2.x and target_pos2.x >= source_pos1.x)
36 | local y_overlap = (target_pos1.y <= source_pos2.y and target_pos1.y >= source_pos1.y) or
37 | (target_pos2.y <= source_pos2.y and target_pos2.y >= source_pos1.y)
38 | local z_overlap = (target_pos1.z <= source_pos2.z and target_pos1.z >= source_pos1.z) or
39 | (target_pos2.z <= source_pos2.z and target_pos2.z >= source_pos1.z)
40 |
41 | if x_overlap and y_overlap and z_overlap then
42 | return false, "Error: jump into itself! extend your jump target"
43 | end
44 |
45 | -- load chunk
46 | minetest.get_voxel_manip():read_from_map(target_pos1, target_pos2)
47 |
48 | if show_marker and has_vizlib then
49 | vizlib.draw_cube(targetPos, radius + 0.5, { color = "#ff0000" })
50 | vizlib.draw_cube(pos, radius + 0.5, { color = "#00ff00" })
51 | local shape = vizlib.draw_point(targetPos, { color = "#0000ff" })
52 | meta:set_int("simulation_expiry", shape.expiry)
53 | end
54 |
55 | local msg = ""
56 | local success = true
57 |
58 | local blacklisted_pos_list = minetest.find_nodes_in_area(source_pos1, source_pos2, jumpdrive.blacklist)
59 | local _, nodepos = next(blacklisted_pos_list)
60 | if nodepos then
61 | return false, "Can't jump node @ " .. minetest.pos_to_string(nodepos)
62 | end
63 |
64 | if minetest.find_node_near(targetPos, radius, "vacuum:vacuum", true) then
65 | msg = msg .. "\nWarning: Jump-target is in vacuum!"
66 | end
67 |
68 | -- -- found to be useless/indescriptive and is superseded by "Jump-target is uncharted"
69 | -- if minetest.find_node_near(targetPos, radius, "ignore", true) then
70 | -- return false, "Warning: Jump-target is in uncharted area"
71 | -- end
72 |
73 | if jumpdrive.is_area_protected(source_pos1, source_pos2, playername) then
74 | return false, "Jump-source is protected!"
75 | end
76 |
77 | if jumpdrive.is_area_protected(target_pos1, target_pos2, playername) then
78 | return false, "Jump-target is protected!"
79 | end
80 |
81 | local is_empty, empty_msg = jumpdrive.is_area_empty(target_pos1, target_pos2)
82 |
83 | if not is_empty then
84 | if jumpdrive.config.emerge_uncharted and empty_msg == "uncharted" then
85 | local callback = function(_, _, calls_remaining, _)
86 | if calls_remaining == 0 then
87 | core.chat_send_player(playername, "Charting complete!")
88 | end
89 | end
90 | core.emerge_area(target_pos1, target_pos2, callback)
91 | end
92 | msg = msg .. "\nJump-target is " .. empty_msg
93 | success = false
94 | end
95 |
96 | -- check preflight conditions
97 | local preflight_result = jumpdrive.preflight_check(pos, targetPos, radius, playername)
98 |
99 | if not preflight_result.success then
100 | -- check failed in customization
101 | msg = msg .. "\nPreflight check failed!"
102 | if preflight_result.message then
103 | msg = preflight_result.message
104 | end
105 | success = false
106 | end
107 |
108 | local power_req = jumpdrive.calculate_power(radius, distance, pos, targetPos)
109 | local powerstorage = meta:get_int("powerstorage")
110 |
111 | if powerstorage < power_req then
112 | -- not enough power
113 | msg = msg .. "\nNot enough power: required=" .. math.floor(power_req) .. ", actual: " .. powerstorage .. " EU"
114 | success = false
115 | end
116 |
117 | return success, msg
118 | end
119 |
120 |
121 |
122 | -- execute jump
123 | jumpdrive.execute_jump = function(pos, player)
124 |
125 | local meta = minetest.get_meta(pos)
126 |
127 | local radius = jumpdrive.get_radius(pos)
128 | local targetPos = jumpdrive.get_meta_pos(pos)
129 |
130 | local distance = vector.distance(pos, targetPos)
131 | local power_req = jumpdrive.calculate_power(radius, distance, pos, targetPos)
132 |
133 | local radius_vector = {x=radius, y=radius, z=radius}
134 | local source_pos1 = vector.subtract(pos, radius_vector)
135 | local source_pos2 = vector.add(pos, radius_vector)
136 | local target_pos1 = vector.subtract(targetPos, radius_vector)
137 | local target_pos2 = vector.add(targetPos, radius_vector)
138 |
139 | local success, msg = jumpdrive.simulate_jump(pos, player, false)
140 | if not success then
141 | return false, msg
142 | end
143 |
144 | -- consume power from storage
145 | local powerstorage = meta:get_int("powerstorage")
146 | meta:set_int("powerstorage", powerstorage - power_req)
147 |
148 | local t0 = minetest.get_us_time()
149 |
150 | minetest.sound_play("jumpdrive_engine", {
151 | pos = pos,
152 | max_hear_distance = 50,
153 | gain = 0.7,
154 | })
155 |
156 | -- actual move
157 | jumpdrive.move(source_pos1, source_pos2, target_pos1, target_pos2)
158 |
159 | local t1 = minetest.get_us_time()
160 | local time_micros = t1 - t0
161 |
162 | minetest.log("action", "[jumpdrive] jump took " .. time_micros .. " us")
163 |
164 | -- show animation in source
165 | minetest.add_particlespawner({
166 | amount = 200,
167 | time = 2,
168 | minpos = source_pos1,
169 | maxpos = source_pos2,
170 | minvel = {x = -2, y = -2, z = -2},
171 | maxvel = {x = 2, y = 2, z = 2},
172 | minacc = {x = -3, y = -3, z = -3},
173 | maxacc = {x = 3, y = 3, z = 3},
174 | minexptime = 0.1,
175 | maxexptime = 5,
176 | minsize = 1,
177 | maxsize = 1,
178 | texture = "spark.png",
179 | glow = 5,
180 | })
181 |
182 |
183 | -- show animation in target
184 | minetest.add_particlespawner({
185 | amount = 200,
186 | time = 2,
187 | minpos = target_pos1,
188 | maxpos = target_pos2,
189 | minvel = {x = -2, y = -2, z = -2},
190 | maxvel = {x = 2, y = 2, z = 2},
191 | minacc = {x = -3, y = -3, z = -3},
192 | maxacc = {x = 3, y = 3, z = 3},
193 | minexptime = 0.1,
194 | maxexptime = 5,
195 | minsize = 1,
196 | maxsize = 1,
197 | texture = "spark.png",
198 | glow = 5,
199 | })
200 |
201 | return true, time_micros
202 | end
203 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2018 Thomas Rudin / Buckaroo Banzay
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 3 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 |
--------------------------------------------------------------------------------
/mapgen.lua:
--------------------------------------------------------------------------------
1 | local metric_mapgen_events_count
2 |
3 |
4 | if minetest.get_modpath("monitoring") then
5 | metric_mapgen_events_count = monitoring.gauge(
6 | "jumpdrive_mapgen_events_count",
7 | "number of events in the mapgen cache"
8 | )
9 | end
10 |
11 | local events = {} -- list of {minp, maxp, time}
12 | jumpdrive.mapgen = {}
13 |
14 | jumpdrive.mapgen.reset = function()
15 | events = {}
16 | end
17 |
18 | -- update last mapgen event time
19 | minetest.register_on_generated(function(minp, maxp)
20 | table.insert(events, {
21 | minp = minp,
22 | maxp = maxp,
23 | time = minetest.get_us_time()
24 | })
25 | end)
26 |
27 |
28 | -- cleanup
29 | local timer = 0
30 | minetest.register_globalstep(function(dtime)
31 | timer = timer + dtime
32 | if timer < 5 then return end
33 | timer=0
34 |
35 | local time = minetest.get_us_time()
36 | local delay_seconds = 10
37 |
38 | local copied_events = events
39 | events = {}
40 |
41 | local count = 0
42 | for _, event in ipairs(copied_events) do
43 | if event.time > (time - (delay_seconds * 1000000)) then
44 | -- still recent
45 | table.insert(events, event)
46 | count = count + 1
47 | end
48 | end
49 |
50 | if metric_mapgen_events_count then
51 | metric_mapgen_events_count.set(count)
52 | end
53 |
54 | end)
55 |
56 |
57 | -- any number = mapgen recently active in that area
58 | jumpdrive.check_mapgen = function(pos)
59 | for _, event in ipairs(events) do
60 | local mapgen_distance = vector.distance(pos, event.minp)
61 | if mapgen_distance < 200 then
62 | return mapgen_distance
63 | end
64 | end
65 |
66 | return false
67 | end
68 |
--------------------------------------------------------------------------------
/metrics.lua:
--------------------------------------------------------------------------------
1 | local metric = monitoring.counter("jumpdrive_move_calls", "number of jumpdrive.move calls")
2 | local metric_time = monitoring.counter("jumpdrive_move_time", "time usage in microseconds for jumpdrive.move calls")
3 |
4 | jumpdrive.move = metric.wrap(metric_time.wrap(jumpdrive.move))
5 |
--------------------------------------------------------------------------------
/migrate.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 | jumpdrive.migrate_engine_meta = function(pos, meta)
4 |
5 | -- previous version had no such variable in the metadata
6 | local max_store = meta:get_int("max_powerstorage")
7 | if max_store == 0 then
8 | meta:set_int("max_powerstorage", jumpdrive.config.powerstorage)
9 | end
10 |
11 | local power_requirement = meta:get_int("power_requirement")
12 | if power_requirement == 0 then
13 | meta:set_int("power_requirement", jumpdrive.config.powerrequirement)
14 | end
15 |
16 | -- start nodetimer if not started
17 | local timer = minetest.get_node_timer(pos)
18 | if not timer:is_started() then
19 | timer:start(2)
20 | end
21 |
22 | -- inventories
23 | local inv = meta:get_inventory()
24 | inv:set_size("main", 8)
25 | inv:set_size("upgrade", 4)
26 |
27 | end
28 |
--------------------------------------------------------------------------------
/mod.conf:
--------------------------------------------------------------------------------
1 | name = jumpdrive
2 | optional_depends = """
3 | mesecons,
4 | travelnet,
5 | telemosaic,
6 | elevator,
7 | vacuum,
8 | locator,
9 | areas,
10 | protector,
11 | digilines,
12 | display_api,
13 | pipeworks,
14 | monitoring,
15 | beds,
16 | ropes,
17 | sethome,
18 | default,
19 | technic,
20 | drawers,
21 | textline,
22 | player_monoids,
23 | planet_mars,
24 | vizlib,
25 | mcl_sounds,
26 | mcl_formspec,
27 | mtt
28 | """
--------------------------------------------------------------------------------
/move/move.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | -- moves the source to the target area
7 | -- no protection- or overlap checking is done here
8 | function jumpdrive.move(source_pos1, source_pos2, target_pos1, target_pos2)
9 |
10 | minetest.log("action", "[jumpdrive] initiating jump (" ..
11 | minetest.pos_to_string(source_pos1) .. "-" .. minetest.pos_to_string(source_pos2) ..
12 | ") (" .. minetest.pos_to_string(target_pos1) .. "-" .. minetest.pos_to_string(target_pos2) .. ")")
13 |
14 | -- step 1: copy via voxel manip
15 | -- https://dev.minetest.net/VoxelManip#Examples
16 |
17 | -- delta between source and target
18 | local delta_vector = vector.subtract(target_pos1, source_pos1)
19 |
20 | -- center of source
21 | local source_center = vector.add(source_pos1, vector.divide(vector.subtract(source_pos2, source_pos1), 2))
22 | minetest.log("action", "[jumpdrive] source-center: " .. minetest.pos_to_string(source_center))
23 |
24 | local t0 = minetest.get_us_time()
25 |
26 | -- load areas (just a precaution)
27 | if minetest.load_area then
28 | minetest.load_area(source_pos1, source_pos2)
29 | minetest.load_area(target_pos1, target_pos2)
30 | end
31 |
32 | -- move mapdata (nodeids, param1, param2)
33 | local movenode_list = jumpdrive.move_mapdata(source_pos1, source_pos2, target_pos1, target_pos2)
34 |
35 | local t1 = minetest.get_us_time()
36 | minetest.log("action", "[jumpdrive] step I took " .. (t1 - t0) .. " us")
37 |
38 | -- step 2: check meta/timers and copy if needed
39 | t0 = minetest.get_us_time()
40 | jumpdrive.move_metadata(source_pos1, source_pos2, delta_vector)
41 | jumpdrive.move_nodetimers(source_pos1, source_pos2, delta_vector)
42 |
43 | -- move "on_movenode" aware nodes
44 | for _, entry in ipairs(movenode_list) do
45 | entry.nodedef.on_movenode(entry.from_pos, entry.to_pos, {
46 | edge = entry.edge
47 | })
48 | end
49 |
50 | -- print stats
51 | t1 = minetest.get_us_time()
52 | minetest.log("action", "[jumpdrive] step II took " .. (t1 - t0) .. " us")
53 |
54 |
55 | -- step 4: move objects
56 | t0 = minetest.get_us_time()
57 | jumpdrive.move_objects(source_center, source_pos1, source_pos2, delta_vector)
58 |
59 | -- move players
60 | jumpdrive.move_players(source_pos1, source_pos2, delta_vector)
61 |
62 | t1 = minetest.get_us_time()
63 | minetest.log("action", "[jumpdrive] step IV took " .. (t1 - t0) .. " us")
64 |
65 |
66 | -- step 5: clear source area with voxel manip
67 | t0 = minetest.get_us_time()
68 | jumpdrive.clear_area(source_pos1, source_pos2)
69 |
70 | t1 = minetest.get_us_time()
71 | minetest.log("action", "[jumpdrive] step V took " .. (t1 - t0) .. " us")
72 |
73 | -- call after_jump callbacks
74 | jumpdrive.fire_after_jump({
75 | pos1 = source_pos1,
76 | pos2 = source_pos2
77 | }, {
78 | pos1 = target_pos1,
79 | pos2 = target_pos2
80 | })
81 |
82 | end
83 |
--------------------------------------------------------------------------------
/move/move_mapdata.lua:
--------------------------------------------------------------------------------
1 | local c_air = minetest.get_content_id("air")
2 |
3 | -- map of replaced content id's on jump
4 | -- TODO: expose as api function
5 | -- =
6 | local mapped_content_ids = {}
7 |
8 | if minetest.get_modpath("vacuum") then
9 | -- don't jump vacuum
10 | mapped_content_ids[minetest.get_content_id("vacuum:vacuum")] = c_air
11 | end
12 |
13 | if minetest.get_modpath("planet_mars") then
14 | -- alias planet_mars:airlight to air
15 | mapped_content_ids[minetest.get_content_id("planet_mars:airlight")] = c_air
16 | end
17 |
18 | -- map of "on_movenode" aware node id's
19 | -- content_id = nodedef
20 | local movenode_aware_nodeids = {}
21 |
22 | -- collect movenode aware node id's
23 | minetest.register_on_mods_loaded(function()
24 | local count = 0
25 | for nodename, nodedef in pairs(minetest.registered_nodes) do
26 | if type(nodedef.on_movenode) == "function" then
27 | count = count + 1
28 | local id = minetest.get_content_id(nodename)
29 | movenode_aware_nodeids[id] = nodedef
30 | end
31 | end
32 | minetest.log("action", "[jumpdrive] collected " .. count .. " 'on_movenode' aware nodes")
33 | end)
34 |
35 | function jumpdrive.move_mapdata(source_pos1, source_pos2, target_pos1, target_pos2)
36 |
37 | -- delta between source and target
38 | local delta_vector = vector.subtract(target_pos1, source_pos1)
39 |
40 | -- read source
41 | local manip = minetest.get_voxel_manip()
42 | local e1, e2 = manip:read_from_map(source_pos1, source_pos2)
43 | local source_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
44 | local source_data = manip:get_data()
45 | local source_param1 = manip:get_light_data()
46 | local source_param2 = manip:get_param2_data()
47 |
48 | minetest.log("action", "[jumpdrive] read source-data")
49 |
50 | -- write target
51 | manip = minetest.get_voxel_manip()
52 | e1, e2 = manip:read_from_map(target_pos1, target_pos2)
53 | local target_area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
54 | local target_data = manip:get_data()
55 | local target_param1 = manip:get_light_data()
56 | local target_param2 = manip:get_param2_data()
57 |
58 | -- list of { from_pos, to_pos, }
59 | local movenode_list = {}
60 |
61 | minetest.log("action", "[jumpdrive] read target-data");
62 |
63 | for z=source_pos1.z, source_pos2.z do
64 | for y=source_pos1.y, source_pos2.y do
65 | for x=source_pos1.x, source_pos2.x do
66 |
67 | local from_pos = { x=x, y=y, z=z }
68 | local to_pos = vector.add(from_pos, delta_vector)
69 |
70 | local source_index = source_area:indexp(from_pos)
71 | local target_index = target_area:indexp(to_pos)
72 |
73 | -- copy block id
74 | local id = source_data[source_index]
75 |
76 | if mapped_content_ids[id] then
77 | -- replace original content id
78 | id = mapped_content_ids[id]
79 | end
80 |
81 | target_data[target_index] = id
82 |
83 | if movenode_aware_nodeids[id] then
84 |
85 | -- check if we are on an edge
86 | local edge = { x=0, y=0, z=0 }
87 |
88 | -- negative edge
89 | if source_pos1.x == x then edge.x = -1 end
90 | if source_pos1.y == y then edge.y = -1 end
91 | if source_pos1.z == z then edge.z = -1 end
92 | -- positive edge
93 | if source_pos2.z == x then edge.x = 1 end
94 | if source_pos2.y == y then edge.y = 1 end
95 | if source_pos2.z == z then edge.z = 1 end
96 |
97 | table.insert(movenode_list, {
98 | from_pos = from_pos,
99 | to_pos = to_pos,
100 | edge = edge,
101 | nodedef = movenode_aware_nodeids[id]
102 | })
103 | end
104 |
105 | -- copy params
106 | target_param1[target_index] = source_param1[source_index]
107 | target_param2[target_index] = source_param2[source_index]
108 | end
109 | end
110 | end
111 |
112 |
113 | manip:set_data(target_data)
114 | manip:set_light_data(target_param1)
115 | manip:set_param2_data(target_param2)
116 | manip:write_to_map()
117 | manip:update_map()
118 |
119 | return movenode_list
120 | end
121 |
--------------------------------------------------------------------------------
/move/move_metadata.lua:
--------------------------------------------------------------------------------
1 |
2 | -- invoked from move.lua
3 | jumpdrive.move_metadata = function(source_pos1, source_pos2, delta_vector)
4 |
5 |
6 | local target_pos1 = vector.add(source_pos1, delta_vector)
7 | local target_pos2 = vector.add(source_pos2, delta_vector)
8 |
9 | -- check if there is some "stale" metadata in the target area
10 | local target_meta_pos_list = minetest.find_nodes_with_meta(target_pos1, target_pos2)
11 | for _,target_pos in pairs(target_meta_pos_list) do
12 | minetest.log("warning", "[jumpdrive] clearing spurious meta in " .. minetest.pos_to_string(target_pos))
13 | local target_meta = minetest.get_meta(target_pos)
14 | target_meta:from_table(nil)
15 | end
16 |
17 | local meta_pos_list = minetest.find_nodes_with_meta(source_pos1, source_pos2)
18 | for _,source_pos in pairs(meta_pos_list) do
19 | local target_pos = vector.add(source_pos, delta_vector)
20 |
21 | local source_meta = minetest.get_meta(source_pos)
22 | local source_table = source_meta:to_table()
23 |
24 | -- copy metadata to target
25 | minetest.get_meta(target_pos):from_table(source_table)
26 |
27 | local node = minetest.get_node(source_pos)
28 |
29 | jumpdrive.node_compat(node.name, source_pos, target_pos, source_pos1, source_pos2, delta_vector)
30 |
31 | -- clear metadata in source
32 | source_meta:from_table(nil)
33 | end
34 |
35 | jumpdrive.commit_node_compat()
36 |
37 | end
38 |
--------------------------------------------------------------------------------
/move/move_nodetimers.lua:
--------------------------------------------------------------------------------
1 |
2 | -- collect nodes with on_timer attributes
3 | local node_names_with_timer = {}
4 | minetest.after(4, function()
5 | for _,node in pairs(minetest.registered_nodes) do
6 | if node.on_timer then
7 | table.insert(node_names_with_timer, node.name)
8 | end
9 | end
10 | minetest.log("action", "[jumpdrive] collected " .. #node_names_with_timer .. " items with node timers")
11 | end)
12 |
13 |
14 | -- invoked from move.lua
15 | jumpdrive.move_nodetimers = function(source_pos1, source_pos2, delta_vector)
16 |
17 | if #node_names_with_timer == 0 then
18 | -- no node timer-nodes or not collected yet
19 | return
20 | end
21 |
22 | local list = minetest.find_nodes_in_area(source_pos1, source_pos2, node_names_with_timer)
23 |
24 | for _,source_pos in pairs(list) do
25 | local target_pos = vector.add(source_pos, delta_vector)
26 |
27 | local source_timer = minetest.get_node_timer(source_pos)
28 | local target_timer = minetest.get_node_timer(target_pos)
29 |
30 | if source_timer:is_started() then
31 | -- set target timer
32 | target_timer:set(
33 | source_timer:get_timeout(),
34 | source_timer:get_elapsed()
35 | )
36 |
37 | -- clear source timer
38 | source_timer:stop()
39 | end
40 | end
41 |
42 | end
43 |
--------------------------------------------------------------------------------
/move/move_objects.lua:
--------------------------------------------------------------------------------
1 |
2 | -- invoked from move.lua
3 | jumpdrive.move_objects = function(source_center, source_pos1, source_pos2, delta_vector)
4 |
5 | local margin = vector.new(0.5, 0.5, 0.5)
6 | local pos1 = vector.subtract(source_pos1, margin)
7 | local pos2 = vector.add(source_pos2, margin)
8 |
9 | local radius = math.ceil(vector.distance(source_center, pos2))
10 |
11 | local all_objects = minetest.get_objects_inside_radius(source_center, radius);
12 | for _,obj in ipairs(all_objects) do
13 |
14 | local objPos = obj:get_pos()
15 |
16 | local x_match = objPos.x >= pos1.x and objPos.x <= pos2.x
17 | local y_match = objPos.y >= pos1.y and objPos.y <= pos2.y
18 | local z_match = objPos.z >= pos1.z and objPos.z <= pos2.z
19 |
20 | if x_match and y_match and z_match and not obj:is_player() then
21 | minetest.log("action", "[jumpdrive] object: @ " .. minetest.pos_to_string(objPos))
22 |
23 | -- coords in range
24 | local entity = obj:get_luaentity()
25 |
26 | if not entity then
27 | minetest.log("action", "[jumpdrive] moving object")
28 | obj:set_pos( vector.add(objPos, delta_vector) )
29 |
30 | elseif entity.name:find("^mobs_animal:") then
31 | minetest.log("action", "[jumpdrive] moving animal")
32 | obj:set_pos( vector.add(objPos, delta_vector) )
33 |
34 | elseif entity.name == "__builtin:item" then
35 | minetest.log("action", "[jumpdrive] moving dropped item")
36 | obj:set_pos( vector.add(objPos, delta_vector) )
37 |
38 | else
39 | minetest.log("action", "[jumpdrive] removing entity: " .. entity.name)
40 | obj:remove()
41 |
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/move/move_players.lua:
--------------------------------------------------------------------------------
1 | local use_player_monoids = minetest.global_exists("player_monoids")
2 |
3 | function jumpdrive.move_players(source_pos1, source_pos2, delta_vector)
4 | -- move players
5 | for _,player in ipairs(minetest.get_connected_players()) do
6 | local playerPos = player:get_pos()
7 | local player_name = player:get_player_name()
8 |
9 | local xMatch = playerPos.x >= (source_pos1.x-0.5) and playerPos.x <= (source_pos2.x+0.5)
10 | local yMatch = playerPos.y >= (source_pos1.y-0.5) and playerPos.y <= (source_pos2.y+0.5)
11 | local zMatch = playerPos.z >= (source_pos1.z-0.5) and playerPos.z <= (source_pos2.z+0.5)
12 |
13 | if xMatch and yMatch and zMatch and player:is_player() then
14 | minetest.log("action", "[jumpdrive] moving player: " .. player:get_player_name())
15 |
16 | -- override gravity if "player_monoids" is available
17 | -- *should* execute before the player get moved
18 | -- to prevent falling through not yet loaded blocks
19 | if use_player_monoids then
20 | -- modify gravity
21 | player_monoids.gravity:add_change(player, 0.01, "jumpdrive:gravity")
22 |
23 | minetest.after(3.0, function()
24 | -- restore gravity
25 | local player_deferred = minetest.get_player_by_name(player_name)
26 | if player_deferred then
27 | player_monoids.gravity:del_change(player_deferred, "jumpdrive:gravity")
28 | end
29 | end)
30 | end
31 |
32 | local new_player_pos = vector.add(playerPos, delta_vector)
33 | player:set_pos( new_player_pos );
34 |
35 | -- send moved mapblock to player
36 | if player.send_mapblock and type(player.send_mapblock) == "function" then
37 | player:send_mapblock(jumpdrive.get_mapblock_from_pos(new_player_pos))
38 | end
39 | end
40 | end
41 |
42 | end
--------------------------------------------------------------------------------
/mtt.lua:
--------------------------------------------------------------------------------
1 | local pos1 = { x=-50, y=-10, z=-50 }
2 | local pos2 = { x=50, y=50, z=50 }
3 |
4 | mtt.emerge_area(pos1, pos2)
5 |
6 | mtt.register("basic move-test", function(callback)
7 | local source_pos1 = { x=0, y=0, z=0 }
8 | local source_pos2 = { x=5, y=5, z=5 }
9 | local target_pos1 = { x=10, y=10, z=10 }
10 | local target_pos2 = { x=15, y=15, z=15 }
11 |
12 | minetest.get_voxel_manip(source_pos1, source_pos1)
13 | local src_node = minetest.get_node(source_pos1)
14 |
15 | areas:add("dummy", "landscape", source_pos1, source_pos2)
16 | areas:save()
17 |
18 | assert(not minetest.is_protected(source_pos1, "dummy"))
19 | assert(minetest.is_protected(source_pos1, "dummy2"))
20 |
21 | jumpdrive.move(source_pos1, source_pos2, target_pos1, target_pos2)
22 |
23 | assert(not minetest.is_protected(source_pos1, "dummy"))
24 | assert(not minetest.is_protected(source_pos1, "dummy2"))
25 |
26 | assert(not minetest.is_protected(target_pos1, "dummy"))
27 | assert(minetest.is_protected(target_pos1, "dummy2"))
28 |
29 | minetest.get_voxel_manip(target_pos1, target_pos1)
30 | local target_node = minetest.get_node(target_pos1)
31 |
32 | if target_node.name ~= src_node.name then
33 | error("moved node name does not match")
34 | end
35 |
36 | if target_node.param2 ~= src_node.param2 then
37 | error("moved param2 does not match")
38 | end
39 |
40 | callback()
41 | end)
42 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | Minetest jumpdrive
2 | ======
3 |
4 | 
5 | 
6 |
7 |
8 | A simple [Jumpdrive](https://en.wikipedia.org/wiki/Jump_drive) for minetest
9 |
10 | Take your buildings with you on your journey
11 |
12 | * Github: [https://github.com/thomasrudin-mt/jumpdrive](https://github.com/thomasrudin-mt/jumpdrive)
13 | * Forum topic: [https://forum.minetest.net/viewtopic.php?f=9&t=20073](https://forum.minetest.net/viewtopic.php?f=9&t=20073)
14 |
15 | # Operation
16 |
17 | * Place a 'jumpdrive:engine' into the center of your creation.
18 | * Connect the engine to a technic HV network
19 | * Let the engine charge
20 | * Choose your target coordinates (should be air or ignore blocks)
21 | * Select your cube-radius
22 | * Click "show" and check the green (source) and red (target) destination markers if everything is in range
23 | * Click "jump"
24 |
25 | Example setup with technic:
26 |
27 | 
28 |
29 |
30 | # Compatibility
31 |
32 | Optional dependencies:
33 | * Mesecon interaction (execute jump on signal)
34 | * Technic rechargeable (HV)
35 | * Travelnet box (gets rewired after jump)
36 | * Elevator (on_place gets called after jump)
37 | * Locator (gets removed and added after each jump)
38 | * Pipeworks teleport tubes (with a patch to pipeworks)
39 | * Beds (thx to @tuedel)
40 | * Ropes (thx to @tuedel)
41 | * Mission-wand as coordinate bookmark (thx to @SwissalpS)
42 | * Compass as coordinate bookmark (thx to @SwissalpS)
43 | * Areas
44 | * Drawers
45 |
46 | # Fuel
47 |
48 | The engine can be connected to a technic HV network or fuelled with power items.
49 | Power items are one of the following
50 | * `default:mese_crystal_fragment`
51 | * `default:mese_crystal`
52 | * `default:mese`
53 |
54 | # Energy requirements
55 |
56 | The energy requirements formula looks like this: **10 x radius x distance**
57 |
58 | For example:
59 | * Distance: 100 blocks
60 | * Radius: 5 blocks
61 | * Required energy: 10 x 5 x 100 = 5000
62 |
63 | # Upgrades
64 |
65 | If the `technic` mod is installed the following items can be used in the upgrade slot:
66 | * `technic:red_energy_crystal` increases power storage
67 | * `technic:green_energy_crystal` increases power storage
68 | * `technic:blue_energy_crystal` increases power storage
69 | * `technic:control_logic_unit` increases power recharge rate
70 |
71 | # Protection
72 |
73 | The source and destination areas are checked for protection so you can't remove and jump into someone else's buildings.
74 |
75 |
76 | # Screenshots
77 |
78 | Interface:
79 |
80 | 
81 |
82 | Example:
83 |
84 | 
85 |
86 | # Advanced operation
87 |
88 | ## Coordinate bookmarking
89 |
90 | You can place empty books into the drive inventory and write the coordinates to them with the "Write to book" button.
91 | The "Read from bookmark" button reads the coordinates from the next valid bookmark item in the inventory. From right to left.
92 | A used bookmark item is placed in the first free slot from the left.
93 | Bookmark items are:
94 | * Written books saved by jumpdrive (or correctly by hand)
95 | * Mission position wands
96 | * Compasses
97 |
98 | ## Diglines
99 |
100 | * See: [Digilines](doc/digiline.md)
101 |
102 | # Settings
103 |
104 | Settings in minetest.conf:
105 |
106 | * **jumpdrive.max_radius** max radius of the jumpdrive (default: *15*)
107 | * **jumpdrive.max_area_radius** max radius of the area jumpdrive (default: *25*)
108 | * **jumpdrive.powerstorage** power storage of the drive (default: *1000000*)
109 | * **jumpdrive.power_requirement** power requirement for charging (default: *2500*)
110 |
111 | # Lua api
112 |
113 | ## Preflight check
114 |
115 | The preflight check can be overriden to execute additional checks:
116 |
117 | ```lua
118 | jumpdrive.preflight_check = function(source, destination, radius, player)
119 | -- check for height limit, only space travel allowed
120 | if destination.y < 1000 then
121 | return { success=false, message="Atmospheric travel not allowed!" }
122 | end
123 |
124 | -- everything ok
125 | return { success=true }
126 | end
127 | ```
128 |
129 | ## Fuel calc
130 |
131 | The default fuel calc can be overwritten by a depending mod:
132 |
133 | ```lua
134 | -- calculates the power requirements for a jump
135 | jumpdrive.calculate_power = function(radius, distance, sourcePos, targetPos)
136 | return 10 * distance * radius
137 | end
138 | ```
139 |
140 | ## Movenode compatibility
141 |
142 | Nodes can be made aware of a changing position if they implement a `on_movenode` function
143 | on the node-definition:
144 |
145 | ```lua
146 | -- example with an override
147 | minetest.override_item("travelnet:travelnet", {
148 | on_movenode = function(from_pos, to_pos, additional_info)
149 | -- additional_info = { edge = { x=0, y=0, z=0 } }
150 | -- magic!
151 | end
152 | })
153 | ```
154 |
155 | * `additional_info.edge` is the vector to the nearest edge if any
156 |
157 |
158 | ## Hooks
159 |
160 | ```lua
161 | -- register a callback that is called upon jump completion
162 | -- can also be used if the `on_movenode` above needs a kind of "commit" to write the changed state to files
163 | jumpdrive.register_after_jump(function(from_area, to_area)
164 | -- from_area/to_area = { pos1, pos2 }
165 | end)
166 | ```
167 |
168 |
169 | # Sources
170 |
171 | * jumprive_engine.ogg: https://freesound.org/people/kaboose102/sounds/340257/
172 |
173 | # Contributors
174 |
175 | * @tuedel
176 | * @SwissalpS
177 | * @Panquesito7
178 | * @OgelGames
179 | * @S-S-X
180 | * Jeremy#2233
181 | * Purple#2916
182 |
183 | # License
184 | * Code: `MIT`
185 | * Textures `CC BY-SA 4.0`
186 |
187 | # Attributions
188 | * `textures/jumpdrive.png`/`textures/jumpdrive_backbone.png`/`textures/jumpdrive_fleet_controller.png`/`textures/jumpdrive_warpdevice.png`
189 | * Jeremy#2233 / Purple#2916
190 |
--------------------------------------------------------------------------------
/screenshots/screenshot_20180507_200203.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/screenshots/screenshot_20180507_200203.png
--------------------------------------------------------------------------------
/screenshots/screenshot_20180507_200309.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/screenshots/screenshot_20180507_200309.png
--------------------------------------------------------------------------------
/screenshots/screenshot_20220305_161502.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/screenshots/screenshot_20220305_161502.png
--------------------------------------------------------------------------------
/settingtypes.txt:
--------------------------------------------------------------------------------
1 | # Allow jumpdrives to generate ungenerated areas
2 | jumpdrive.allow_emerge (Chart uncharted jump targets) bool false
3 |
--------------------------------------------------------------------------------
/sounds/jumpdrive_engine.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/sounds/jumpdrive_engine.ogg
--------------------------------------------------------------------------------
/technic_run.lua:
--------------------------------------------------------------------------------
1 |
2 | jumpdrive.technic_run = function(pos)
3 | local meta = minetest.get_meta(pos)
4 | jumpdrive.migrate_engine_meta(pos, meta)
5 |
6 | local eu_input = meta:get_int("HV_EU_input")
7 | local store = meta:get_int("powerstorage")
8 | local power_requirement = meta:get_int("power_requirement")
9 | local max_store = meta:get_int("max_powerstorage")
10 |
11 | if store < max_store then
12 | -- charge
13 | meta:set_int("HV_EU_demand", power_requirement)
14 | store = store + eu_input
15 | meta:set_int("powerstorage", math.min(store, max_store))
16 | else
17 | -- charged
18 | meta:set_int("HV_EU_demand", 0)
19 | end
20 |
21 | jumpdrive.update_infotext(meta, pos)
22 | end
23 |
--------------------------------------------------------------------------------
/testship.we:
--------------------------------------------------------------------------------
1 | 5:return {{["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 1, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 1, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 2, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 2, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 3, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 3, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 4, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 4, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 5, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 5, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 6, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 6, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 7, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 7, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 8, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 8, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 9, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 9, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 0, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 1, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 2, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 1, ["param1"] = 78, ["z"] = 2, ["name"] = "technic:hv_cable"}, {["x"] = 3, ["meta"] = {["fields"] = {["infotext"] = "Arrayed Solar HV Generator Active (4900 EU)", ["HV_EU_supply"] = "4900"}, ["inventory"] = {}}, ["y"] = 2, ["param1"] = 94, ["z"] = 2, ["name"] = "technic:solar_array_hv"}, {["x"] = 3, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 3, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 1, ["param1"] = 94, ["z"] = 2, ["name"] = "technic:hv_cable"}, {["x"] = 4, ["meta"] = {["fields"] = {["infotext"] = "Arrayed Solar HV Generator Active (4900 EU)", ["HV_EU_supply"] = "4900"}, ["inventory"] = {}}, ["y"] = 2, ["param1"] = 110, ["z"] = 2, ["name"] = "technic:solar_array_hv"}, {["x"] = 4, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 4, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 1, ["param1"] = 109, ["z"] = 2, ["name"] = "technic:hv_cable"}, {["x"] = 5, ["y"] = 1, ["param1"] = 126, ["z"] = 3, ["name"] = "technic:hv_cable"}, {["x"] = 5, ["y"] = 1, ["param1"] = 142, ["z"] = 4, ["name"] = "technic:hv_cable"}, {["x"] = 5, ["y"] = 1, ["param1"] = 158, ["z"] = 5, ["name"] = "technic:hv_cable"}, {["x"] = 5, ["meta"] = {["fields"] = {["infotext"] = "Switching Station. Supply: 19.6 kEU Demand: 2500 EU", ["formspec"] = "field[channel;Channel;${channel}]"}, ["inventory"] = {}}, ["y"] = 2, ["z"] = 2, ["name"] = "technic:switching_station"}, {["x"] = 5, ["meta"] = {["fields"] = {["HV_EU_input"] = "8550", ["HV_EU_demand"] = "100000", ["infotext"] = "HV Battery Box: 680.3 kEU / 1000 kEU", ["formspec"] = "size[8,9]image[1,1;1,2;technic_power_meter_bg.png]list[context;src;3,1;1,1;]image[4,1;1,1;technic_battery_reload.png]list[context;dst;5,1;1,1;]label[0,0;HV Battery Box]label[3,0;Charge]label[5,0;Discharge]label[1,3;Power level]list[current_player;main;0,5;8,4;]listring[context;dst]listring[current_player;main]listring[context;src]listring[current_player;main]list[context;upgrade1;3.5,3;1,1;]list[context;upgrade2;4.5,3;1,1;]label[3.5,4;Upgrade Slots]listring[context;upgrade1]listring[current_player;main]listring[context;upgrade2]listring[current_player;main]image[1,1;1,2;technic_power_meter_bg.png^[lowpart:0:technic_power_meter_fg.png]", ["internal_EU_charge"] = "680298", ["internal_EU_charge_max"] = "1000000", ["last_side_shown"] = "6", ["HV_EU_supply"] = "400000"}, ["inventory"] = {["upgrade2"] = {""}, ["src"] = {""}, ["upgrade1"] = {""}, ["dst"] = {""}}}, ["param2"] = 3, ["y"] = 2, ["z"] = 3, ["name"] = "technic:hv_battery_box6"}, {["x"] = 5, ["meta"] = {["fields"] = {["HV_EU_input"] = "8550", ["HV_EU_demand"] = "100000", ["infotext"] = "HV Battery Box: 671.7 kEU / 1000 kEU", ["formspec"] = "size[8,9]image[1,1;1,2;technic_power_meter_bg.png]list[context;src;3,1;1,1;]image[4,1;1,1;technic_battery_reload.png]list[context;dst;5,1;1,1;]label[0,0;HV Battery Box]label[3,0;Charge]label[5,0;Discharge]label[1,3;Power level]list[current_player;main;0,5;8,4;]listring[context;dst]listring[current_player;main]listring[context;src]listring[current_player;main]list[context;upgrade1;3.5,3;1,1;]list[context;upgrade2;4.5,3;1,1;]label[3.5,4;Upgrade Slots]listring[context;upgrade1]listring[current_player;main]listring[context;upgrade2]listring[current_player;main]image[1,1;1,2;technic_power_meter_bg.png^[lowpart:0:technic_power_meter_fg.png]", ["internal_EU_charge"] = "680298", ["internal_EU_charge_max"] = "1000000", ["last_side_shown"] = "6", ["HV_EU_supply"] = "400000"}, ["inventory"] = {["upgrade2"] = {""}, ["src"] = {""}, ["upgrade1"] = {""}, ["dst"] = {""}}}, ["param2"] = 3, ["y"] = 2, ["z"] = 4, ["name"] = "technic:hv_battery_box6"}, {["x"] = 5, ["y"] = 2, ["param1"] = 174, ["z"] = 5, ["name"] = "technic:hv_cable"}, {["x"] = 5, ["y"] = 3, ["param1"] = 190, ["z"] = 5, ["name"] = "technic:hv_cable"}, {["x"] = 5, ["y"] = 4, ["param1"] = 206, ["z"] = 5, ["name"] = "technic:hv_cable"}, {["x"] = 5, ["meta"] = {["fields"] = {["power_requirement"] = "2500", ["HV_EU_demand"] = "2500", ["formspec"] = "size[8,10.55;]field[0.3,0.5;2,1;x;X;-148]field[2.3,0.5;2,1;y;Y;38]field[4.3,0.5;2,1;z;Z;275]field[6.3,0.5;2,1;radius;Radius;5]button_exit[0,1;2,1;jump;Jump]button_exit[2,1;2,1;show;Show]button_exit[4,1;2,1;save;Save]button[6,1;2,1;reset;Reset]button[0,2;4,1;write_book;Write to book]button[4,2;4,1;read_book;Read from bookmark]list[context;main;0,3.25;8,1;]list[current_player;main;0,5.75;8,4;]field[4.3,10.27;3.2,1;digiline_channel;Digiline channel;]button_exit[7,9.95;1,1;set_digiline_channel;Set]listring[context;main]listring[current_player;main]label[3,4.7;Upgrades]list[context;upgrade;4,4.5;4,1;]", ["y"] = "38", ["x"] = "-148", ["owner"] = "singleplayer", ["channel"] = "jumpdrive", ["HV_EU_input"] = "2500", ["z"] = "275", ["infotext"] = "Power: 2500/2500 Store: 202500/1000000", ["max_powerstorage"] = "1000000", ["radius"] = "5", ["powerstorage"] = "202500"}, ["inventory"] = {["main"] = {"", "", "", "", "", "", "", ""}, ["upgrade"] = {"", "", "", ""}}}, ["y"] = 5, ["z"] = 5, ["name"] = "jumpdrive:engine"}, {["x"] = 5, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 5, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 1, ["param1"] = 94, ["z"] = 2, ["name"] = "technic:hv_cable"}, {["x"] = 6, ["meta"] = {["fields"] = {["infotext"] = "Arrayed Solar HV Generator Active (4900 EU)", ["HV_EU_supply"] = "4900"}, ["inventory"] = {}}, ["y"] = 2, ["param1"] = 110, ["z"] = 2, ["name"] = "technic:solar_array_hv"}, {["x"] = 6, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 6, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 1, ["param1"] = 78, ["z"] = 2, ["name"] = "technic:hv_cable"}, {["x"] = 7, ["meta"] = {["fields"] = {["infotext"] = "Arrayed Solar HV Generator Active (4900 EU)", ["HV_EU_supply"] = "4900"}, ["inventory"] = {}}, ["y"] = 2, ["param1"] = 94, ["z"] = 2, ["name"] = "technic:solar_array_hv"}, {["x"] = 7, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 7, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 8, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 9, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 0, ["param1"] = 15, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 1, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 1, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 2, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 2, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 3, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 3, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 4, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 4, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 5, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 5, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 6, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 6, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 7, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 7, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 8, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 8, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 9, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 9, ["z"] = 10, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 0, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 1, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 2, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 3, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 4, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 5, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 6, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 7, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 8, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 9, ["name"] = "default:stone"}, {["x"] = 10, ["y"] = 10, ["z"] = 10, ["name"] = "default:stone"}}
--------------------------------------------------------------------------------
/textures/jumpdrive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive.png
--------------------------------------------------------------------------------
/textures/jumpdrive_air.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_air.png
--------------------------------------------------------------------------------
/textures/jumpdrive_area.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_area.png
--------------------------------------------------------------------------------
/textures/jumpdrive_backbone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_backbone.png
--------------------------------------------------------------------------------
/textures/jumpdrive_blue_mese_crystal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_blue_mese_crystal.png
--------------------------------------------------------------------------------
/textures/jumpdrive_fleet_controller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_fleet_controller.png
--------------------------------------------------------------------------------
/textures/jumpdrive_raw_blue_mese_crystal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_raw_blue_mese_crystal.png
--------------------------------------------------------------------------------
/textures/jumpdrive_remote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_remote.png
--------------------------------------------------------------------------------
/textures/jumpdrive_warpdevice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/jumpdrive_warpdevice.png
--------------------------------------------------------------------------------
/textures/marker_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/marker_blue.png
--------------------------------------------------------------------------------
/textures/marker_green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/marker_green.png
--------------------------------------------------------------------------------
/textures/marker_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/marker_red.png
--------------------------------------------------------------------------------
/textures/spark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mt-mods/jumpdrive/b65f0ccdb552a470ec18b3d8b4779a7daaa69069/textures/spark.png
--------------------------------------------------------------------------------
/upgrade.lua:
--------------------------------------------------------------------------------
1 |
2 | jumpdrive.upgrade = {}
3 |
4 | local upgrades = {}
5 |
6 | jumpdrive.upgrade.register = function(item_name, def)
7 | upgrades[item_name] = def
8 | end
9 |
10 | jumpdrive.upgrade.calculate = function(pos)
11 | local meta = minetest.get_meta(pos)
12 | local inv = meta:get_inventory()
13 | local size = inv:get_size("upgrade")
14 |
15 | -- reset values
16 | meta:set_int("power_requirement", jumpdrive.config.powerrequirement)
17 | meta:set_int("max_powerstorage", jumpdrive.config.powerstorage)
18 |
19 | for i=1,size do
20 | local stack = inv:get_stack("upgrade", i)
21 | if not stack:is_empty() then
22 | local upgrade_def = upgrades[stack:get_name()]
23 | if upgrade_def then
24 | upgrade_def(meta)
25 | end
26 | end
27 | end
28 |
29 | end
30 |
31 | if minetest.get_modpath("technic") then
32 | jumpdrive.upgrade.register("technic:red_energy_crystal", function(meta)
33 | meta:set_int("max_powerstorage", meta:get_int("max_powerstorage") + jumpdrive.config.powerstorage*0.1)
34 | end)
35 |
36 | jumpdrive.upgrade.register("technic:green_energy_crystal", function(meta)
37 | meta:set_int("max_powerstorage", meta:get_int("max_powerstorage") + jumpdrive.config.powerstorage*0.2)
38 | end)
39 |
40 | jumpdrive.upgrade.register("technic:blue_energy_crystal", function(meta)
41 | meta:set_int("max_powerstorage", meta:get_int("max_powerstorage") + jumpdrive.config.powerstorage*0.5)
42 | end)
43 |
44 | jumpdrive.upgrade.register("technic:control_logic_unit", function(meta)
45 | meta:set_int("power_requirement", meta:get_int("power_requirement") + jumpdrive.config.powerrequirement)
46 | end)
47 | end
48 |
--------------------------------------------------------------------------------
/warp_device.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 | minetest.register_node("jumpdrive:warp_device", {
4 | description = "Warp Device",
5 |
6 | tiles = {"jumpdrive_warpdevice.png"},
7 | groups = {cracky=5,oddly_breakable_by_hand=1,handy=1,pickaxey=1},
8 | _mcl_blast_resistance = 2,
9 | _mcl_hardness = 0.9,
10 | sounds = jumpdrive.sounds.node_sound_glass_defaults(),
11 | is_ground_content = false,
12 | light_source = 4
13 | })
14 |
--------------------------------------------------------------------------------