Rewrite generate notification mechanism

Add support for notify-on-decoration
Clean up mapgen constructors
Clean up mapgen.cpp code style somewhat
Remove trailing whitespace from some files
This commit is contained in:
kwolekr 2014-12-06 04:18:04 -05:00
parent 2b119e1e19
commit 5062b99cb0
19 changed files with 436 additions and 329 deletions

@ -1533,10 +1533,11 @@ minetest.get_perlin(seeddiff, octaves, persistence, scale)
^ Return world-specific perlin noise (int(worldseed)+seeddiff)
minetest.get_voxel_manip()
^ Return voxel manipulator object
minetest.set_gen_notify(flags)
minetest.set_gen_notify(flags, {deco_ids})
^ Set the types of on-generate notifications that should be collected
^ flags is a comma-delimited combination of:
^ dungeon, temple, cave_begin, cave_end, large_cave_begin, large_cave_end
^ flags is a flag field with the available flags:
^ dungeon, temple, cave_begin, cave_end, large_cave_begin, large_cave_end, decoration
^ The second parameter is a list of IDS of decorations which notification is requested for
minetest.get_mapgen_object(objectname)
^ Return requested mapgen object if available (see Mapgen objects)
minetest.set_mapgen_params(MapgenParams)
@ -2220,7 +2221,9 @@ current mapgen.
Returns a table mapping requested generation notification types to arrays of positions at which the
corresponding generated structures are located at within the current chunk. To set the capture of positions
of interest to be recorded on generate, use minetest.set_gen_notify().
Possible fields of the table returned are: dungeon, temple, cave_begin, cave_end, large_cave_begin, large_cave_end
Possible fields of the table returned are:
dungeon, temple, cave_begin, cave_end, large_cave_begin, large_cave_end, decoration
Decorations have a key in the format of "decoration#id", where id is the numeric unique decoration ID.
Registered entities
--------------------

