init.lua 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. -- Always load the API
  2. ----------------------
  3. dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/api.lua")
  4. -- Disable biome-search implementation on unsuitable mapgens
  5. ------------------------------------------------------------
  6. local mg_name = minetest.get_mapgen_setting("mg_name")
  7. if mg_name == "v6" or mg_name == "singlenode" then
  8. return
  9. end
  10. -- Parameters
  11. -------------
  12. -- Resolution of search grid in nodes.
  13. local res = 64
  14. -- Number of points checked in the square search grid (edge * edge).
  15. local checks = 128 * 128
  16. -- Starting point for biome checks. This also sets the y co-ordinate for all
  17. -- points checked, so the suitable biomes must be active at this y.
  18. local pos = {x = 0, y = 8, z = 0}
  19. -- Table of suitable biomes and matching API function
  20. local biome_ids = {}
  21. function spawn.add_suitable_biome(biome)
  22. local id = minetest.get_biome_id(biome)
  23. assert(id ~= nil)
  24. biome_ids[id] = true
  25. end
  26. for _, name in ipairs({
  27. "taiga", "coniferous_forest", "deciduous_forest", "grassland", "savanna"
  28. }) do
  29. local id = minetest.get_biome_id(name)
  30. if id then
  31. biome_ids[id] = true
  32. end
  33. end
  34. -- End of parameters
  35. --------------------
  36. -- Direction table
  37. local dirs = {
  38. vector.new(0, 0, 1),
  39. vector.new(-1, 0, 0),
  40. vector.new(0, 0, -1),
  41. vector.new(1, 0, 0),
  42. }
  43. -- Initial variables
  44. local edge_len = 1
  45. local edge_dist = 0
  46. local dir_step = 0
  47. local dir_ind = 1
  48. local searched = false
  49. local success = false
  50. local spawn_pos = {}
  51. -- Get world 'mapgen_limit' and 'chunksize' to calculate 'spawn_limit'.
  52. -- This accounts for how mapchunks are not generated if they or their shell exceed
  53. -- 'mapgen_limit'.
  54. local mapgen_limit = tonumber(minetest.get_mapgen_setting("mapgen_limit"))
  55. local chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
  56. local spawn_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0)
  57. -- Functions
  58. ------------
  59. -- Get next position on square search spiral
  60. local function next_pos()
  61. if edge_dist == edge_len then
  62. edge_dist = 0
  63. dir_ind = dir_ind + 1
  64. if dir_ind == 5 then
  65. dir_ind = 1
  66. end
  67. dir_step = dir_step + 1
  68. edge_len = math.floor(dir_step / 2) + 1
  69. end
  70. local dir = dirs[dir_ind]
  71. local move = vector.multiply(dir, res)
  72. edge_dist = edge_dist + 1
  73. return vector.add(pos, move)
  74. end
  75. -- Spawn position search
  76. local function search()
  77. for iter = 1, checks do
  78. local biome_data = minetest.get_biome_data(pos)
  79. -- Sometimes biome_data is nil
  80. if biome_data and biome_ids[biome_data.biome] then
  81. local spawn_y = minetest.get_spawn_level(pos.x, pos.z)
  82. if spawn_y then
  83. spawn_pos = vector.new(pos.x, spawn_y, pos.z)
  84. return true
  85. end
  86. end
  87. pos = next_pos()
  88. -- Check for position being outside world edge
  89. if math.abs(pos.x) > spawn_limit or math.abs(pos.z) > spawn_limit then
  90. return false
  91. end
  92. end
  93. return false
  94. end
  95. function spawn.get_default_pos()
  96. -- Search for spawn position once per server session
  97. if not searched then
  98. success = search()
  99. searched = true
  100. end
  101. return success and spawn_pos
  102. end