Add findbiome mod
This commit is contained in:
parent
b2c8d7cff0
commit
c9b464f329
|
@ -0,0 +1,23 @@
|
||||||
|
# Minetest mod: findbiome
|
||||||
|
|
||||||
|
## Description
|
||||||
|
This is a mod to help with mod/game development for Minetest.
|
||||||
|
It adds a command (“findbiome”) to find a biome nearby and teleport you to it
|
||||||
|
and another command (“listbiomes”) to list biomes.
|
||||||
|
|
||||||
|
Version: 1.0.1
|
||||||
|
|
||||||
|
## Known limitations
|
||||||
|
There's no guarantee you will always find the biome, even if it exists in the world.
|
||||||
|
This can happen if the biome is very obscure or small, but usually you should be
|
||||||
|
able to find the biome.
|
||||||
|
|
||||||
|
If the biome could not be found, just move to somewhere else and try again.
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
- paramat (MIT License)
|
||||||
|
- Wuzzy (MIT License)
|
||||||
|
|
||||||
|
See license.txt for license information.
|
||||||
|
|
||||||
|
This mod is based on the algorithm of the "spawn" mod from Minetest Game 5.0.0.
|
|
@ -0,0 +1,320 @@
|
||||||
|
local S = minetest.get_translator("findbiome")
|
||||||
|
|
||||||
|
local mod_biomeinfo = minetest.get_modpath("biomeinfo") ~= nil
|
||||||
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||||
|
local water_level = tonumber(minetest.get_mapgen_setting("water_level"))
|
||||||
|
|
||||||
|
-- Calculate the maximum playable limit
|
||||||
|
local mapgen_limit = tonumber(minetest.get_mapgen_setting("mapgen_limit"))
|
||||||
|
local chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
|
||||||
|
local playable_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0)
|
||||||
|
|
||||||
|
-- Parameters
|
||||||
|
-------------
|
||||||
|
|
||||||
|
-- Resolution of search grid in nodes.
|
||||||
|
local res = 64
|
||||||
|
-- Number of points checked in the square search grid (edge * edge).
|
||||||
|
local checks = 128 * 128
|
||||||
|
|
||||||
|
-- End of parameters
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
-- Direction table
|
||||||
|
|
||||||
|
local dirs = {
|
||||||
|
{x = 0, y = 0, z = 1},
|
||||||
|
{x = -1, y = 0, z = 0},
|
||||||
|
{x = 0, y = 0, z = -1},
|
||||||
|
{x = 1, y = 0, z = 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Returns true if pos is within the world boundaries
|
||||||
|
local function is_in_world(pos)
|
||||||
|
return not (math.abs(pos.x) > playable_limit or math.abs(pos.y) > playable_limit or math.abs(pos.z) > playable_limit)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Checks if pos is within the biome's boundaries. If it isn't, places pos inside the boundaries.
|
||||||
|
local function adjust_pos_to_biome_limits(pos, biome_id)
|
||||||
|
local bpos = table.copy(pos)
|
||||||
|
local biome_name = minetest.get_biome_name(biome_id)
|
||||||
|
local biome = minetest.registered_biomes[biome_name]
|
||||||
|
if not biome then
|
||||||
|
minetest.log("error", "[findbiome] adjust_pos_to_biome_limits non-existing biome!")
|
||||||
|
return bpos, true
|
||||||
|
end
|
||||||
|
local axes = {"y", "x", "z"}
|
||||||
|
local out_of_bounds = false
|
||||||
|
for a=1, #axes do
|
||||||
|
local ax = axes[a]
|
||||||
|
local min, max
|
||||||
|
if biome[ax.."_min"] then
|
||||||
|
min = biome[ax.."_min"]
|
||||||
|
else
|
||||||
|
min = -playable_limit
|
||||||
|
end
|
||||||
|
if biome[ax.."_max"] then
|
||||||
|
max = biome[ax.."_max"]
|
||||||
|
else
|
||||||
|
max = playable_limit
|
||||||
|
end
|
||||||
|
min = tonumber(min)
|
||||||
|
max = tonumber(max)
|
||||||
|
if bpos[ax] < min then
|
||||||
|
out_of_bounds = true
|
||||||
|
bpos[ax] = min
|
||||||
|
if max-min > 16 then
|
||||||
|
bpos[ax] = math.max(bpos[ax] + 8, -playable_limit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if bpos[ax] > max then
|
||||||
|
out_of_bounds = true
|
||||||
|
bpos[ax] = max
|
||||||
|
if max-min > 16 then
|
||||||
|
bpos[ax] = math.min(bpos[ax] - 8, playable_limit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return bpos, out_of_bounds
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Find the special default biome
|
||||||
|
local function find_default_biome()
|
||||||
|
local all_biomes = minetest.registered_biomes
|
||||||
|
local biome_count = 0
|
||||||
|
for b, biome in pairs(all_biomes) do
|
||||||
|
biome_count = biome_count + 1
|
||||||
|
end
|
||||||
|
-- Trivial case: No biomes registered, default biome is everywhere.
|
||||||
|
if biome_count == 0 then
|
||||||
|
local y = minetest.get_spawn_level(0, 0)
|
||||||
|
if not y then
|
||||||
|
y = 0
|
||||||
|
end
|
||||||
|
return { x = 0, y = y, z = 0 }
|
||||||
|
end
|
||||||
|
local pos = {}
|
||||||
|
-- Just check a lot of random positions
|
||||||
|
-- It's a crappy algorithm but better than nothing.
|
||||||
|
for i=1, 100 do
|
||||||
|
pos.x = math.random(-playable_limit, playable_limit)
|
||||||
|
pos.y = math.random(-playable_limit, playable_limit)
|
||||||
|
pos.z = math.random(-playable_limit, playable_limit)
|
||||||
|
local biome_data = minetest.get_biome_data(pos)
|
||||||
|
if biome_data and minetest.get_biome_name(biome_data.biome) == "default" then
|
||||||
|
return pos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_biome(pos, biomes)
|
||||||
|
pos = vector.round(pos)
|
||||||
|
-- Pos: Starting point for biome checks. This also sets the y co-ordinate for all
|
||||||
|
-- points checked, so the suitable biomes must be active at this y.
|
||||||
|
|
||||||
|
-- Initial variables
|
||||||
|
|
||||||
|
local edge_len = 1
|
||||||
|
local edge_dist = 0
|
||||||
|
local dir_step = 0
|
||||||
|
local dir_ind = 1
|
||||||
|
local success = false
|
||||||
|
local spawn_pos
|
||||||
|
local biome_ids
|
||||||
|
|
||||||
|
-- Get next position on square search spiral
|
||||||
|
local function next_pos()
|
||||||
|
if edge_dist == edge_len then
|
||||||
|
edge_dist = 0
|
||||||
|
dir_ind = dir_ind + 1
|
||||||
|
if dir_ind == 5 then
|
||||||
|
dir_ind = 1
|
||||||
|
end
|
||||||
|
dir_step = dir_step + 1
|
||||||
|
edge_len = math.floor(dir_step / 2) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local dir = dirs[dir_ind]
|
||||||
|
local move = vector.multiply(dir, res)
|
||||||
|
|
||||||
|
edge_dist = edge_dist + 1
|
||||||
|
|
||||||
|
return vector.add(pos, move)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Position search
|
||||||
|
local function search()
|
||||||
|
local attempt = 1
|
||||||
|
while attempt < 3 do
|
||||||
|
for iter = 1, checks do
|
||||||
|
local biome_data = minetest.get_biome_data(pos)
|
||||||
|
-- Sometimes biome_data is nil
|
||||||
|
local biome = biome_data and biome_data.biome
|
||||||
|
for id_ind = 1, #biome_ids do
|
||||||
|
local biome_id = biome_ids[id_ind]
|
||||||
|
pos = adjust_pos_to_biome_limits(pos, biome_id)
|
||||||
|
local spos = table.copy(pos)
|
||||||
|
if biome == biome_id then
|
||||||
|
local good_spawn_height = pos.y <= water_level + 16 and pos.y >= water_level
|
||||||
|
local spawn_y = minetest.get_spawn_level(spos.x, spos.z)
|
||||||
|
if spawn_y then
|
||||||
|
spawn_pos = {x = spos.x, y = spawn_y, z = spos.z}
|
||||||
|
elseif not good_spawn_height then
|
||||||
|
spawn_pos = {x = spos.x, y = spos.y, z = spos.z}
|
||||||
|
elseif attempt >= 2 then
|
||||||
|
spawn_pos = {x = spos.x, y = spos.y, z = spos.z}
|
||||||
|
end
|
||||||
|
if spawn_pos then
|
||||||
|
local adjusted_pos, outside = adjust_pos_to_biome_limits(spawn_pos, biome_id)
|
||||||
|
if is_in_world(spawn_pos) and not outside then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = next_pos()
|
||||||
|
end
|
||||||
|
attempt = attempt + 1
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local function search_v6()
|
||||||
|
if not mod_biomeinfo then return
|
||||||
|
false
|
||||||
|
end
|
||||||
|
for iter = 1, checks do
|
||||||
|
local found_biome = biomeinfo.get_v6_biome(pos)
|
||||||
|
for i = 1, #biomes do
|
||||||
|
local searched_biome = biomes[i]
|
||||||
|
if found_biome == searched_biome then
|
||||||
|
local spawn_y = minetest.get_spawn_level(pos.x, pos.z)
|
||||||
|
if spawn_y then
|
||||||
|
spawn_pos = {x = pos.x, y = spawn_y, z = pos.z}
|
||||||
|
if is_in_world(spawn_pos) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = next_pos()
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if mg_name == "v6" then
|
||||||
|
success = search_v6()
|
||||||
|
else
|
||||||
|
-- Table of suitable biomes
|
||||||
|
biome_ids = {}
|
||||||
|
for i=1, #biomes do
|
||||||
|
local id = minetest.get_biome_id(biomes[i])
|
||||||
|
if not id then
|
||||||
|
return nil, false
|
||||||
|
end
|
||||||
|
table.insert(biome_ids, id)
|
||||||
|
end
|
||||||
|
success = search()
|
||||||
|
end
|
||||||
|
return spawn_pos, success
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local mods_loaded = false
|
||||||
|
minetest.register_on_mods_loaded(function()
|
||||||
|
mods_loaded = true
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Regiver chat commands
|
||||||
|
do
|
||||||
|
minetest.register_chatcommand("findbiome", {
|
||||||
|
description = S("Find and teleport to biome"),
|
||||||
|
params = S("<biome>"),
|
||||||
|
privs = { debug = true, teleport = true },
|
||||||
|
func = function(name, param)
|
||||||
|
if not mods_loaded then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if not player then
|
||||||
|
return false, S("No player.")
|
||||||
|
end
|
||||||
|
local pos = player:get_pos()
|
||||||
|
local invalid_biome = true
|
||||||
|
if mg_name == "v6" then
|
||||||
|
if not mod_biomeinfo then
|
||||||
|
return false, S("Not supported. The “biomeinfo” mod is required for v6 mapgen support!")
|
||||||
|
end
|
||||||
|
local biomes = biomeinfo.get_active_v6_biomes()
|
||||||
|
for b=1, #biomes do
|
||||||
|
if param == biomes[b] then
|
||||||
|
invalid_biome = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if param == "default" then
|
||||||
|
local biome_pos = find_default_biome()
|
||||||
|
if biome_pos then
|
||||||
|
player:set_pos(biome_pos)
|
||||||
|
return true, S("Biome found at @1.", minetest.pos_to_string(biome_pos))
|
||||||
|
else
|
||||||
|
return false, S("No biome found!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local id = minetest.get_biome_id(param)
|
||||||
|
if id then
|
||||||
|
invalid_biome = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if invalid_biome then
|
||||||
|
return false, S("Biome does not exist!")
|
||||||
|
end
|
||||||
|
local biome_pos, success = find_biome(pos, {param})
|
||||||
|
if success then
|
||||||
|
player:set_pos(biome_pos)
|
||||||
|
return true, S("Biome found at @1.", minetest.pos_to_string(biome_pos))
|
||||||
|
else
|
||||||
|
return false, S("No biome found!")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("listbiomes", {
|
||||||
|
description = S("List all biomes"),
|
||||||
|
params = "",
|
||||||
|
privs = { debug = true },
|
||||||
|
func = function(name, param)
|
||||||
|
if not mods_loaded then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local biomes
|
||||||
|
local b = 0
|
||||||
|
if mg_name == "v6" then
|
||||||
|
if not mod_biomeinfo then
|
||||||
|
return false, S("Not supported. The “biomeinfo” mod is required for v6 mapgen support!")
|
||||||
|
end
|
||||||
|
biomes = biomeinfo.get_active_v6_biomes()
|
||||||
|
b = #biomes
|
||||||
|
else
|
||||||
|
biomes = {}
|
||||||
|
for k,v in pairs(minetest.registered_biomes) do
|
||||||
|
table.insert(biomes, k)
|
||||||
|
b = b + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if b == 0 then
|
||||||
|
return true, S("No biomes.")
|
||||||
|
else
|
||||||
|
table.sort(biomes)
|
||||||
|
for b=1, #biomes do
|
||||||
|
minetest.chat_send_player(name, biomes[b])
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
License of source code
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
Copyright (C) 2018 paramat
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
https://opensource.org/licenses/MIT
|
|
@ -0,0 +1,10 @@
|
||||||
|
# textdomain: findbiome
|
||||||
|
Find and teleport to biome=Ein Biom finden und hinteleportieren
|
||||||
|
<biome>=<Biom>
|
||||||
|
No player.=Kein Spieler
|
||||||
|
Biome does not exist!=Biom existiert nicht!
|
||||||
|
Biome found at @1.=Biom gefunden bei @1.
|
||||||
|
No biome found!=Kein Biom gefunden!
|
||||||
|
List all biomes=Alle Biome auflisten
|
||||||
|
No biomes.=Keine Biome.
|
||||||
|
Not supported. The “biomeinfo” mod is required for v6 mapgen support!=Nicht unterstützt. Die Mod „biomeinfo“ wird für Unterstützung des v6-Kartengenerators benötigt.
|
|
@ -0,0 +1,10 @@
|
||||||
|
# textdomain: findbiome
|
||||||
|
Find and teleport to biome=
|
||||||
|
<biome>=
|
||||||
|
No player.=
|
||||||
|
Biome does not exist!=
|
||||||
|
Biome found at @1.=
|
||||||
|
No biome found!=
|
||||||
|
List all biomes=
|
||||||
|
No biomes.=
|
||||||
|
Not supported. The “biomeinfo” mod is required for v6 mapgen support!=
|
|
@ -0,0 +1,3 @@
|
||||||
|
name=findbiome
|
||||||
|
description=Add commands to list and find biomes
|
||||||
|
optional_depends=biomeinfo
|
Loading…
Reference in New Issue