init.lua 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. -- spawn/init.lua
  2. -- Disable by mapgen, setting or if 'static_spawnpoint' is set
  3. --------------------------------------------------------------
  4. local mg_name = minetest.get_mapgen_setting("mg_name")
  5. if mg_name == "v6" or mg_name == "singlenode" or
  6. minetest.settings:get("static_spawnpoint") or
  7. minetest.settings:get_bool("engine_spawn") 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
  20. local biome_ids = {
  21. minetest.get_biome_id("taiga"),
  22. minetest.get_biome_id("coniferous_forest"),
  23. minetest.get_biome_id("deciduous_forest"),
  24. minetest.get_biome_id("grassland"),
  25. minetest.get_biome_id("savanna"),
  26. }
  27. -- End of parameters
  28. --------------------
  29. -- Direction table
  30. local dirs = {
  31. {x = 0, y = 0, z = 1},
  32. {x = -1, y = 0, z = 0},
  33. {x = 0, y = 0, z = -1},
  34. {x = 1, y = 0, z = 0},
  35. }
  36. -- Initial variables
  37. local edge_len = 1
  38. local edge_dist = 0
  39. local dir_step = 0
  40. local dir_ind = 1
  41. local searched = false
  42. local success = false
  43. local spawn_pos = {}
  44. -- Get world 'mapgen_limit' and 'chunksize' to calculate 'spawn_limit'.
  45. -- This accounts for how mapchunks are not generated if they or their shell exceed
  46. -- 'mapgen_limit'.
  47. local mapgen_limit = tonumber(minetest.get_mapgen_setting("mapgen_limit"))
  48. local chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
  49. local spawn_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0)
  50. --Functions
  51. -----------
  52. -- Get next position on square search spiral
  53. local function next_pos()
  54. if edge_dist == edge_len then
  55. edge_dist = 0
  56. dir_ind = dir_ind + 1
  57. if dir_ind == 5 then
  58. dir_ind = 1
  59. end
  60. dir_step = dir_step + 1
  61. edge_len = math.floor(dir_step / 2) + 1
  62. end
  63. local dir = dirs[dir_ind]
  64. local move = vector.multiply(dir, res)
  65. edge_dist = edge_dist + 1
  66. return vector.add(pos, move)
  67. end
  68. -- Spawn position search
  69. local function search()
  70. for iter = 1, checks do
  71. local biome_data = minetest.get_biome_data(pos)
  72. -- Sometimes biome_data is nil
  73. local biome = biome_data and biome_data.biome
  74. for id_ind = 1, #biome_ids do
  75. local biome_id = biome_ids[id_ind]
  76. if biome == biome_id then
  77. local spawn_y = minetest.get_spawn_level(pos.x, pos.z)
  78. if spawn_y then
  79. spawn_pos = {x = pos.x, y = spawn_y, z = pos.z}
  80. return true
  81. end
  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. -- On new player spawn and player respawn
  93. -- Search for spawn position once per server session. If successful, store
  94. -- position and reposition players, otherwise leave them at engine spawn
  95. -- position.
  96. local function on_spawn(player)
  97. if not searched then
  98. success = search()
  99. searched = true
  100. end
  101. if success then
  102. player:set_pos(spawn_pos)
  103. end
  104. return success
  105. end
  106. minetest.register_on_newplayer(function(player)
  107. on_spawn(player)
  108. end)
  109. local enable_bed_respawn = minetest.settings:get_bool("enable_bed_respawn")
  110. if enable_bed_respawn == nil then
  111. enable_bed_respawn = true
  112. end
  113. minetest.register_on_respawnplayer(function(player)
  114. -- Avoid respawn conflict with beds mod
  115. if beds and enable_bed_respawn and
  116. beds.spawn[player:get_player_name()] then
  117. return
  118. end
  119. return on_spawn(player)
  120. end)