init.lua 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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. spawn.add_suitable_biome(name)
  30. end
  31. -- End of parameters
  32. --------------------
  33. -- Direction table
  34. local dirs = {
  35. vector.new(0, 0, 1),
  36. vector.new(-1, 0, 0),
  37. vector.new(0, 0, -1),
  38. vector.new(1, 0, 0),
  39. }
  40. -- Initial variables
  41. local edge_len = 1
  42. local edge_dist = 0
  43. local dir_step = 0
  44. local dir_ind = 1
  45. local searched = false
  46. local success = false
  47. local spawn_pos = {}
  48. -- Get world 'mapgen_limit' and 'chunksize' to calculate 'spawn_limit'.
  49. -- This accounts for how mapchunks are not generated if they or their shell exceed
  50. -- 'mapgen_limit'.
  51. local mapgen_limit = tonumber(minetest.get_mapgen_setting("mapgen_limit"))
  52. local chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
  53. local spawn_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0)
  54. -- Functions
  55. ------------
  56. -- Get next position on square search spiral
  57. local function next_pos()
  58. if edge_dist == edge_len then
  59. edge_dist = 0
  60. dir_ind = dir_ind + 1
  61. if dir_ind == 5 then
  62. dir_ind = 1
  63. end
  64. dir_step = dir_step + 1
  65. edge_len = math.floor(dir_step / 2) + 1
  66. end
  67. local dir = dirs[dir_ind]
  68. local move = vector.multiply(dir, res)
  69. edge_dist = edge_dist + 1
  70. return vector.add(pos, move)
  71. end
  72. -- Spawn position search
  73. local function search()
  74. for iter = 1, checks do
  75. local biome_data = minetest.get_biome_data(pos)
  76. -- Sometimes biome_data is nil
  77. if biome_data and biome_ids[biome_data.biome] then
  78. local spawn_y = minetest.get_spawn_level(pos.x, pos.z)
  79. if spawn_y then
  80. spawn_pos = vector.new(pos.x, spawn_y, pos.z)
  81. return true
  82. end
  83. end
  84. pos = next_pos()
  85. -- Check for position being outside world edge
  86. if math.abs(pos.x) > spawn_limit or math.abs(pos.z) > spawn_limit then
  87. return false
  88. end
  89. end
  90. return false
  91. end
  92. function spawn.get_default_pos()
  93. -- Search for spawn position once per server session
  94. if not searched then
  95. success = search()
  96. searched = true
  97. end
  98. return success and spawn_pos
  99. end