Add findbiome mod

This commit is contained in:
Wuzzy 2020-04-03 12:51:01 +02:00
parent b2c8d7cff0
commit c9b464f329
6 changed files with 390 additions and 0 deletions

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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!=

View file

@ -0,0 +1,3 @@
name=findbiome
description=Add commands to list and find biomes
optional_depends=biomeinfo