390 lines
10 KiB
Lua
390 lines
10 KiB
Lua
|
--[[
|
||
|
|
||
|
Hyperloop Mod
|
||
|
=============
|
||
|
|
||
|
Copyright (C) 2017 Joachim Stolberg
|
||
|
|
||
|
LGPLv2.1+
|
||
|
See LICENSE.txt for more information
|
||
|
|
||
|
History:
|
||
|
see init.lua
|
||
|
|
||
|
Migrate from v1 to v2
|
||
|
|
||
|
]]--
|
||
|
|
||
|
-- for lazy programmers
|
||
|
local SP = minetest.pos_to_string
|
||
|
local P = minetest.string_to_pos
|
||
|
local M = minetest.get_meta
|
||
|
|
||
|
-- Load support for intllib.
|
||
|
local S = hyperloop.S
|
||
|
local NS = hyperloop.NS
|
||
|
|
||
|
local Tube = hyperloop.Tube
|
||
|
local Shaft = hyperloop.Shaft
|
||
|
|
||
|
local Elevators = hyperloop.Elevators
|
||
|
local Stations = hyperloop.Stations
|
||
|
|
||
|
local tLegacyNodeNames = {}
|
||
|
|
||
|
local JunctionsToBePlacedAfter = {}
|
||
|
|
||
|
local function get_tube_data(pos, dir1, dir2, num_tubes)
|
||
|
local param2, tube_type = tubelib2.encode_param2(dir1, dir2, num_tubes)
|
||
|
return pos, param2, tube_type, num_tubes
|
||
|
end
|
||
|
|
||
|
-- Check if node has a connection on the given dir
|
||
|
local function connected(self, pos, dir)
|
||
|
local _,node = self:get_node(pos, dir)
|
||
|
return self.primary_node_names[node.name]
|
||
|
or self.secondary_node_names[node.name]
|
||
|
end
|
||
|
|
||
|
-- Determine dirs via surrounding nodes
|
||
|
local function determine_dir1_dir2_and_num_conn(self, pos)
|
||
|
local dirs = {}
|
||
|
for dir = 1, 6 do
|
||
|
if connected(self, pos, dir) then
|
||
|
dirs[#dirs+1] = dir
|
||
|
end
|
||
|
end
|
||
|
if #dirs == 1 then
|
||
|
return dirs[1], nil, 1
|
||
|
elseif #dirs == 2 then
|
||
|
return dirs[1], dirs[2], 2
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- convert legacy tubes to current tubes
|
||
|
for idx = 0,2 do
|
||
|
minetest.register_node("hyperloop:tube"..idx, {
|
||
|
description = S("Hyperloop Legacy Tube"),
|
||
|
tiles = {
|
||
|
-- up, down, right, left, back, front
|
||
|
"hyperloop_tube_locked.png^[transformR90]",
|
||
|
"hyperloop_tube_locked.png^[transformR90]",
|
||
|
'hyperloop_tube_closed.png',
|
||
|
'hyperloop_tube_closed.png',
|
||
|
'hyperloop_tube_open.png',
|
||
|
'hyperloop_tube_open.png',
|
||
|
},
|
||
|
|
||
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||
|
local node = minetest.get_node(pos)
|
||
|
node.name = "hyperloop:tubeS"
|
||
|
minetest.swap_node(pos, node)
|
||
|
if not Tube:after_place_tube(pos, placer, pointed_thing) then
|
||
|
minetest.remove_node(pos)
|
||
|
return true
|
||
|
end
|
||
|
return false
|
||
|
end,
|
||
|
|
||
|
paramtype2 = "facedir",
|
||
|
node_placement_prediction = "hyperloop:tubeS",
|
||
|
groups = {cracky=2, not_in_creative_inventory=1},
|
||
|
is_ground_content = false,
|
||
|
sounds = default.node_sound_metal_defaults(),
|
||
|
})
|
||
|
end
|
||
|
|
||
|
local function convert_legary_nodes(self, pos, dir)
|
||
|
local convert_next_tube = function(self, pos, dir)
|
||
|
local npos, node = self:get_node(pos, dir)
|
||
|
if tLegacyNodeNames[node.name] then
|
||
|
local dir1, dir2, num = determine_dir1_dir2_and_num_conn(self, npos)
|
||
|
if dir1 then
|
||
|
self.clbk_after_place_tube(get_tube_data(npos, dir1,
|
||
|
dir2 or tubelib2.Turn180Deg[dir1], num))
|
||
|
if tubelib2.Turn180Deg[dir] == dir1 then
|
||
|
return npos, dir2
|
||
|
else
|
||
|
return npos, dir1
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local cnt = 0
|
||
|
if not dir then return pos, dir, cnt end
|
||
|
while cnt <= 64000 do
|
||
|
local new_pos, new_dir = convert_next_tube(self, pos, dir)
|
||
|
if cnt > 0 and (cnt % self.max_tube_length) == 0 then -- border reached?
|
||
|
JunctionsToBePlacedAfter[#JunctionsToBePlacedAfter + 1] = pos
|
||
|
end
|
||
|
if not new_dir then break end
|
||
|
pos, dir = new_pos, new_dir
|
||
|
cnt = cnt + 1
|
||
|
end
|
||
|
return pos, dir, cnt
|
||
|
end
|
||
|
|
||
|
local function convert_line(self, pos, dir)
|
||
|
local fpos,fdir = convert_legary_nodes(self, pos, dir)
|
||
|
self:tool_repair_tube(pos)
|
||
|
end
|
||
|
|
||
|
|
||
|
local tWifiNodes = {} -- user for pairing
|
||
|
local lWifiNodes = {} -- used for post processing
|
||
|
|
||
|
local function set_pairing(pos, peer_pos)
|
||
|
|
||
|
M(pos):set_int("tube_dir", Tube:get_primary_dir(pos))
|
||
|
M(peer_pos):set_int("tube_dir", Tube:get_primary_dir(peer_pos))
|
||
|
|
||
|
local tube_dir1 = Tube:store_teleport_data(pos, peer_pos)
|
||
|
local tube_dir2 = Tube:store_teleport_data(peer_pos, pos)
|
||
|
end
|
||
|
|
||
|
|
||
|
local function wifi_post_processing()
|
||
|
for _,pos in ipairs(lWifiNodes) do
|
||
|
local dir = Tube:get_primary_dir(pos)
|
||
|
local npos = Tube:get_pos(pos, dir)
|
||
|
Tube:tool_repair_tube(npos)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Wifi nodes don't know their counterpart.
|
||
|
-- But by means of the tube head nodes, two
|
||
|
-- Wifi nodes in one tube line can be determined.
|
||
|
local function determine_wifi_pairs(pos)
|
||
|
-- determine 1. tube head node
|
||
|
local pos1 = M(pos):get_string("peer")
|
||
|
if pos1 == "" then return end
|
||
|
-- determine 2. tube head node
|
||
|
local pos2 = M(P(pos1)):get_string("peer")
|
||
|
if pos2 == "" then return end
|
||
|
for k,item in pairs(tWifiNodes) do
|
||
|
-- entry already available
|
||
|
if item[1] == pos2 and item[2] == pos1 then
|
||
|
tWifiNodes[k] = nil
|
||
|
-- start paring
|
||
|
set_pairing(P(k), pos)
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
-- add single Wifi node to pairing table
|
||
|
tWifiNodes[SP(pos)] = {pos1, pos2}
|
||
|
end
|
||
|
|
||
|
local function next_node_on_the_way_to_a_wifi_node(pos)
|
||
|
local dirs = {}
|
||
|
for dir = 1, 6 do
|
||
|
local npos, node = Tube:get_node(pos, dir)
|
||
|
if tLegacyNodeNames[node.name] then
|
||
|
dirs[#dirs+1] = dir
|
||
|
elseif node.name == "hyperloop:tube_wifi1" then
|
||
|
lWifiNodes[#lWifiNodes+1] = npos
|
||
|
determine_wifi_pairs(npos)
|
||
|
end
|
||
|
end
|
||
|
if #dirs == 1 then
|
||
|
return dirs[1], nil, 1
|
||
|
elseif #dirs == 2 then
|
||
|
return dirs[1], dirs[2], 2
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function search_wifi_node(pos, dir)
|
||
|
local convert_next_tube = function(pos, dir)
|
||
|
local npos, node = Tube:get_node(pos, dir)
|
||
|
local dir1, dir2, num = next_node_on_the_way_to_a_wifi_node(npos)
|
||
|
if dir1 then
|
||
|
if tubelib2.Turn180Deg[dir] == dir1 then
|
||
|
return npos, dir2
|
||
|
else
|
||
|
return npos, dir1
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local cnt = 0
|
||
|
if not dir then return pos, cnt end
|
||
|
while true do
|
||
|
local new_pos, new_dir = convert_next_tube(pos, dir)
|
||
|
if not new_dir then break end
|
||
|
pos, dir = new_pos, new_dir
|
||
|
cnt = cnt + 1
|
||
|
end
|
||
|
return pos, dir, cnt
|
||
|
end
|
||
|
|
||
|
local function search_wifi_node_in_all_dirs(pos)
|
||
|
-- check all positions
|
||
|
for dir = 1, 6 do
|
||
|
local npos, node = Tube:get_node(pos, dir)
|
||
|
if node and node.name == "hyperloop:tube1" then
|
||
|
search_wifi_node(pos, dir)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function convert_tube_line(pos)
|
||
|
-- check all positions
|
||
|
for dir = 1, 6 do
|
||
|
local npos, node = Tube:get_node(pos, dir)
|
||
|
if node and node.name == "hyperloop:tube1" then
|
||
|
convert_line(Tube, pos, dir)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function convert_shaft_line(pos)
|
||
|
-- check lower position
|
||
|
convert_line(Shaft, pos, 5)
|
||
|
-- check upper position
|
||
|
pos.y = pos.y + 1
|
||
|
convert_line(Shaft, pos, 6)
|
||
|
pos.y = pos.y - 1
|
||
|
end
|
||
|
|
||
|
local function station_name(item)
|
||
|
if item.junction == true then
|
||
|
return "Junction"
|
||
|
elseif item.station_name then
|
||
|
return item.station_name
|
||
|
else
|
||
|
return "Station"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function add_to_table(tbl, tValues)
|
||
|
local res = table.copy(tbl)
|
||
|
for k,v in pairs(tValues) do
|
||
|
tbl[k] = v
|
||
|
end
|
||
|
return res
|
||
|
end
|
||
|
|
||
|
local function convert_station_data(tAllStations)
|
||
|
tLegacyNodeNames = {
|
||
|
["hyperloop:tube0"] = true,
|
||
|
["hyperloop:tube1"] = true,
|
||
|
["hyperloop:tube2"] = true,
|
||
|
}
|
||
|
|
||
|
local originNodeNames = add_to_table(Tube.primary_node_names, tLegacyNodeNames)
|
||
|
|
||
|
for key,item in pairs(tAllStations) do
|
||
|
if item.pos and Tube:is_secondary_node(item.pos) then
|
||
|
Stations:set(item.pos, station_name(item), {
|
||
|
owner = item.owner or S("<unknown>"),
|
||
|
junction = item.junction,
|
||
|
facedir = item.facedir,
|
||
|
booking_info = item.booking_info,
|
||
|
booking_pos = item.booking_pos,
|
||
|
})
|
||
|
end
|
||
|
end
|
||
|
-- First perform the Wifi node pairing
|
||
|
-- before all tube node loose their meta data
|
||
|
-- while converted.
|
||
|
for key,item in pairs(tAllStations) do
|
||
|
if item.pos and Tube:is_secondary_node(item.pos) then
|
||
|
search_wifi_node_in_all_dirs(item.pos)
|
||
|
end
|
||
|
end
|
||
|
-- Then convert all tube nodes
|
||
|
for key,item in pairs(tAllStations) do
|
||
|
if item.pos and Tube:is_secondary_node(item.pos) then
|
||
|
convert_tube_line(item.pos)
|
||
|
Tube:after_place_node(item.pos)
|
||
|
end
|
||
|
end
|
||
|
-- Repair the tube lines of wifi nodes
|
||
|
wifi_post_processing()
|
||
|
|
||
|
Tube.primary_node_names = originNodeNames
|
||
|
end
|
||
|
|
||
|
local function convert_elevator_data(tAllElevators)
|
||
|
tLegacyNodeNames = {
|
||
|
["hyperloop:shaft"] = true,
|
||
|
["hyperloop:shaft2"] = true,
|
||
|
}
|
||
|
local originNodeNames = add_to_table(Shaft.primary_node_names, tLegacyNodeNames)
|
||
|
local originDirsToCheck = table.copy(Shaft.dirs_to_check)
|
||
|
Shaft.dirs_to_check = {5,6} -- legacy elevators use up/down only
|
||
|
|
||
|
for pos,tElevator in pairs(tAllElevators) do
|
||
|
for _,floor in pairs(tElevator.floors) do
|
||
|
if floor.pos and Shaft:is_secondary_node(floor.pos) then
|
||
|
Elevators:set(floor.pos, floor.name, {
|
||
|
facedir = floor.facedir,
|
||
|
})
|
||
|
convert_shaft_line(floor.pos)
|
||
|
M(floor.pos):set_int("change_counter", 0)
|
||
|
Shaft:after_place_node(floor.pos)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
Shaft.primary_node_names = originNodeNames
|
||
|
Shaft.dirs_to_check = originDirsToCheck
|
||
|
end
|
||
|
|
||
|
local function place_junctions()
|
||
|
for _,pos in ipairs(JunctionsToBePlacedAfter) do
|
||
|
minetest.set_node(pos, {name = "hyperloop:junction"})
|
||
|
M(pos):set_string("infotext", S("Junction"))
|
||
|
Stations:set(pos, "Junction", {owner = S("unknown"), junction = true})
|
||
|
Tube:after_place_node(pos)
|
||
|
minetest.log("action", "[Hyperloop] Junction placed at "..SP(pos))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local wpath = minetest.get_worldpath()
|
||
|
function hyperloop.file2table(filename)
|
||
|
local f = io.open(wpath..DIR_DELIM..filename, "r")
|
||
|
if f == nil then return nil end
|
||
|
local t = f:read("*all")
|
||
|
f:close()
|
||
|
if t == "" or t == nil then return nil end
|
||
|
return minetest.deserialize(t)
|
||
|
end
|
||
|
|
||
|
local function migrate()
|
||
|
local data = hyperloop.file2table("mod_hyperloop.data")
|
||
|
if data then
|
||
|
minetest.log("action", "[Hyperloop] Migrate data...")
|
||
|
hyperloop.convert = true
|
||
|
convert_station_data(data.tAllStations)
|
||
|
convert_elevator_data(data.tAllElevators)
|
||
|
os.remove(wpath..DIR_DELIM.."mod_hyperloop.data")
|
||
|
place_junctions()
|
||
|
hyperloop.convert = nil
|
||
|
minetest.log("action", "[Hyperloop] Data migrated")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
minetest.after(5, migrate)
|
||
|
|
||
|
minetest.register_lbm({
|
||
|
label = "[Hyperloop] booking/seat/door migration",
|
||
|
name = "hyperloop:migrate",
|
||
|
nodenames = {
|
||
|
"hyperloop:booking", "hyperloop:booking_ground",
|
||
|
"hyperloop:doorTopPassive", "hyperloop:doorBottom",
|
||
|
"hyperloop:seat",
|
||
|
},
|
||
|
run_at_every_load = true,
|
||
|
action = function(pos, node)
|
||
|
local meta = M(pos)
|
||
|
if meta:get_string("key_str") ~= "" then
|
||
|
local s = meta:get_string("key_str")
|
||
|
meta:set_string("sStationPos", "("..string.sub(s, 2, -2)..")")
|
||
|
if node.name == "hyperloop:booking" or node.name == "hyperloop:booking_ground" then
|
||
|
meta:set_int("change_counter", 0)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
})
|