mirror of
https://github.com/minetest/minetest.git
synced 2024-11-26 17:43:45 +01:00
Add L-system trees as decorations (#14355)
This commit is contained in:
parent
f07e1026ac
commit
60810c2d37
@ -37,6 +37,7 @@ core.features = {
|
|||||||
blocking_pointability_type = true,
|
blocking_pointability_type = true,
|
||||||
dynamic_add_media_startup = true,
|
dynamic_add_media_startup = true,
|
||||||
dynamic_add_media_filepath = true,
|
dynamic_add_media_filepath = true,
|
||||||
|
lsystem_decoration_type = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
function core.has_feature(arg)
|
function core.has_feature(arg)
|
||||||
|
@ -4533,6 +4533,12 @@ Can specify a probability of a node randomly appearing when placed.
|
|||||||
This decoration type is intended to be used for multi-node sized discrete
|
This decoration type is intended to be used for multi-node sized discrete
|
||||||
structures, such as trees, cave spikes, rocks, and so on.
|
structures, such as trees, cave spikes, rocks, and so on.
|
||||||
|
|
||||||
|
`lsystem`
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Generates a L-system tree at the position where the decoration is placed.
|
||||||
|
Uses the same L-system as `minetest.spawn_tree`, but is faster than using it manually.
|
||||||
|
The `treedef` field in the decoration definition is used for the tree definition.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -5376,6 +5382,8 @@ Utilities
|
|||||||
dynamic_add_media_startup = true,
|
dynamic_add_media_startup = true,
|
||||||
-- dynamic_add_media supports `filename` and `filedata` parameters (5.9.0)
|
-- dynamic_add_media supports `filename` and `filedata` parameters (5.9.0)
|
||||||
dynamic_add_media_filepath = true,
|
dynamic_add_media_filepath = true,
|
||||||
|
-- L-system decoration type (5.9.0)
|
||||||
|
lsystem_decoration_type = true,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -10134,7 +10142,7 @@ See [Decoration types]. Used by `minetest.register_decoration`.
|
|||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
deco_type = "simple",
|
deco_type = "simple",
|
||||||
-- Type. "simple" or "schematic" supported
|
-- Type. "simple", "schematic" or "lsystem" supported
|
||||||
|
|
||||||
place_on = "default:dirt_with_grass",
|
place_on = "default:dirt_with_grass",
|
||||||
-- Node (or list of nodes) that the decoration can be placed on
|
-- Node (or list of nodes) that the decoration can be placed on
|
||||||
@ -10287,6 +10295,12 @@ See [Decoration types]. Used by `minetest.register_decoration`.
|
|||||||
-- Effect is inverted for "all_ceilings" decorations.
|
-- Effect is inverted for "all_ceilings" decorations.
|
||||||
-- Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer
|
-- Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer
|
||||||
-- to the 'place_on' node.
|
-- to the 'place_on' node.
|
||||||
|
|
||||||
|
----- L-system-type parameters
|
||||||
|
|
||||||
|
treedef = {},
|
||||||
|
-- Same as for `minetest.spawn_tree`.
|
||||||
|
-- See section [L-system trees] for more details.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "mapgen/treegen.h"
|
||||||
|
|
||||||
|
|
||||||
FlagDesc flagdesc_deco[] = {
|
FlagDesc flagdesc_deco[] = {
|
||||||
@ -472,3 +473,24 @@ size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceilin
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
ObjDef *DecoLSystem::clone() const
|
||||||
|
{
|
||||||
|
auto def = new DecoLSystem();
|
||||||
|
Decoration::cloneTo(def);
|
||||||
|
|
||||||
|
def->tree_def = tree_def;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t DecoLSystem::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
|
||||||
|
{
|
||||||
|
if (!canPlaceDecoration(vm, p))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Make sure that tree_def can't be modified, since it is shared.
|
||||||
|
const auto &ref = *tree_def;
|
||||||
|
return treegen::make_ltree(*vm, p, m_ndef, ref);
|
||||||
|
}
|
||||||
|
@ -31,6 +31,7 @@ class Mapgen;
|
|||||||
class MMVManip;
|
class MMVManip;
|
||||||
class PcgRandom;
|
class PcgRandom;
|
||||||
class Schematic;
|
class Schematic;
|
||||||
|
namespace treegen { struct TreeDef; }
|
||||||
|
|
||||||
enum DecorationType {
|
enum DecorationType {
|
||||||
DECO_SIMPLE,
|
DECO_SIMPLE,
|
||||||
@ -112,12 +113,15 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
class DecoLSystem : public Decoration {
|
class DecoLSystem : public Decoration {
|
||||||
public:
|
public:
|
||||||
virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
|
ObjDef *clone() const;
|
||||||
|
|
||||||
|
virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling);
|
||||||
|
|
||||||
|
// In case it gets cloned it uses the same tree def.
|
||||||
|
std::shared_ptr<treegen::TreeDef> tree_def;
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
class DecorationManager : public ObjDefManager {
|
class DecorationManager : public ObjDefManager {
|
||||||
@ -139,8 +143,8 @@ public:
|
|||||||
return new DecoSimple;
|
return new DecoSimple;
|
||||||
case DECO_SCHEMATIC:
|
case DECO_SCHEMATIC:
|
||||||
return new DecoSchematic;
|
return new DecoSchematic;
|
||||||
//case DECO_LSYSTEM:
|
case DECO_LSYSTEM:
|
||||||
// return new DecoLSystem;
|
return new DecoLSystem;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
namespace treegen
|
namespace treegen
|
||||||
{
|
{
|
||||||
|
|
||||||
|
void TreeDef::resolveNodeNames()
|
||||||
|
{
|
||||||
|
getIdFromNrBacklog(&trunknode.param0, "", CONTENT_IGNORE);
|
||||||
|
getIdFromNrBacklog(&leavesnode.param0, "", CONTENT_IGNORE);
|
||||||
|
if (leaves2_chance)
|
||||||
|
getIdFromNrBacklog(&leaves2node.param0, "", CONTENT_IGNORE);
|
||||||
|
if (fruit_chance)
|
||||||
|
getIdFromNrBacklog(&fruitnode.param0, "", CONTENT_IGNORE);
|
||||||
|
}
|
||||||
|
|
||||||
void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree,
|
void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree,
|
||||||
const NodeDefManager *ndef, s32 seed)
|
const NodeDefManager *ndef, s32 seed)
|
||||||
{
|
{
|
||||||
|
@ -35,7 +35,9 @@ namespace treegen {
|
|||||||
UNBALANCED_BRACKETS
|
UNBALANCED_BRACKETS
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TreeDef {
|
struct TreeDef : public NodeResolver {
|
||||||
|
virtual void resolveNodeNames();
|
||||||
|
|
||||||
std::string initial_axiom;
|
std::string initial_axiom;
|
||||||
std::string rules_a;
|
std::string rules_a;
|
||||||
std::string rules_b;
|
std::string rules_b;
|
||||||
|
@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "debug.h" // For FATAL_ERROR
|
#include "debug.h" // For FATAL_ERROR
|
||||||
#include <SColor.h>
|
#include <SColor.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
#include "mapgen/treegen.h"
|
||||||
|
|
||||||
struct EnumString es_TileAnimationType[] =
|
struct EnumString es_TileAnimationType[] =
|
||||||
{
|
{
|
||||||
@ -2006,6 +2007,51 @@ void push_noiseparams(lua_State *L, NoiseParams *np)
|
|||||||
lua_setfield(L, -2, "spread");
|
lua_setfield(L, -2, "spread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool read_tree_def(lua_State *L, int idx, const NodeDefManager *ndef,
|
||||||
|
treegen::TreeDef &tree_def)
|
||||||
|
{
|
||||||
|
std::string trunk, leaves, fruit;
|
||||||
|
if (!lua_istable(L, idx))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
getstringfield(L, idx, "axiom", tree_def.initial_axiom);
|
||||||
|
getstringfield(L, idx, "rules_a", tree_def.rules_a);
|
||||||
|
getstringfield(L, idx, "rules_b", tree_def.rules_b);
|
||||||
|
getstringfield(L, idx, "rules_c", tree_def.rules_c);
|
||||||
|
getstringfield(L, idx, "rules_d", tree_def.rules_d);
|
||||||
|
getstringfield(L, idx, "trunk", trunk);
|
||||||
|
tree_def.m_nodenames.push_back(trunk);
|
||||||
|
getstringfield(L, idx, "leaves", leaves);
|
||||||
|
tree_def.m_nodenames.push_back(leaves);
|
||||||
|
tree_def.leaves2_chance = 0;
|
||||||
|
getstringfield(L, idx, "leaves2", leaves);
|
||||||
|
if (!leaves.empty()) {
|
||||||
|
getintfield(L, idx, "leaves2_chance", tree_def.leaves2_chance);
|
||||||
|
if (tree_def.leaves2_chance)
|
||||||
|
tree_def.m_nodenames.push_back(leaves);
|
||||||
|
}
|
||||||
|
getintfield(L, idx, "angle", tree_def.angle);
|
||||||
|
getintfield(L, idx, "iterations", tree_def.iterations);
|
||||||
|
if (!getintfield(L, idx, "random_level", tree_def.iterations_random_level))
|
||||||
|
tree_def.iterations_random_level = 0;
|
||||||
|
getstringfield(L, idx, "trunk_type", tree_def.trunk_type);
|
||||||
|
getboolfield(L, idx, "thin_branches", tree_def.thin_branches);
|
||||||
|
tree_def.fruit_chance = 0;
|
||||||
|
getstringfield(L, idx, "fruit", fruit);
|
||||||
|
if (!fruit.empty()) {
|
||||||
|
getintfield(L, idx, "fruit_chance", tree_def.fruit_chance);
|
||||||
|
if (tree_def.fruit_chance)
|
||||||
|
tree_def.m_nodenames.push_back(fruit);
|
||||||
|
}
|
||||||
|
tree_def.explicit_seed = getintfield(L, idx, "seed", tree_def.seed);
|
||||||
|
|
||||||
|
// Resolves the node IDs for trunk, leaves, leaves2 and fruit at runtime,
|
||||||
|
// when tree_def.resolveNodeNames will be called.
|
||||||
|
ndef->pendNodeResolve(&tree_def);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// Returns depth of json value tree
|
// Returns depth of json value tree
|
||||||
static int push_json_value_getdepth(const Json::Value &value)
|
static int push_json_value_getdepth(const Json::Value &value)
|
||||||
|
@ -70,6 +70,7 @@ struct NoiseParams;
|
|||||||
class Schematic;
|
class Schematic;
|
||||||
class ServerActiveObject;
|
class ServerActiveObject;
|
||||||
struct collisionMoveResult;
|
struct collisionMoveResult;
|
||||||
|
namespace treegen { struct TreeDef; }
|
||||||
|
|
||||||
extern struct EnumString es_TileAnimationType[];
|
extern struct EnumString es_TileAnimationType[];
|
||||||
|
|
||||||
@ -189,6 +190,10 @@ bool read_noiseparams (lua_State *L, int index,
|
|||||||
NoiseParams *np);
|
NoiseParams *np);
|
||||||
void push_noiseparams (lua_State *L, NoiseParams *np);
|
void push_noiseparams (lua_State *L, NoiseParams *np);
|
||||||
|
|
||||||
|
bool read_tree_def (lua_State *L, int idx,
|
||||||
|
const NodeDefManager *ndef,
|
||||||
|
treegen::TreeDef &tree_def);
|
||||||
|
|
||||||
void luaentity_get (lua_State *L,u16 id);
|
void luaentity_get (lua_State *L,u16 id);
|
||||||
|
|
||||||
bool push_json_value (lua_State *L,
|
bool push_json_value (lua_State *L,
|
||||||
|
@ -1331,45 +1331,6 @@ int ModApiEnv::l_find_path(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_tree_def(lua_State *L, int idx,
|
|
||||||
const NodeDefManager *ndef, treegen::TreeDef &tree_def)
|
|
||||||
{
|
|
||||||
std::string trunk, leaves, fruit;
|
|
||||||
if (!lua_istable(L, idx))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
getstringfield(L, idx, "axiom", tree_def.initial_axiom);
|
|
||||||
getstringfield(L, idx, "rules_a", tree_def.rules_a);
|
|
||||||
getstringfield(L, idx, "rules_b", tree_def.rules_b);
|
|
||||||
getstringfield(L, idx, "rules_c", tree_def.rules_c);
|
|
||||||
getstringfield(L, idx, "rules_d", tree_def.rules_d);
|
|
||||||
getstringfield(L, idx, "trunk", trunk);
|
|
||||||
tree_def.trunknode = ndef->getId(trunk);
|
|
||||||
getstringfield(L, idx, "leaves", leaves);
|
|
||||||
tree_def.leavesnode = ndef->getId(leaves);
|
|
||||||
tree_def.leaves2_chance = 0;
|
|
||||||
getstringfield(L, idx, "leaves2", leaves);
|
|
||||||
if (!leaves.empty()) {
|
|
||||||
tree_def.leaves2node = ndef->getId(leaves);
|
|
||||||
getintfield(L, idx, "leaves2_chance", tree_def.leaves2_chance);
|
|
||||||
}
|
|
||||||
getintfield(L, idx, "angle", tree_def.angle);
|
|
||||||
getintfield(L, idx, "iterations", tree_def.iterations);
|
|
||||||
if (!getintfield(L, idx, "random_level", tree_def.iterations_random_level))
|
|
||||||
tree_def.iterations_random_level = 0;
|
|
||||||
getstringfield(L, idx, "trunk_type", tree_def.trunk_type);
|
|
||||||
getboolfield(L, idx, "thin_branches", tree_def.thin_branches);
|
|
||||||
tree_def.fruit_chance = 0;
|
|
||||||
getstringfield(L, idx, "fruit", fruit);
|
|
||||||
if (!fruit.empty()) {
|
|
||||||
tree_def.fruitnode = ndef->getId(fruit);
|
|
||||||
getintfield(L, idx, "fruit_chance", tree_def.fruit_chance);
|
|
||||||
}
|
|
||||||
tree_def.explicit_seed = getintfield(L, idx, "seed", tree_def.seed);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// spawn_tree(pos, treedef)
|
// spawn_tree(pos, treedef)
|
||||||
int ModApiEnv::l_spawn_tree(lua_State *L)
|
int ModApiEnv::l_spawn_tree(lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "mapgen/mg_schematic.h"
|
#include "mapgen/mg_schematic.h"
|
||||||
#include "mapgen/mapgen_v5.h"
|
#include "mapgen/mapgen_v5.h"
|
||||||
#include "mapgen/mapgen_v7.h"
|
#include "mapgen/mapgen_v7.h"
|
||||||
|
#include "mapgen/treegen.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -110,6 +111,7 @@ bool read_schematic_def(lua_State *L, int index,
|
|||||||
|
|
||||||
bool read_deco_simple(lua_State *L, DecoSimple *deco);
|
bool read_deco_simple(lua_State *L, DecoSimple *deco);
|
||||||
bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco);
|
bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco);
|
||||||
|
bool read_deco_lsystem(lua_State *L, const NodeDefManager *ndef, DecoLSystem *deco);
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1226,6 +1228,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
|
|||||||
success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco);
|
success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco);
|
||||||
break;
|
break;
|
||||||
case DECO_LSYSTEM:
|
case DECO_LSYSTEM:
|
||||||
|
success = read_deco_lsystem(L, ndef, (DecoLSystem *)deco);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1308,6 +1311,17 @@ bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic
|
|||||||
return schem != NULL;
|
return schem != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool read_deco_lsystem(lua_State *L, const NodeDefManager *ndef, DecoLSystem *deco)
|
||||||
|
{
|
||||||
|
deco->tree_def = std::make_shared<treegen::TreeDef>();
|
||||||
|
|
||||||
|
lua_getfield(L, 1, "treedef");
|
||||||
|
bool has_def = read_tree_def(L, -1, ndef, *(deco->tree_def));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return has_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// register_ore({lots of stuff})
|
// register_ore({lots of stuff})
|
||||||
int ModApiMapgen::l_register_ore(lua_State *L)
|
int ModApiMapgen::l_register_ore(lua_State *L)
|
||||||
|
Loading…
Reference in New Issue
Block a user