init.lua 7.0 KB

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