@ -45,7 +45,7 @@ CaveV6::CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_
max_tunnel_diameter = ps->range(2, 6);
dswitchint = ps->range(1, 14);
flooded = true;
if (large_cave) {
part_max_length_rs = ps->range(2,4);
tunnel_routepoints = ps->range(5, ps->range(15,30));
@ -55,7 +55,7 @@ CaveV6::CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_
part_max_length_rs = ps->range(2,9);
tunnel_routepoints = ps->range(10, ps->range(15,30));
}
large_cave_is_flat = (ps->range(0,1) == 0);
}
@ -109,21 +109,21 @@ void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
(float)(ps->next() % ar.Z) + 0.5
);
int notifytype = large_cave ? GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
if (mg->gennotify & (1 << notifytype)) {
std::vector <v3s16> *nvec = mg->gen_notifications[notifytype];
nvec->push_back(v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z));
}
// Add generation notify begin event
v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
GenNotifyType notifytype = large_cave ?
GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
mg->gennotify.addEvent(notifytype, abs_pos);
// Generate some tunnel starting from orp
for (u16 j = 0; j < tunnel_routepoints; j++)
makeTunnel(j % dswitchint == 0);
notifytype = large_cave ? GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
if (mg->gennotify & (1 << notifytype)) {
std::vector <v3s16> *nvec = mg->gen_notifications[notifytype];
nvec->push_back(v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z));
}
// Add generation notify end event
abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
notifytype = large_cave ?
GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
mg->gennotify.addEvent(notifytype, abs_pos);
}
@ -179,31 +179,31 @@ void CaveV6::makeTunnel(bool dirswitch) {
rp.X = 0;
else if (rp.X >= ar.X)
rp.X = ar.X - 1;
if (rp.Y < route_y_min)
rp.Y = route_y_min;
else if (rp.Y >= route_y_max)
rp.Y = route_y_max - 1;
if (rp.Z < 0)
rp.Z = 0;
else if (rp.Z >= ar.Z)
rp.Z = ar.Z - 1;
vec = rp - orp;
float veclen = vec.getLength();
// As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
if (veclen < 0.05)
veclen = 1.0;
// Every second section is rough
bool randomize_xz = (ps2->range(1, 2) == 1);
// Carve routes
for (float f = 0; f < 1.0; f += 1.0 / veclen)
carveRoute(vec, f, randomize_xz);
orp = rp;
}
@ -212,10 +212,10 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
MapNode airnode(CONTENT_AIR);
MapNode waternode(c_water_source);
MapNode lavanode(c_lava_source);
v3s16 startp(orp.X, orp.Y, orp.Z);
startp += of;
v3f fp = orp + vec * f;
fp.X += 0.1 * ps->range(-10, 10);
fp.Z += 0.1 * ps->range(-10, 10);
@ -227,13 +227,13 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
d0 += ps->range(-1, 1);
d1 += ps->range(-1, 1);
}
for (s16 z0 = d0; z0 <= d1; z0++) {
s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
s16 maxabsxz = MYMAX(abs(x0), abs(z0));
s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
for (s16 y0 = -si2; y0 <= si2; y0++) {
for (s16 y0 = -si2; y0 <= si2; y0++) {
if (large_cave_is_flat) {
// Make large caves not so tall
if (rs > 7 && abs(y0) >= rs / 3)
@ -293,7 +293,7 @@ CaveV7::CaveV7(MapgenV7 *mg, PseudoRandom *ps, bool is_large_cave) {
dswitchint = ps->range(1, 14);
flooded = ps->range(1, 2) == 2;
if (large_cave) {
part_max_length_rs = ps->range(2, 4);
tunnel_routepoints = ps->range(5, ps->range(15, 30));
@ -305,7 +305,7 @@ CaveV7::CaveV7(MapgenV7 *mg, PseudoRandom *ps, bool is_large_cave) {
min_tunnel_diameter = 2;
max_tunnel_diameter = ps->range(2, 6);
}
large_cave_is_flat = (ps->range(0, 1) == 0);
}
@ -358,21 +358,21 @@ void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
(float)(ps->next() % ar.Z) + 0.5
);
int notifytype = large_cave ? GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
if (mg->gennotify & (1 << notifytype)) {
std::vector <v3s16> *nvec = mg->gen_notifications[notifytype];
nvec->push_back(v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z));
}
// Add generation notify begin event
v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
GenNotifyType notifytype = large_cave ?
GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
mg->gennotify.addEvent(notifytype, abs_pos);
// Generate some tunnel starting from orp
for (u16 j = 0; j < tunnel_routepoints; j++)
makeTunnel(j % dswitchint == 0);
notifytype = large_cave ? GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
if (mg->gennotify & (1 << notifytype)) {
std::vector <v3s16> *nvec = mg->gen_notifications[notifytype];
nvec->push_back(v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z));
}
// Add generation notify end event
abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
notifytype = large_cave ?
GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
mg->gennotify.addEvent(notifytype, abs_pos);
}
@ -428,7 +428,7 @@ void CaveV7::makeTunnel(bool dirswitch) {
v3s16 orpi(orp.X, orp.Y, orp.Z);
v3s16 veci(vec.X, vec.Y, vec.Z);
v3s16 p;
p = orpi + veci + of + rs / 2;
if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
p.X >= node_min.X && p.X <= node_max.X) {
@ -439,7 +439,7 @@ void CaveV7::makeTunnel(bool dirswitch) {
} else if (p.Y > water_level) {
return; // If it's not in our heightmap, use a simple heuristic
}
p = orpi + of + rs / 2;
if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
p.X >= node_min.X && p.X <= node_max.X) {
@ -447,7 +447,7 @@ void CaveV7::makeTunnel(bool dirswitch) {
s16 h = mg->ridge_heightmap[index];
if (h < p.Y)
return;
} else if (p.Y > water_level) {
} else if (p.Y > water_level) {
return;
}
}
@ -459,23 +459,23 @@ void CaveV7::makeTunnel(bool dirswitch) {
rp.X = 0;
else if (rp.X >= ar.X)
rp.X = ar.X - 1;
if (rp.Y < route_y_min)
rp.Y = route_y_min;
else if (rp.Y >= route_y_max)
rp.Y = route_y_max - 1;
if (rp.Z < 0)
rp.Z = 0;
else if (rp.Z >= ar.Z)
rp.Z = ar.Z - 1;
vec = rp - orp;
float veclen = vec.getLength();
if (veclen < 0.05)
veclen = 1.0;
// Every second section is rough
bool randomize_xz = (ps->range(1, 2) == 1);
@ -487,7 +487,7 @@ void CaveV7::makeTunnel(bool dirswitch) {
// Carve routes
for (float f = 0; f < 1.0; f += 1.0 / veclen)
carveRoute(vec, f, randomize_xz, is_ravine);
orp = rp;
}
@ -496,14 +496,14 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
MapNode airnode(CONTENT_AIR);
MapNode waternode(c_water_source);
MapNode lavanode(c_lava_source);
v3s16 startp(orp.X, orp.Y, orp.Z);
startp += of;
float nval = NoisePerlin3D(np_caveliquids, startp.X,
startp.Y, startp.Z, mg->seed);
MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
v3f fp = orp + vec * f;
fp.X += 0.1 * ps->range(-10, 10);
fp.Z += 0.1 * ps->range(-10, 10);
@ -515,23 +515,23 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
d0 += ps->range(-1, 1);
d1 += ps->range(-1, 1);
}
bool flat_cave_floor = !large_cave && ps->range(0, 2) == 2;
bool should_make_cave_hole = ps->range(1, 10) == 1;
for (s16 z0 = d0; z0 <= d1; z0++) {
s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
s16 maxabsxz = MYMAX(abs(x0), abs(z0));
s16 si2 = is_ravine ? MYMIN(ps->range(25, 26), ar.Y) :
rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
for (s16 y0 = -si2; y0 <= si2; y0++) {
// Make better floors in small caves
if(flat_cave_floor && y0 <= -rs/2 && rs<=7)
continue;
if (large_cave_is_flat) {
// Make large caves not so tall
if (rs > 7 && abs(y0) >= rs / 3)
@ -540,7 +540,7 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
p += of;
if (!is_ravine && mg->heightmap && should_make_cave_hole &&
p.X <= node_max.X && p.Z <= node_max.Z) {
int maplen = node_max.X - node_min.X + 1;
@ -553,13 +553,13 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
continue;
u32 i = vm->m_area.index(p);
// Don't replace air, water, lava, or ice
content_t c = vm->m_data[i].getContent();
if (!ndef->get(c).is_ground_content || c == CONTENT_AIR ||
c == c_water_source || c == c_lava_source || c == c_ice)
continue;
if (large_cave) {
int full_ymin = node_min.Y - MAP_BLOCKSIZE;
int full_ymax = node_max.Y + MAP_BLOCKSIZE;
@ -573,7 +573,7 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
} else {
if (c == CONTENT_IGNORE)
continue;
vm->m_data[i] = airnode;
vm->m_flags[i] |= VMANIP_FLAG_CAVE;
}

@ -46,7 +46,7 @@ DungeonGen::DungeonGen(Mapgen *mapgen, DungeonParams *dparams) {
#ifdef DGEN_USE_TORCHES
c_torch = ndef->getId("default:torch");
#endif
if (dparams) {
memcpy(&dp, dparams, sizeof(dp));
} else {
@ -95,7 +95,7 @@ void DungeonGen::generate(u32 bseed, v3s16 nmin, v3s16 nmax) {
}
}
}
// Add it
makeDungeon(v3s16(1,1,1) * MAP_BLOCKSIZE);
@ -115,7 +115,7 @@ void DungeonGen::generate(u32 bseed, v3s16 nmin, v3s16 nmax) {
}
}
}
//printf("== gen dungeons: %dms\n", t.stop());
}
@ -144,7 +144,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
random.range(0,areasize.X-roomsize.X-1-start_padding.X),
random.range(0,areasize.Y-roomsize.Y-1-start_padding.Y),
random.range(0,areasize.Z-roomsize.Z-1-start_padding.Z));
/*
Check that we're not putting the room to an unknown place,
otherwise it might end up floating in the air
@ -181,10 +181,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
makeRoom(roomsize, roomplace);
v3s16 room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2);
if (mg->gennotify & (1 << dp.notifytype)) {
std::vector <v3s16> *nvec = mg->gen_notifications[dp.notifytype];
nvec->push_back(room_center);
}
mg->gennotify.addEvent(dp.notifytype, room_center);
#ifdef DGEN_USE_TORCHES
// Place torch at room center (for testing)
@ -212,7 +209,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
// Create walker and find a place for a door
v3s16 doorplace;
v3s16 doordir;
m_pos = walker_start_place;
if (!findPlaceForDoor(doorplace, doordir))
return;
@ -253,7 +250,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
{
MapNode n_cobble(dp.c_cobble);
MapNode n_air(CONTENT_AIR);
// Make +-X walls
for (s16 z = 0; z < roomsize.Z; z++)
for (s16 y = 0; y < roomsize.Y; y++)
@ -393,10 +390,10 @@ void DungeonGen::makeCorridor(v3s16 doorplace,
u32 partlength = random.range(1, 13);
u32 partcount = 0;
s16 make_stairs = 0;
if (random.next() % 2 == 0 && partlength >= 3)
make_stairs = random.next() % 2 ? 1 : -1;
for (u32 i = 0; i < length; i++) {
v3s16 p = p0 + dir;
if (partcount != 0)
@ -409,7 +406,7 @@ void DungeonGen::makeCorridor(v3s16 doorplace,
VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(dp.c_cobble), 0);
makeHole(p);
makeHole(p - dir);
// TODO: fix stairs code so it works 100% (quite difficult)
// exclude stairs from the bottom step
@ -419,11 +416,11 @@ void DungeonGen::makeCorridor(v3s16 doorplace,
((make_stairs == -1) && i != length - 1))) {
// rotate face 180 deg if making stairs backwards
int facedir = dir_to_facedir(dir * make_stairs);
u32 vi = vm->m_area.index(p.X - dir.X, p.Y - 1, p.Z - dir.Z);
if (vm->m_data[vi].getContent() == dp.c_cobble)
vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
vi = vm->m_area.index(p.X, p.Y, p.Z);
if (vm->m_data[vi].getContent() == dp.c_cobble)
vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "voxel.h"
#include "noise.h"
#include "mapgen.h"
#define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
#define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
@ -30,7 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ManualMapVoxelManipulator;
class INodeDefManager;
class Mapgen;
v3s16 rand_ortho_dir(PseudoRandom &random, bool diagonal_dirs);
v3s16 turn_xz(v3s16 olddir, int t);
@ -44,7 +44,7 @@ struct DungeonParams {
content_t c_moss;
content_t c_stair;
int notifytype;
GenNotifyType notifytype;
bool diagonal_dirs;
float mossratio;
v3s16 holesize;
@ -65,14 +65,14 @@ public:
content_t c_torch;
DungeonParams dp;
//RoomWalker
v3s16 m_pos;
v3s16 m_dir;
DungeonGen(Mapgen *mg, DungeonParams *dparams);
void generate(u32 bseed, v3s16 full_node_min, v3s16 full_node_max);
void makeDungeon(v3s16 start_padding);
void makeRoom(v3s16 roomsize, v3s16 roomplace);
void makeCorridor(v3s16 doorplace, v3s16 doordir,
@ -84,7 +84,7 @@ public:
bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir);
bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
v3s16 &result_doordir, v3s16 &result_roomplace);
void randomizeDir()
{
m_dir = rand_ortho_dir(random, dp.diagonal_dirs);

@ -94,7 +94,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef) {
this->oremgr = new OreManager(gamedef);
this->decomgr = new DecorationManager(gamedef);
this->schemmgr = new SchematicManager(gamedef);
this->gennotify = 0;
this->gen_notify_on = 0;
// Note that accesses to this variable are not synchronized.
// This is because the *only* thread ever starting or stopping

@ -89,7 +89,8 @@ public:
u16 qlimit_diskonly;
u16 qlimit_generate;
u32 gennotify;
u32 gen_notify_on;
std::set<u32> gen_notify_on_deco_ids;
//// Block emerge queue data structures
JMutex queuemutex;

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "content_sao.h"
#include "nodedef.h"
#include "emerge.h"
#include "content_mapnode.h" // For content_mapnode_get_new_name
#include "voxelalgorithms.h"
#include "profiler.h"
@ -55,36 +56,53 @@ FlagDesc flagdesc_gennotify[] = {
{"cave_end", 1 << GENNOTIFY_CAVE_END},
{"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN},
{"large_cave_end", 1 << GENNOTIFY_LARGECAVE_END},
{"decoration", 1 << GENNOTIFY_DECORATION},
{NULL, 0}
};
///////////////////////////////////////////////////////////////////////////////
Mapgen::Mapgen()
{
generating = false;
id = -1;
seed = 0;
water_level = 0;
flags = 0;
Mapgen::Mapgen() {
seed = 0;
water_level = 0;
generating = false;
id = -1;
vm = NULL;
ndef = NULL;
heightmap = NULL;
biomemap = NULL;
for (unsigned int i = 0; i != NUM_GEN_NOTIFY; i++)
gen_notifications[i] = new std::vector<v3s16>;
}
Mapgen::~Mapgen() {
for (unsigned int i = 0; i != NUM_GEN_NOTIFY; i++)
delete gen_notifications[i];
Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
{
generating = false;
id = mapgenid;
seed = (int)params->seed;
water_level = params->water_level;
flags = params->flags;
csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
vm = NULL;
ndef = NULL;
heightmap = NULL;
biomemap = NULL;
}
Mapgen::~Mapgen()
{
}
// Returns Y one under area minimum if not found
s16 Mapgen::findGroundLevelFull(v2s16 p2d) {
s16 Mapgen::findGroundLevelFull(v2s16 p2d)
{
v3s16 em = vm->m_area.getExtent();
s16 y_nodes_max = vm->m_area.MaxEdge.Y;
s16 y_nodes_min = vm->m_area.MinEdge.Y;
@ -102,7 +120,8 @@ s16 Mapgen::findGroundLevelFull(v2s16 p2d) {
}
s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax) {
s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
{
v3s16 em = vm->m_area.getExtent();
u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
s16 y;
@ -118,7 +137,8 @@ s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax) {
}
void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) {
void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
{
if (!heightmap)
return;
@ -141,7 +161,8 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) {
}
void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax) {
void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
{
bool isliquid, wasliquid;
v3s16 em = vm->m_area.getExtent();
@ -165,7 +186,8 @@ void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nm
}
void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) {
void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light)
{
ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
VoxelArea a(nmin, nmax);
@ -179,7 +201,8 @@ void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) {
}
void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) {
void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
{
if (light <= 1 || !a.contains(p))
return;
@ -202,7 +225,8 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) {
}
void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) {
void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax)
{
VoxelArea a(nmin, nmax);
bool block_is_underground = (water_level >= nmax.Y);
@ -264,7 +288,8 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) {
}
void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) {
void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax)
{
enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
VoxelArea a(nmin, nmax);
bool block_is_underground = (water_level > nmax.Y);
@ -287,6 +312,72 @@ void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) {
}
///////////////////////////////////////////////////////////////////////////////
GenerateNotifier::GenerateNotifier()
{
}
GenerateNotifier::GenerateNotifier(u32 notify_on,
std::set<u32> *notify_on_deco_ids)
{
m_notify_on = notify_on;
m_notify_on_deco_ids = notify_on_deco_ids;
}
void GenerateNotifier::setNotifyOn(u32 notify_on)
{
m_notify_on = notify_on;
}
void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
{
m_notify_on_deco_ids = notify_on_deco_ids;
}
bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
{
if (!(m_notify_on & (1 << type)))
return false;
if (type == GENNOTIFY_DECORATION &&
m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
return false;
GenNotifyEvent gne;
gne.type = type;
gne.pos = pos;
gne.id = id;
m_notify_events.push_back(gne);
return true;
}
void GenerateNotifier::getEvents(
std::map<std::string, std::vector<v3s16> > &event_map,
bool peek_events)
{
std::list<GenNotifyEvent>::iterator it;
for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
GenNotifyEvent &gn = *it;
std::string name = (gn.type == GENNOTIFY_DECORATION) ?
"decoration#"+ itos(gn.id) :
flagdesc_gennotify[gn.type].name;
event_map[name].push_back(gn.pos);
}
if (!peek_events)
m_notify_events.clear();
}
///////////////////////////////////////////////////////////////////////////////

@ -34,8 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MG_FLAT 0x08
#define MG_LIGHT 0x10
#define NUM_GEN_NOTIFY 6
class Settings;
class ManualMapVoxelManipulator;
class INodeDefManager;
@ -61,13 +59,39 @@ enum MapgenObject {
MGOBJ_GENNOTIFY
};
enum GenNotify {
enum GenNotifyType {
GENNOTIFY_DUNGEON,
GENNOTIFY_TEMPLE,
GENNOTIFY_CAVE_BEGIN,
GENNOTIFY_CAVE_END,
GENNOTIFY_LARGECAVE_BEGIN,
GENNOTIFY_LARGECAVE_END
GENNOTIFY_LARGECAVE_END,
GENNOTIFY_DECORATION,
NUM_GENNOTIFY_TYPES
};
struct GenNotifyEvent {
GenNotifyType type;
v3s16 pos;
u32 id;
};
class GenerateNotifier {
public:
GenerateNotifier();
GenerateNotifier(u32 notify_on, std::set<u32> *notify_on_deco_ids);
void setNotifyOn(u32 notify_on);
void setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids);
bool addEvent(GenNotifyType type, v3s16 pos, u32 id=0);
void getEvents(std::map<std::string, std::vector<v3s16> > &event_map,
bool peek_events=false);
private:
u32 m_notify_on;
std::set<u32> *m_notify_on_deco_ids;
std::list<GenNotifyEvent> m_notify_events;
};
struct MapgenSpecificParams {
@ -85,7 +109,8 @@ struct MapgenParams {
MapgenSpecificParams *sparams;
MapgenParams() {
MapgenParams()
{
mg_name = DEFAULT_MAPGEN;
seed = 0;
water_level = 1;
@ -99,6 +124,7 @@ class Mapgen {
public:
int seed;
int water_level;
u32 flags;
bool generating;
int id;
ManualMapVoxelManipulator *vm;
@ -108,10 +134,10 @@ public:
u8 *biomemap;
v3s16 csize;
u32 gennotify;
std::vector<v3s16> *gen_notifications[NUM_GEN_NOTIFY];
GenerateNotifier gennotify;
Mapgen();
Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge);
virtual ~Mapgen();
s16 findGroundLevelFull(v2s16 p2d);

@ -39,7 +39,8 @@ void MapgenSinglenodeParams::writeParams(Settings *settings) {
///////////////////////////////////////////////////////////////////////////////
MapgenSinglenode::MapgenSinglenode(int mapgenid,
MapgenParams *params, EmergeManager *emerge)
MapgenParams *params, EmergeManager *emerge)
: Mapgen(mapgenid, params, emerge)
{
flags = params->flags;
@ -67,18 +68,18 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data) {
data->blockpos_requested.Z <= data->blockpos_max.Z);
this->generating = true;
this->vm = data->vmanip;
this->vm = data->vmanip;
this->ndef = data->nodedef;
v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max;
// Area of central chunk
v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
MapNode n_node(c_node);
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 y = node_min.Y; y <= node_max.Y; y++) {
u32 i = vm->m_area.index(node_min.X, y, z);
@ -96,7 +97,7 @@ void MapgenSinglenode::makeChunk(BlockMakeData *data) {
if (flags & MG_LIGHT)
calcLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
this->generating = false;
}

@ -47,19 +47,12 @@ FlagDesc flagdesc_mapgen_v5[] = {
};
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_) {
this->generating = false;
this->id = mapgenid;
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_)
: Mapgen(mapgenid, params, emerge)
{
this->emerge = emerge_;
this->bmgr = emerge->biomemgr;
this->seed = (int)params->seed;
this->water_level = params->water_level;
this->flags = params->flags;
this->gennotify = emerge->gennotify;
this->csize = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE;
// amount of elements to skip for the next index
// for noise/height/biome maps (not vmanip)
this->ystride = csize.X;
@ -69,8 +62,7 @@ MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_) {
this->heightmap = new s16[csize.X * csize.Z];
MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
this->spflags = sp->spflags;
this->spflags = sp->spflags;
// Terrain noise
noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
@ -129,7 +121,7 @@ MapgenV5::~MapgenV5() {
delete noise_heat;
delete noise_humidity;
delete[] heightmap;
delete[] biomemap;
}
@ -234,12 +226,12 @@ void MapgenV5::makeChunk(BlockMakeData *data) {
assert(data->blockpos_requested.X <= data->blockpos_max.X &&
data->blockpos_requested.Y <= data->blockpos_max.Y &&
data->blockpos_requested.Z <= data->blockpos_max.Z);
generating = true;
vm = data->vmanip;
vm = data->vmanip;
ndef = data->nodedef;
//TimeTaker t("makeChunk");
v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max;
node_min = blockpos_min * MAP_BLOCKSIZE;
@ -249,7 +241,7 @@ void MapgenV5::makeChunk(BlockMakeData *data) {
// Create a block-specific seed
blockseed = emerge->getBlockSeed(full_node_min); //////use getBlockSeed2()!
// Make some noise
calculateNoise();
@ -265,7 +257,7 @@ void MapgenV5::makeChunk(BlockMakeData *data) {
// Calculate biomes
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
noise_humidity->result, heightmap, biomemap);
// Actually place the biome-specific nodes
generateBiomes();
@ -288,12 +280,12 @@ void MapgenV5::makeChunk(BlockMakeData *data) {
// Add top and bottom side of water to transforming_liquid queue
updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
// Calculate lighting
if (flags & MG_LIGHT)
calcLighting(node_min - v3s16(0, 1, 0) - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
node_max + v3s16(0, 1, 0) + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
this->generating = false;
}
@ -303,7 +295,7 @@ void MapgenV5::calculateNoise() {
int x = node_min.X;
int y = node_min.Y - 1;
int z = node_min.Z;
noise_filler_depth->perlinMap2D(x, z);
noise_factor->perlinMap2D(x, z);
noise_height->perlinMap2D(x, z);
@ -426,20 +418,20 @@ void MapgenV5::generateBiomes() {
v3s16 em = vm->m_area.getExtent();
u32 index = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
Biome *biome = (Biome *)bmgr->get(biomemap[index]);
s16 dfiller = biome->depth_filler + noise_filler_depth->result[index];
s16 y0_top = biome->depth_top;
s16 y0_filler = biome->depth_top + dfiller;
s16 nplaced = 0;
u32 i = vm->m_area.index(x, node_max.Y, z);
u32 i = vm->m_area.index(x, node_max.Y, z);
content_t c_above = vm->m_data[i + em.X].getContent();
bool have_air = c_above == CONTENT_AIR;
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
content_t c = vm->m_data[i].getContent();
bool is_replaceable_content =
@ -448,7 +440,7 @@ void MapgenV5::generateBiomes() {
if (is_replaceable_content && have_air) {
content_t c_below = vm->m_data[i - em.X].getContent();
if (c_below != CONTENT_AIR) {
if (nplaced < y0_top) {
if(y < water_level)
@ -484,7 +476,7 @@ void MapgenV5::generateBiomes() {
have_air = true;
nplaced = 0;
}
vm->m_area.add_y(em, i, -1);
}
}
@ -493,14 +485,14 @@ void MapgenV5::generateBiomes() {
void MapgenV5::dustTopNodes() {
v3s16 em = vm->m_area.getExtent();
u32 index = 0;
if (water_level > node_max.Y)
return;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
Biome *biome = (Biome *)bmgr->get(biomemap[index]);
if (biome->c_dust == CONTENT_IGNORE)
continue;
@ -512,18 +504,18 @@ void MapgenV5::dustTopNodes() {
vm->m_area.add_y(em, vi, -1);
}
content_t c = vm->m_data[vi].getContent();
if (c == biome->c_water && biome->c_dust_water != CONTENT_IGNORE) {
if (y < node_min.Y - 1)
continue;
vm->m_data[vi] = MapNode(biome->c_dust_water);
} else if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE
&& c != biome->c_dust) {
if (y == node_max.Y + 1)
continue;
vm->m_area.add_y(em, vi, 1);
vm->m_data[vi] = MapNode(biome->c_dust);
}

@ -41,7 +41,7 @@ struct MapgenV5Params : public MapgenSpecificParams {
MapgenV5Params();
~MapgenV5Params() {}
void readParams(Settings *settings);
void writeParams(Settings *settings);
};
@ -54,7 +54,6 @@ public:
int ystride;
int zstride;
u32 flags;
u32 spflags;
u32 blockseed;
@ -62,7 +61,7 @@ public:
v3s16 node_max;
v3s16 full_node_min;
v3s16 full_node_max;
Noise *noise_filler_depth;
Noise *noise_factor;
Noise *noise_height;
@ -92,7 +91,7 @@ public:
MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_);
~MapgenV5();
virtual void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
void calculateNoise();
@ -107,7 +106,7 @@ struct MapgenFactoryV5 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV5(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams() {
return new MapgenV5Params();
};

@ -49,21 +49,13 @@ FlagDesc flagdesc_mapgen_v6[] = {
///////////////////////////////////////////////////////////////////////////////
MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge) {
this->generating = false;
this->id = mapgenid;
this->emerge = emerge;
this->seed = (int)params->seed;
this->water_level = params->water_level;
this->flags = params->flags;
this->csize = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE;
this->gennotify = emerge->gennotify;
MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge)
: Mapgen(mapgenid, params, emerge)
{
this->emerge = emerge;
this->ystride = csize.X; //////fix this
MapgenV6Params *sp = (MapgenV6Params *)params->sparams;
MapgenV6Params *sp = (MapgenV6Params *)params->sparams;
this->spflags = sp->spflags;
this->freq_desert = sp->freq_desert;
this->freq_beach = sp->freq_beach;
@ -224,7 +216,7 @@ bool MapgenV6::block_is_underground(u64 seed, v3s16 blockpos)
//////////////////////// Base terrain height functions
float MapgenV6::baseTerrainLevel(float terrain_base, float terrain_higher,
float steepness, float height_select) {
float steepness, float height_select) {
float base = 1 + terrain_base;
float higher = 1 + terrain_higher;
@ -245,7 +237,7 @@ float MapgenV6::baseTerrainLevel(float terrain_base, float terrain_higher,
float a_off = -0.20; // Offset to more low
float a = 0.5 + b * (a_off + height_select);
a = rangelim(a, 0.0, 1.0); // Limit
return base * (1.0 - a) + higher * a;
}
@ -253,7 +245,7 @@ float MapgenV6::baseTerrainLevel(float terrain_base, float terrain_higher,
float MapgenV6::baseTerrainLevelFromNoise(v2s16 p) {
if (flags & MG_FLAT)
return water_level;
float terrain_base = NoisePerlin2DPosOffset(noise_terrain_base->np,
p.X, 0.5, p.Y, 0.5, seed);
float terrain_higher = NoisePerlin2DPosOffset(noise_terrain_higher->np,
@ -277,12 +269,12 @@ float MapgenV6::baseTerrainLevelFromMap(v2s16 p) {
float MapgenV6::baseTerrainLevelFromMap(int index) {
if (flags & MG_FLAT)
return water_level;
float terrain_base = noise_terrain_base->result[index];
float terrain_higher = noise_terrain_higher->result[index];
float steepness = noise_steepness->result[index];
float height_select = noise_height_select->result[index];
return baseTerrainLevel(terrain_base, terrain_higher,
steepness, height_select);
}
@ -340,7 +332,7 @@ float MapgenV6::getTreeAmount(v2s16 p)
/*double noise = noise2d_perlin(
0.5+(float)p.X/125, 0.5+(float)p.Y/125,
seed+2, 4, 0.66);*/
float noise = NoisePerlin2D(np_trees, p.X, p.Y, seed);
float zeroval = -0.39;
if (noise < zeroval)
@ -355,9 +347,9 @@ bool MapgenV6::getHaveAppleTree(v2s16 p)
/*is_apple_tree = noise2d_perlin(
0.5+(float)p.X/100, 0.5+(float)p.Z/100,
data->seed+342902, 3, 0.45) > 0.2;*/
float noise = NoisePerlin2D(np_apple_trees, p.X, p.Y, seed);
return noise > 0.2;
}
@ -366,11 +358,11 @@ float MapgenV6::getMudAmount(int index)
{
if (flags & MG_FLAT)
return AVERAGE_MUD_AMOUNT;
/*return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
0.5+(float)p.X/200, 0.5+(float)p.Y/200,
seed+91013, 3, 0.55));*/
return noise_mud->result[index];
}
@ -381,7 +373,7 @@ bool MapgenV6::getHaveBeach(int index)
/*double sandnoise = noise2d_perlin(
0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
seed+59420, 3, 0.50);*/
float sandnoise = noise_beach->result[index];
return (sandnoise > freq_beach);
}
@ -393,16 +385,16 @@ BiomeV6Type MapgenV6::getBiome(int index, v2s16 p)
/*double d = noise2d_perlin(
0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
seed+9130, 3, 0.50);*/
float d = noise_biome->result[index];
if (d > freq_desert)
return BT_DESERT;
if ((spflags & MGV6_BIOMEBLEND) &&
(d > freq_desert - 0.10) &&
((noise2d(p.X, p.Y, seed) + 1.0) > (freq_desert - d) * 20.0))
return BT_DESERT;
return BT_NORMAL;
}
@ -425,11 +417,11 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
assert(data->blockpos_requested.X <= data->blockpos_max.X &&
data->blockpos_requested.Y <= data->blockpos_max.Y &&
data->blockpos_requested.Z <= data->blockpos_max.Z);
this->generating = true;
this->vm = data->vmanip;
this->vm = data->vmanip;
this->ndef = data->nodedef;
// Hack: use minimum block coords for old code that assumes a single block
v3s16 blockpos = data->blockpos_requested;
v3s16 blockpos_min = data->blockpos_min;
@ -491,7 +483,7 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
flowMud(mudflow_minpos, mudflow_maxpos);
}
// Add dungeons
if (flags & MG_DUNGEONS) {
DungeonParams dp;
@ -525,7 +517,7 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
DungeonGen dgen(this, &dp);
dgen.generate(blockseed, full_node_min, full_node_max);
}
// Add top and bottom side of water to transforming_liquid queue
updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
@ -535,7 +527,7 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
// Generate some trees, and add grass, if a jungle
if (flags & MG_TREES)
placeTreesAndJungleGrass();
// Generate the registered decorations
emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
@ -546,7 +538,7 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
if (flags & MG_LIGHT)
calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
this->generating = false;
}
@ -598,25 +590,25 @@ int MapgenV6::generateGround() {
MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
int stone_surface_max_y = -MAP_GENERATION_LIMIT;
u32 index = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
// Surface height
s16 surface_y = (s16)baseTerrainLevelFromMap(index);
// Log it
if (surface_y > stone_surface_max_y)
stone_surface_max_y = surface_y;
BiomeV6Type bt = getBiome(index, v2s16(x, z));
// Fill ground with stone
v3s16 em = vm->m_area.getExtent();
u32 i = vm->m_area.index(x, node_min.Y, z);
for (s16 y = node_min.Y; y <= node_max.Y; y++) {
if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
if (y <= surface_y) {
vm->m_data[i] = (y > water_level && bt == BT_DESERT) ?
vm->m_data[i] = (y > water_level && bt == BT_DESERT) ?
n_desert_stone : n_stone;
} else if (y <= water_level) {
vm->m_data[i] = n_water_source;
@ -627,7 +619,7 @@ int MapgenV6::generateGround() {
vm->m_area.add_y(em, i, 1);
}
}
return stone_surface_max_y;
}
@ -647,11 +639,11 @@ void MapgenV6::addMud() {
// Find ground level
s16 surface_y = find_stone_level(v2s16(x, z)); /////////////////optimize this!
// Handle area not found
if (surface_y == vm->m_area.MinEdge.Y - 1)
continue;
BiomeV6Type bt = getBiome(index, v2s16(x, z));
addnode = (bt == BT_DESERT) ? n_desert_sand : n_dirt;
@ -830,7 +822,7 @@ void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos) {
void MapgenV6::addDirtGravelBlobs() {
if (getBiome(v2s16(node_min.X, node_min.Z)) != BT_NORMAL)
return;
PseudoRandom pr(blockseed + 983);
for (int i = 0; i < volume_nodes/10/10/10; i++) {
bool only_fill_cave = (myrand_range(0,1) != 0);
@ -844,7 +836,7 @@ void MapgenV6::addDirtGravelBlobs() {
pr.range(node_min.Y, node_max.Y) - size.Y / 2,
pr.range(node_min.Z, node_max.Z) - size.Z / 2
);
MapNode n1((p0.Y > -32 && !pr.range(0, 1)) ? c_dirt : c_gravel);
for (int z1 = 0; z1 < size.Z; z1++)
for (int y1 = 0; y1 < size.Y; y1++)
@ -869,7 +861,7 @@ void MapgenV6::placeTreesAndJungleGrass() {
//TimeTaker t("placeTrees");
if (node_max.Y < water_level)
return;
PseudoRandom grassrandom(blockseed + 53);
content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
// if we don't have junglegrass, don't place cignore... that's bad
@ -877,12 +869,12 @@ void MapgenV6::placeTreesAndJungleGrass() {
c_junglegrass = CONTENT_AIR;
MapNode n_junglegrass(c_junglegrass);
v3s16 em = vm->m_area.getExtent();
// Divide area into parts
s16 div = 8;
s16 sidelen = central_area_size.X / div;
double area = sidelen * sidelen;
// N.B. We must add jungle grass first, since tree leaves will
// obstruct the ground, giving us a false ground level
for (s16 z0 = 0; z0 < div; z0++)
@ -902,10 +894,10 @@ void MapgenV6::placeTreesAndJungleGrass() {
node_min.X + sidelen + sidelen * x0 - 1,
node_min.Z + sidelen + sidelen * z0 - 1
);
// Amount of trees, jungle area
u32 tree_count = area * getTreeAmount(p2d_center);
float humidity;
bool is_jungle = false;
if (spflags & MGV6_JUNGLES) {
@ -917,16 +909,16 @@ void MapgenV6::placeTreesAndJungleGrass() {
}
// Add jungle grass
if (is_jungle) {
if (is_jungle) {
u32 grass_count = 5 * humidity * tree_count;
for (u32 i = 0; i < grass_count; i++) {
s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////optimize this!
if (y < water_level || y < node_min.Y || y > node_max.Y)
continue;
u32 vi = vm->m_area.index(x, y, z);
// place on dirt_with_grass, since we know it is exposed to sunlight
if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
@ -935,7 +927,7 @@ void MapgenV6::placeTreesAndJungleGrass() {
}
}
}
// Put trees in random places on part of division
for (u32 i = 0; i < tree_count; i++) {
s16 x = myrand_range(p2d_min.X, p2d_max.X);
@ -945,7 +937,7 @@ void MapgenV6::placeTreesAndJungleGrass() {
// Don't make a tree so high that it doesn't fit
if(y < water_level || y > node_max.Y - 6)
continue;
v3s16 p(x,y,z);
// Trees grow only on mud and grass
{
@ -956,7 +948,7 @@ void MapgenV6::placeTreesAndJungleGrass() {
continue;
}
p.Y++;
// Make a tree
if (is_jungle) {
treegen::make_jungletree(*vm, p, ndef, myrand());
@ -1009,15 +1001,15 @@ void MapgenV6::generateCaves(int max_stone_y) {
u32 bruises_count = 1;
PseudoRandom ps(blockseed + 21343);
PseudoRandom ps2(blockseed + 1032);
if (ps.range(1, 6) == 1)
bruises_count = ps.range(0, ps.range(0, 2));
if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
caves_count /= 3;
bruises_count /= 3;
}
for (u32 i = 0; i < caves_count + bruises_count; i++) {
bool large_cave = (i >= caves_count);
CaveV6 cave(this, &ps, &ps2, large_cave);

@ -55,10 +55,10 @@ struct MapgenV6Params : public MapgenSpecificParams {
NoiseParams np_humidity;
NoiseParams np_trees;
NoiseParams np_apple_trees;
MapgenV6Params();
~MapgenV6Params() {}
void readParams(Settings *settings);
void writeParams(Settings *settings);
};
@ -68,7 +68,6 @@ public:
EmergeManager *emerge;
int ystride;
u32 flags;
u32 spflags;
u32 blockseed;
@ -111,7 +110,7 @@ public:
MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge);
~MapgenV6();
void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
@ -124,7 +123,7 @@ public:
s16 find_stone_level(v2s16 p2d);
bool block_is_underground(u64 seed, v3s16 blockpos);
s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision);
float getHumidity(v2s16 p);
float getTreeAmount(v2s16 p);
bool getHaveAppleTree(v2s16 p);
@ -134,9 +133,9 @@ public:
bool getHaveBeach(int index);
BiomeV6Type getBiome(v2s16 p);
BiomeV6Type getBiome(int index, v2s16 p);
u32 get_blockseed(u64 seed, v3s16 p);
virtual void calculateNoise();
int generateGround();
void addMud();
@ -152,7 +151,7 @@ struct MapgenFactoryV6 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV6(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams() {
return new MapgenV6Params();
};

@ -49,19 +49,12 @@ FlagDesc flagdesc_mapgen_v7[] = {
///////////////////////////////////////////////////////////////////////////////
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge) {
this->generating = false;
this->id = mapgenid;
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
: Mapgen(mapgenid, params, emerge)
{
this->emerge = emerge;
this->bmgr = emerge->biomemgr;
this->seed = (int)params->seed;
this->water_level = params->water_level;
this->flags = params->flags;
this->gennotify = emerge->gennotify;
this->csize = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE;
//// amount of elements to skip for the next index
//// for noise/height/biome maps (not vmanip)
this->ystride = csize.X;
@ -119,7 +112,7 @@ MapgenV7::~MapgenV7() {
delete noise_heat;
delete noise_humidity;
delete[] ridge_heightmap;
delete[] heightmap;
delete[] biomemap;
@ -177,7 +170,7 @@ void MapgenV7Params::writeParams(Settings *settings) {
int MapgenV7::getGroundLevelAtPoint(v2s16 p) {
// Base terrain calculation
s16 y = baseTerrainLevelAtPoint(p.X, p.Y);
// Ridge/river terrain calculation
float width = 0.3;
float uwatern = NoisePerlin2DNoTxfm(noise_ridge_uwater->np, p.X, p.Y, seed) * 2;
@ -185,14 +178,14 @@ int MapgenV7::getGroundLevelAtPoint(v2s16 p) {
// if inside a river, simply guess
if (uwatern >= -width && uwatern <= width)
return water_level - 10;
// Mountain terrain calculation
int iters = 128; // don't even bother iterating more than 128 times..
while (iters--) {
//current point would have been air
if (!getMountainTerrainAtPoint(p.X, y, p.Y))
return y;
y++;
}
@ -209,12 +202,12 @@ void MapgenV7::makeChunk(BlockMakeData *data) {
assert(data->blockpos_requested.X <= data->blockpos_max.X &&
data->blockpos_requested.Y <= data->blockpos_max.Y &&
data->blockpos_requested.Z <= data->blockpos_max.Z);
this->generating = true;
this->vm = data->vmanip;
this->vm = data->vmanip;
this->ndef = data->nodedef;
//TimeTaker t("makeChunk");
v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max;
node_min = blockpos_min * MAP_BLOCKSIZE;
@ -223,19 +216,19 @@ void MapgenV7::makeChunk(BlockMakeData *data) {
full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
blockseed = emerge->getBlockSeed(full_node_min); //////use getBlockSeed2()!
// Make some noise
calculateNoise();
// Generate base terrain, mountains, and ridges with initial heightmaps
s16 stone_surface_max_y = generateTerrain();
updateHeightmap(node_min, node_max);
// Calculate biomes
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
noise_humidity->result, heightmap, biomemap);
// Actually place the biome-specific nodes and what not
generateBiomes();
@ -255,17 +248,17 @@ void MapgenV7::makeChunk(BlockMakeData *data) {
// Sprinkle some dust on top after everything else was generated
dustTopNodes();
//printf("makeChunk: %dms\n", t.stop());
updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
if (flags & MG_LIGHT)
calcLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
//setLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
// node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE, 0xFF);
this->generating = false;
}
@ -275,24 +268,24 @@ void MapgenV7::calculateNoise() {
int x = node_min.X;
int y = node_min.Y;
int z = node_min.Z;
noise_height_select->perlinMap2D(x, z);
noise_height_select->transformNoiseMap();
noise_terrain_persist->perlinMap2D(x, z);
noise_terrain_persist->transformNoiseMap();
float *persistmap = noise_terrain_persist->result;
for (int i = 0; i != csize.X * csize.Z; i++)
persistmap[i] = rangelim(persistmap[i], 0.4, 0.9);
noise_terrain_base->perlinMap2DModulated(x, z, persistmap);
noise_terrain_base->transformNoiseMap();
noise_terrain_alt->perlinMap2DModulated(x, z, persistmap);
noise_terrain_alt->transformNoiseMap();
noise_filler_depth->perlinMap2D(x, z);
if (spflags & MGV7_MOUNTAINS) {
noise_mountain->perlinMap3D(x, y, z);
noise_mount_height->perlinMap2D(x, z);
@ -303,10 +296,10 @@ void MapgenV7::calculateNoise() {
noise_ridge->perlinMap3D(x, y, z);
noise_ridge_uwater->perlinMap2D(x, z);
}
noise_heat->perlinMap2D(x, z);
noise_humidity->perlinMap2D(x, z);
//printf("calculateNoise: %dus\n", t.stop());
}
@ -315,7 +308,7 @@ Biome *MapgenV7::getBiomeAtPoint(v3s16 p) {
float heat = NoisePerlin2D(bmgr->np_heat, p.X, p.Z, seed);
float humidity = NoisePerlin2D(bmgr->np_humidity, p.X, p.Z, seed);
s16 groundlevel = baseTerrainLevelAtPoint(p.X, p.Z);
return bmgr->getBiome(heat, humidity, groundlevel);
}
@ -323,7 +316,7 @@ Biome *MapgenV7::getBiomeAtPoint(v3s16 p) {
float MapgenV7::baseTerrainLevelAtPoint(int x, int z) {
float hselect = NoisePerlin2D(noise_height_select->np, x, z, seed);
hselect = rangelim(hselect, 0.0, 1.0);
float persist = NoisePerlin2D(noise_terrain_persist->np, x, z, seed);
persist = rangelim(persist, 0.4, 0.9);
@ -335,7 +328,7 @@ float MapgenV7::baseTerrainLevelAtPoint(int x, int z) {
if (height_alt > height_base)
return height_alt;
return (height_base * hselect) + (height_alt * (1.0 - hselect));
}
@ -344,7 +337,7 @@ float MapgenV7::baseTerrainLevelFromMap(int index) {
float hselect = rangelim(noise_height_select->result[index], 0.0, 1.0);
float height_base = noise_terrain_base->result[index];
float height_alt = noise_terrain_alt->result[index];
if (height_alt > height_base)
return height_alt;
@ -373,7 +366,7 @@ void MapgenV7::carveRivers() {
MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
MapNode n_stone(c_stone);
u32 index = 0;
int river_depth = 4;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
@ -385,16 +378,16 @@ void MapgenV7::carveRivers() {
float height = terrain_river * (1 - abs(terrain_mod)) *
noise_terrain_river->np->scale;
height = log(height * height); //log(h^3) is pretty interesting for terrain
s16 y = heightmap[index];
if (height < 1.0 && y > river_depth &&
y - river_depth >= node_min.Y && y <= node_max.Y) {
for (s16 ry = y; ry != y - river_depth; ry--) {
u32 vi = vm->m_area.index(x, ry, z);
vm->m_data[vi] = n_air;
}
u32 vi = vm->m_area.index(x, y - river_depth, z);
vm->m_data[vi] = n_water_source;
}
@ -411,7 +404,7 @@ int MapgenV7::generateTerrain() {
if (spflags & MGV7_RIDGES)
generateRidgeTerrain();
return ymax;
}
@ -420,23 +413,23 @@ int MapgenV7::generateBaseTerrain() {
MapNode n_air(CONTENT_AIR);
MapNode n_stone(c_stone);
MapNode n_water(c_water_source);
int stone_surface_max_y = -MAP_GENERATION_LIMIT;
v3s16 em = vm->m_area.getExtent();
u32 index = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
float surface_height = baseTerrainLevelFromMap(index);
s16 surface_y = (s16)surface_height;
heightmap[index] = surface_y;
heightmap[index] = surface_y;
ridge_heightmap[index] = surface_y;
if (surface_y > stone_surface_max_y)
stone_surface_max_y = surface_y;
u32 i = vm->m_area.index(x, node_min.Y, z);
u32 i = vm->m_area.index(x, node_min.Y, z);
for (s16 y = node_min.Y; y <= node_max.Y; y++) {
if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
if (y <= surface_y)
@ -449,7 +442,7 @@ int MapgenV7::generateBaseTerrain() {
vm->m_area.add_y(em, i, 1);
}
}
return stone_surface_max_y;
}
@ -457,10 +450,10 @@ int MapgenV7::generateBaseTerrain() {
void MapgenV7::generateMountainTerrain() {
if (node_max.Y <= water_level)
return;
MapNode n_stone(c_stone);
u32 j = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 y = node_min.Y; y <= node_max.Y; y++) {
u32 vi = vm->m_area.index(node_min.X, y, z);
@ -469,7 +462,7 @@ void MapgenV7::generateMountainTerrain() {
if (getMountainTerrainFromMap(j, index, y))
vm->m_data[vi] = n_stone;
vi++;
j++;
}
@ -481,36 +474,36 @@ void MapgenV7::generateRidgeTerrain() {
MapNode n_water(c_water_source);
MapNode n_air(CONTENT_AIR);
u32 index = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 y = node_min.Y; y <= node_max.Y; y++) {
u32 vi = vm->m_area.index(node_min.X, y, z);
for (s16 x = node_min.X; x <= node_max.X; x++, index++, vi++) {
int j = (z - node_min.Z) * csize.X + (x - node_min.X);
if (heightmap[j] < water_level - 4)
continue;
float widthn = (noise_terrain_persist->result[j] - 0.6) / 0.1;
//widthn = rangelim(widthn, -0.05, 0.5);
float width = 0.3; // TODO: figure out acceptable perlin noise values
float uwatern = noise_ridge_uwater->result[j] * 2;
if (uwatern < -width || uwatern > width)
continue;
float height_mod = (float)(y + 17) / 2.5;
float width_mod = (width - fabs(uwatern));
float nridge = noise_ridge->result[index] * (float)y / 7.0;
if (y < water_level)
nridge = -fabs(nridge) * 3.0 * widthn * 0.3;
if (nridge + width_mod * height_mod < 0.6)
continue;
if (y < ridge_heightmap[j])
ridge_heightmap[j] = y - 1;
ridge_heightmap[j] = y - 1;
vm->m_data[vi] = (y > water_level) ? n_air : n_water;
}
@ -528,7 +521,7 @@ void MapgenV7::generateBiomes() {
v3s16 em = vm->m_area.getExtent();
u32 index = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
Biome *biome = (Biome *)bmgr->get(biomemap[index]);
@ -537,14 +530,14 @@ void MapgenV7::generateBiomes() {
s16 y0_filler = biome->depth_top + dfiller;
s16 nplaced = 0;
u32 i = vm->m_area.index(x, node_max.Y, z);
u32 i = vm->m_area.index(x, node_max.Y, z);
content_t c_above = vm->m_data[i + em.X].getContent();
bool have_air = c_above == CONTENT_AIR;
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
content_t c = vm->m_data[i].getContent();
// It could be the case that the elevation is equal to the chunk
// boundary, but the chunk above has not been generated yet
if (y == node_max.Y && c_above == CONTENT_IGNORE &&
@ -554,10 +547,10 @@ void MapgenV7::generateBiomes() {
(x - node_min.X);
have_air = !getMountainTerrainFromMap(j, index, y);
}
if (c == c_stone && have_air) {
content_t c_below = vm->m_data[i - em.X].getContent();
if (c_below != CONTENT_AIR) {
if (nplaced < y0_top) {
if(y < water_level)
@ -593,7 +586,7 @@ void MapgenV7::generateBiomes() {
have_air = true;
nplaced = 0;
}
vm->m_area.add_y(em, i, -1);
}
}
@ -603,14 +596,14 @@ void MapgenV7::generateBiomes() {
void MapgenV7::dustTopNodes() {
v3s16 em = vm->m_area.getExtent();
u32 index = 0;
if (water_level > node_max.Y)
return;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
Biome *biome = (Biome *)bmgr->get(biomemap[index]);
if (biome->c_dust == CONTENT_IGNORE)
continue;
@ -622,17 +615,17 @@ void MapgenV7::dustTopNodes() {
vm->m_area.add_y(em, vi, -1);
}
content_t c = vm->m_data[vi].getContent();
if (c == biome->c_water && biome->c_dust_water != CONTENT_IGNORE) {
if (y < node_min.Y)
continue;
vm->m_data[vi] = MapNode(biome->c_dust_water);
} else if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE) {
if (y == node_max.Y)
continue;
vm->m_area.add_y(em, vi, 1);
vm->m_data[vi] = MapNode(biome->c_dust);
}
@ -649,10 +642,10 @@ void MapgenV7::addTopNodes() {
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
Biome *biome = bmgr->biomes[biomemap[index]];
//////////////////// First, add top nodes below the ridge
s16 y = ridge_heightmap[index];
// This cutoff is good enough, but not perfect.
// It will cut off potentially placed top nodes at chunk boundaries
if (y < node_min.Y)
@ -664,7 +657,7 @@ void MapgenV7::addTopNodes() {
if (ndef->get(c).walkable)
continue;
}
// N.B. It is necessary to search downward since ridge_heightmap[i]
// might not be the actual height, just the lowest part in the chunk
// where a ridge had been carved
@ -692,7 +685,7 @@ void MapgenV7::addTopNodes() {
vm->m_data[i] = MapNode(c_dirt_with_grass);
}
}
//////////////////// Now, add top nodes on top of the ridge
y = heightmap[index];
if (y > node_max.Y) {

@ -42,10 +42,10 @@ struct MapgenV7Params : public MapgenSpecificParams {
NoiseParams np_ridge_uwater;
NoiseParams np_mountain;
NoiseParams np_ridge;
MapgenV7Params();
~MapgenV7Params() {}
void readParams(Settings *settings);
void writeParams(Settings *settings);
};
@ -57,7 +57,6 @@ public:
int ystride;
int zstride;
u32 flags;
u32 spflags;
u32 blockseed;
@ -65,9 +64,9 @@ public:
v3s16 node_max;
v3s16 full_node_min;
v3s16 full_node_max;
s16 *ridge_heightmap;
Noise *noise_terrain_base;
Noise *noise_terrain_alt;
Noise *noise_terrain_persist;
@ -77,10 +76,10 @@ public:
Noise *noise_ridge_uwater;
Noise *noise_mountain;
Noise *noise_ridge;
Noise *noise_heat;
Noise *noise_humidity;
content_t c_stone;
content_t c_dirt;
content_t c_dirt_with_grass;
@ -95,7 +94,7 @@ public:
MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge);
~MapgenV7();
virtual void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
Biome *getBiomeAtPoint(v3s16 p);
@ -104,19 +103,19 @@ public:
float baseTerrainLevelFromMap(int index);
bool getMountainTerrainAtPoint(int x, int y, int z);
bool getMountainTerrainFromMap(int idx_xyz, int idx_xz, int y);
void calculateNoise();
virtual int generateTerrain();
int generateBaseTerrain();
void generateMountainTerrain();
void generateRidgeTerrain();
void generateBiomes();
void dustTopNodes();
//void addTopNodes();
void generateCaves(int max_stone_y);
};
@ -124,7 +123,7 @@ struct MapgenFactoryV7 : public MapgenFactory {
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV7(mgid, params, emerge);
};
MapgenSpecificParams *createMapgenParams() {
return new MapgenV7Params();
};

@ -144,7 +144,9 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
}
}
generate(mg, &ps, max_y, v3s16(x, y, z));
v3s16 pos(x, y, z);
if (generate(mg, &ps, max_y, pos))
mg->gennotify.addEvent(GENNOTIFY_DECORATION, pos, id);
}
}
@ -254,12 +256,12 @@ bool DecoSimple::canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p)
}
void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
size_t DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
{
ManualMapVoxelManipulator *vm = mg->vm;
if (!canPlaceDecoration(vm, p))
return;
return 0;
content_t c_place = c_decos[pr->range(0, c_decos.size() - 1)];
@ -279,6 +281,8 @@ void DecoSimple::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
vm->m_data[vi] = MapNode(c_place);
}
return 1;
}
@ -291,7 +295,7 @@ int DecoSimple::getHeight()
///////////////////////////////////////////////////////////////////////////////
void DecoSchematic::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
size_t DecoSchematic::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
{
ManualMapVoxelManipulator *vm = mg->vm;
@ -305,12 +309,14 @@ void DecoSchematic::generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p)
u32 vi = vm->m_area.index(p);
content_t c = vm->m_data[vi].getContent();
if (!CONTAINS(c_place_on, c))
return;
return 0;
Rotation rot = (rotation == ROTATE_RAND) ?
(Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
schematic->blitToVManip(p, vm, rot, false, mg->ndef);
return 1;
}

@ -77,7 +77,7 @@ public:
size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) = 0;
virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p) = 0;
virtual int getHeight() = 0;
};
@ -92,7 +92,7 @@ public:
~DecoSimple() {}
bool canPlaceDecoration(ManualMapVoxelManipulator *vm, v3s16 p);
virtual void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual int getHeight();
};
@ -105,7 +105,7 @@ public:
~DecoSchematic() {}
void generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual size_t generate(Mapgen *mg, PseudoRandom *pr, s16 max_y, v3s16 p);
virtual int getHeight();
};

@ -95,7 +95,7 @@ size_t Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
nmax.Y = ymax;
generate(mg->vm, mg->seed, blockseed, nmin, nmax);
return 0;
return 1;
}

@ -194,23 +194,21 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
return 1;
}
case MGOBJ_GENNOTIFY: {
std::map<std::string, std::vector<v3s16> >event_map;
std::map<std::string, std::vector<v3s16> >::iterator it;
mg->gennotify.getEvents(event_map);
lua_newtable(L);
for (int i = 0; flagdesc_gennotify[i].name; i++) {
if (!(emerge->gennotify & flagdesc_gennotify[i].flag))
continue;
std::vector<v3s16> *posvec = mg->gen_notifications[i];
if (!posvec)
return 0;
for (it = event_map.begin(); it != event_map.end(); ++it) {
lua_newtable(L);
for (unsigned int j = 0; j != posvec->size(); j++) {
push_v3s16(L, (*posvec)[j]);
for (size_t j = 0; j != it->second.size(); j++) {
push_v3s16(L, it->second[j]);
lua_rawseti(L, -2, j + 1);
}
lua_setfield(L, -2, flagdesc_gennotify[i].name);
posvec->clear();
lua_setfield(L, -2, it->first.c_str());
}
return 1;
@ -291,14 +289,24 @@ int ModApiMapgen::l_set_noiseparam_defaults(lua_State *L)
return 0;
}
// set_gen_notify(string)
// set_gen_notify(flags, {deco_id_table})
int ModApiMapgen::l_set_gen_notify(lua_State *L)
{
u32 flags = 0, flagmask = 0;
EmergeManager *emerge = getServer(L)->getEmergeManager();
if (read_flags(L, 1, flagdesc_gennotify, &flags, &flagmask)) {
EmergeManager *emerge = getServer(L)->getEmergeManager();
emerge->gennotify = flags;
emerge->gen_notify_on &= ~flagmask;
emerge->gen_notify_on |= flags;
}
if (lua_istable(L, 2)) {
lua_pushnil(L);
while (lua_next(L, 2)) {
if (lua_isnumber(L, -1))
emerge->gen_notify_on_deco_ids.insert(lua_tonumber(L, -1));
lua_pop(L, 1);
}
}
return 0;
@ -372,7 +380,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
<< decotype << " not implemented";
return 0;
}
deco->name = getstringfield_default(L, index, "name", "");
deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
deco->sidelen = getintfield_default(L, index, "sidelen", 8);