init.lua 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. if not minetest.global_exists("networks") then
  2. networks = {}
  3. networks.modpath = minetest.get_modpath("networks")
  4. -- load insecure environment
  5. local secenv = minetest.request_insecure_environment()
  6. if secenv then
  7. print("[networks] insecure environment loaded.")
  8. networks.sql = secenv.require("lsqlite3")
  9. assert(networks.sql)
  10. else
  11. minetest.log("error", "[networks] failed to load insecure" ..
  12. " environment, please add this mod to the trusted mods list.")
  13. end
  14. end
  15. local param2_rules = {
  16. [0] = "x",
  17. [1] = "z",
  18. [2] = "x",
  19. [3] = "z",
  20. [4] = "x",
  21. [5] = "y",
  22. [6] = "x",
  23. [7] = "y",
  24. [8] = "x",
  25. [9] = "y",
  26. [10] = "x",
  27. [11] = "y",
  28. [12] = "y",
  29. [13] = "z",
  30. [14] = "y",
  31. [15] = "z",
  32. [16] = "y",
  33. [17] = "z",
  34. [18] = "y",
  35. [19] = "z",
  36. [20] = "x",
  37. [21] = "z",
  38. [22] = "x",
  39. [23] = "z",
  40. }
  41. local direction_rules = {
  42. ["n"] = "z",
  43. ["s"] = "z",
  44. ["w"] = "x",
  45. ["e"] = "x",
  46. ["u"] = "y",
  47. ["d"] = "y",
  48. }
  49. -- Get cable axis alignment from a param2 value.
  50. -- Cable nodes must have nodeboxes that match this.
  51. -- All cable nodes must align to the same axis.
  52. networks.cable_rotation_to_axis =
  53. function(param2)
  54. if param2 >= 0 and param2 <= 23 then
  55. return param2_rules[param2]
  56. end
  57. end
  58. -- Get a unit vector from a cardinal direction, or up/down.
  59. networks.direction_to_vector =
  60. function(dir)
  61. local d = vector.new(0, 0, 0)
  62. if dir == "n" then
  63. d.z = 1
  64. elseif dir == "s" then
  65. d.z = -1
  66. elseif dir == "w" then
  67. d.x = -1
  68. elseif dir == "e" then
  69. d.x = 1
  70. elseif dir == "u" then
  71. d.y = 1
  72. elseif dir == "d" then
  73. d.y = -1
  74. else
  75. return nil
  76. end
  77. return d
  78. end
  79. -- Find a network hub, starting from a position and continuing in a direction.
  80. -- Cable nodes (with the right axis) may intervene between hubs.
  81. -- This function must return the position of the next hub, if possible, or nil.
  82. networks.find_hub =
  83. function(pos, dir, tier)
  84. local meta = minetest.get_meta(pos)
  85. local p = vector.new(pos.x, pos.y, pos.z)
  86. local d = networks.direction_to_vector(dir)
  87. local station_name = "switching_station:" .. tier
  88. local cable_name = "cable:" .. tier
  89. -- Max cable length. +1 because a switching station takes up 1 meter of length.
  90. local cable_length = cable.get_max_length(tier)+1
  91. -- Seek a limited number of meters in a direction.
  92. for i = 1, cable_length, 1 do
  93. p = vector.add(p, d)
  94. local node = minetest.get_node(p)
  95. if node.name == station_name then
  96. -- Compatible switching station found!
  97. return p
  98. elseif node.name == cable_name then
  99. -- It's a cable node. We need to check its rotation.
  100. local paxis = networks.cable_rotation_to_axis(node.param2)
  101. if paxis then
  102. local daxis = direction_rules[dir]
  103. if not daxis or paxis ~= daxis then
  104. -- Cable has bad axis. Stop scanning.
  105. return nil
  106. end
  107. else
  108. -- Invalid param2. We stop scanning.
  109. return nil
  110. end
  111. -- Unless these items can automatically update switching stations when removed, we can't allow this.
  112. --elseif minetest.get_item_group(node.name, "conductor") > 0 and minetest.get_item_group(node.name, "block") > 0 then
  113. -- Anything that is both in group `conductor` and `block` is treated as a cable node.
  114. -- This allows cables to pass through walls without requiring ugly holes.
  115. else
  116. -- Anything other than a cable node or switching station blocks search.
  117. return nil
  118. end
  119. end
  120. return nil
  121. end
  122. networks.refresh_hubs =
  123. function(pos, tier)
  124. local meta = minetest.get_meta(pos)
  125. for k, v in ipairs({
  126. {n="n"},
  127. {n="s"},
  128. {n="e"},
  129. {n="w"},
  130. {n="u"},
  131. {n="d"},
  132. }) do
  133. local p = networks.find_hub(pos, v.n, tier)
  134. if p then
  135. meta:set_string(v.n, minetest.pos_to_string(p))
  136. else
  137. meta:set_string(v.n, nil)
  138. end
  139. end
  140. end
  141. -- Invalidate all nearby hubs from a position: NSEW, UD.
  142. -- This should cause them to re-update their routing.
  143. -- This would need to be done if a hub or cable is removed.
  144. networks.invalidate_hubs =
  145. function(pos, tier)
  146. for k, v in ipairs({
  147. {n="n"},
  148. {n="s"},
  149. {n="e"},
  150. {n="w"},
  151. {n="u"},
  152. {n="d"},
  153. }) do
  154. local p = networks.find_hub(pos, v.n, tier)
  155. if p then
  156. local meta = minetest.get_meta(p)
  157. for i, j in ipairs({
  158. {n="n"},
  159. {n="s"},
  160. {n="e"},
  161. {n="w"},
  162. {n="u"},
  163. {n="d"},
  164. }) do
  165. meta:set_string(j.n, nil)
  166. end
  167. -- Trigger node update.
  168. local timer = minetest.get_node_timer(p)
  169. if not timer:is_started() then
  170. timer:start(1.0)
  171. end
  172. end
  173. end
  174. end
  175. -- This function must return a table of all adjacent hubs.
  176. -- Table entries shall contain position of hub and its message function.
  177. networks.get_adjacent_hubs =
  178. function(pos, tiers)
  179. -- If `tiers` is omitted or nil, then all tiers are allowed.
  180. if not tiers then tiers = {"lv", "mv", "hv"} end
  181. -- Return list of discovered network hubs.
  182. local hubs = {}
  183. -- List of valid adjacent locations.
  184. local targets = {
  185. {x=pos.x+1, y=pos.y, z=pos.z},
  186. {x=pos.x-1, y=pos.y, z=pos.z},
  187. {x=pos.x, y=pos.y, z=pos.z+1},
  188. {x=pos.x, y=pos.y, z=pos.z-1},
  189. {x=pos.x, y=pos.y-1, z=pos.z},
  190. {x=pos.x, y=pos.y+1, z=pos.z},
  191. }
  192. -- Get all adjacent nodes once.
  193. local nodes = {}
  194. for k, v in ipairs(targets) do
  195. local meta = minetest.get_meta(v)
  196. if meta:get_string("technic_machine") == "yes" then
  197. local nn = meta:get_string("technic_name")
  198. if meta:get_string("technic_type") == "switch" then
  199. nodes[#nodes+1] = {name=nn, pos=v}
  200. end
  201. end
  202. end
  203. -- Scan through adjacent nodes and find valid ones.
  204. for j, t in ipairs(tiers) do
  205. local nn = "switching_station:" .. t
  206. local def = minetest.registered_items[nn]
  207. for k, v in ipairs(nodes) do
  208. if v.name == nn then
  209. hubs[#hubs+1] = {pos=v.pos, on_machine_execute=def.on_machine_execute}
  210. end
  211. end
  212. end
  213. return hubs
  214. end
  215. -- This function must return a table of all adjacent machines.
  216. -- Table entries shall contain position of machine and its message function.
  217. networks.get_adjacent_machines =
  218. function(pos, tier)
  219. -- Return list of discovered adjacent machines.
  220. local hubs = {}
  221. -- List of valid adjacent locations.
  222. local targets = {
  223. {x=pos.x+1, y=pos.y, z=pos.z},
  224. {x=pos.x-1, y=pos.y, z=pos.z},
  225. {x=pos.x, y=pos.y, z=pos.z+1},
  226. {x=pos.x, y=pos.y, z=pos.z-1},
  227. {x=pos.x, y=pos.y-1, z=pos.z},
  228. {x=pos.x, y=pos.y+1, z=pos.z},
  229. }
  230. for k, v in ipairs(targets) do
  231. local meta = minetest.get_meta(v)
  232. if meta:get_string("technic_machine") == "yes" then
  233. if string.find(meta:get_string("technic_tier"), tier) then
  234. local nn = meta:get_string("technic_name")
  235. -- Switching stations are NOT machines in the context of this function.
  236. -- This function cannot return switching stations because that would make a recursion mess.
  237. if nn ~= "" and not string.find(nn, "^switching_station:") then
  238. local def = minetest.registered_items[nn]
  239. assert(type(def.on_machine_execute) == "function")
  240. hubs[#hubs+1] = {pos=v, on_machine_execute=def.on_machine_execute}
  241. end
  242. end
  243. end
  244. end
  245. return hubs
  246. end
  247. if not networks.run_once then
  248. local c = "networks:core"
  249. local f = networks.modpath .. "/init.lua"
  250. reload.register_file(c, f, false)
  251. dofile(networks.modpath .. "/nodestore.lua")
  252. dofile(networks.modpath .. "/net2.lua")
  253. networks.run_once = true
  254. end