^ 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)
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
--------------------
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));
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);
}
(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);
}
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;
}
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);
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)
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));
min_tunnel_diameter = 2;
max_tunnel_diameter = ps->range(2, 6);
}
-
+
large_cave_is_flat = (ps->range(0, 1) == 0);
}
(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);
}
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) {
} 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) {
s16 h = mg->ridge_heightmap[index];
if (h < p.Y)
return;
- } else if (p.Y > water_level) {
+ } else if (p.Y > water_level) {
return;
}
}
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);
// Carve routes
for (float f = 0; f < 1.0; f += 1.0 / veclen)
carveRoute(vec, f, randomize_xz, is_ravine);
-
+
orp = rp;
}
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);
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)
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;
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;
} else {
if (c == CONTENT_IGNORE)
continue;
-
+
vm->m_data[i] = airnode;
vm->m_flags[i] |= VMANIP_FLAG_CAVE;
}
#ifdef DGEN_USE_TORCHES
c_torch = ndef->getId("default:torch");
#endif
-
+
if (dparams) {
memcpy(&dp, dparams, sizeof(dp));
} else {
}
}
}
-
+
// Add it
makeDungeon(v3s16(1,1,1) * MAP_BLOCKSIZE);
}
}
}
-
+
//printf("== gen dungeons: %dms\n", t.stop());
}
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
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)
// Create walker and find a place for a door
v3s16 doorplace;
v3s16 doordir;
-
+
m_pos = walker_start_place;
if (!findPlaceForDoor(doorplace, doordir))
return;
{
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++)
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)
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
((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);
#include "voxel.h"
#include "noise.h"
+#include "mapgen.h"
#define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
#define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
class ManualMapVoxelManipulator;
class INodeDefManager;
-class Mapgen;
v3s16 rand_ortho_dir(PseudoRandom &random, bool diagonal_dirs);
v3s16 turn_xz(v3s16 olddir, int t);
content_t c_moss;
content_t c_stair;
- int notifytype;
+ GenNotifyType notifytype;
bool diagonal_dirs;
float mossratio;
v3s16 holesize;
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,
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);
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
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;
#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"
{"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(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() {
- for (unsigned int i = 0; i != NUM_GEN_NOTIFY; i++)
- delete gen_notifications[i];
+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;
}
-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;
}
-void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) {
+void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
+{
if (!heightmap)
return;
}
-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();
}
-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);
}
-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;
}
-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);
}
-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);
}
+///////////////////////////////////////////////////////////////////////////////
+
+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();
+}
+
+
///////////////////////////////////////////////////////////////////////////////
#define MG_FLAT 0x08
#define MG_LIGHT 0x10
-#define NUM_GEN_NOTIFY 6
-
class Settings;
class ManualMapVoxelManipulator;
class INodeDefManager;
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 {
MapgenSpecificParams *sparams;
- MapgenParams() {
+ MapgenParams()
+ {
mg_name = DEFAULT_MAPGEN;
seed = 0;
water_level = 1;
public:
int seed;
int water_level;
+ u32 flags;
bool generating;
int id;
ManualMapVoxelManipulator *vm;
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);
///////////////////////////////////////////////////////////////////////////////
MapgenSinglenode::MapgenSinglenode(int mapgenid,
- MapgenParams *params, EmergeManager *emerge)
+ MapgenParams *params, EmergeManager *emerge)
+ : Mapgen(mapgenid, params, emerge)
{
flags = params->flags;
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);
if (flags & MG_LIGHT)
calcLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
-
+
this->generating = false;
}
};
-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;
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);
delete noise_heat;
delete noise_humidity;
-
+
delete[] heightmap;
delete[] biomemap;
}
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;
// Create a block-specific seed
blockseed = emerge->getBlockSeed(full_node_min); //////use getBlockSeed2()!
-
+
// Make some noise
calculateNoise();
// Calculate biomes
bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
noise_humidity->result, heightmap, biomemap);
-
+
// Actually place the biome-specific nodes
generateBiomes();
// 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;
}
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);
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 =
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)
have_air = true;
nplaced = 0;
}
-
+
vm->m_area.add_y(em, i, -1);
}
}
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;
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);
}
MapgenV5Params();
~MapgenV5Params() {}
-
+
void readParams(Settings *settings);
void writeParams(Settings *settings);
};
int ystride;
int zstride;
- u32 flags;
u32 spflags;
u32 blockseed;
v3s16 node_max;
v3s16 full_node_min;
v3s16 full_node_max;
-
+
Noise *noise_filler_depth;
Noise *noise_factor;
Noise *noise_height;
MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_);
~MapgenV5();
-
+
virtual void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
void calculateNoise();
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV5(mgid, params, emerge);
};
-
+
MapgenSpecificParams *createMapgenParams() {
return new MapgenV5Params();
};
///////////////////////////////////////////////////////////////////////////////
-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;
//////////////////////// 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;
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;
}
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,
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);
}
/*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)
/*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;
}
{
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];
}
/*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);
}
/*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;
}
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;
flowMud(mudflow_minpos, mudflow_maxpos);
}
-
+
// Add dungeons
if (flags & MG_DUNGEONS) {
DungeonParams dp;
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);
// 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);
if (flags & MG_LIGHT)
calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
-
+
this->generating = false;
}
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;
vm->m_area.add_y(em, i, 1);
}
}
-
+
return stone_surface_max_y;
}
// 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;
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);
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++)
//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
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++)
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) {
}
// 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) {
}
}
}
-
+
// 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);
// 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
{
continue;
}
p.Y++;
-
+
// Make a tree
if (is_jungle) {
treegen::make_jungletree(*vm, p, ndef, myrand());
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);
NoiseParams np_humidity;
NoiseParams np_trees;
NoiseParams np_apple_trees;
-
+
MapgenV6Params();
~MapgenV6Params() {}
-
+
void readParams(Settings *settings);
void writeParams(Settings *settings);
};
EmergeManager *emerge;
int ystride;
- u32 flags;
u32 spflags;
u32 blockseed;
MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge);
~MapgenV6();
-
+
void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
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);
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();
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV6(mgid, params, emerge);
};
-
+
MapgenSpecificParams *createMapgenParams() {
return new MapgenV6Params();
};
///////////////////////////////////////////////////////////////////////////////
-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;
delete noise_heat;
delete noise_humidity;
-
+
delete[] ridge_heightmap;
delete[] heightmap;
delete[] biomemap;
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;
// 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++;
}
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;
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();
// 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;
}
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);
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());
}
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);
}
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);
if (height_alt > height_base)
return height_alt;
-
+
return (height_base * hselect) + (height_alt * (1.0 - hselect));
}
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;
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++)
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;
}
if (spflags & MGV7_RIDGES)
generateRidgeTerrain();
-
+
return ymax;
}
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)
vm->m_area.add_y(em, i, 1);
}
}
-
+
return stone_surface_max_y;
}
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);
if (getMountainTerrainFromMap(j, index, y))
vm->m_data[vi] = n_stone;
-
+
vi++;
j++;
}
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;
}
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 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 &&
(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)
have_air = true;
nplaced = 0;
}
-
+
vm->m_area.add_y(em, i, -1);
}
}
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;
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);
}
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)
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
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) {
NoiseParams np_ridge_uwater;
NoiseParams np_mountain;
NoiseParams np_ridge;
-
+
MapgenV7Params();
~MapgenV7Params() {}
-
+
void readParams(Settings *settings);
void writeParams(Settings *settings);
};
int ystride;
int zstride;
- u32 flags;
u32 spflags;
u32 blockseed;
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;
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;
MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge);
~MapgenV7();
-
+
virtual void makeChunk(BlockMakeData *data);
int getGroundLevelAtPoint(v2s16 p);
Biome *getBiomeAtPoint(v3s16 p);
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);
};
Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
return new MapgenV7(mgid, params, emerge);
};
-
+
MapgenSpecificParams *createMapgenParams() {
return new MapgenV7Params();
};
}
}
- 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);
}
}
}
-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)];
vm->m_data[vi] = MapNode(c_place);
}
+
+ return 1;
}
///////////////////////////////////////////////////////////////////////////////
-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;
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;
}
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;
};
~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();
};
~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();
};
nmax.Y = ymax;
generate(mg->vm, mg->seed, blockseed, nmin, nmax);
- return 0;
+ return 1;
}
return 1;
}
case MGOBJ_GENNOTIFY: {
- lua_newtable(L);
- for (int i = 0; flagdesc_gennotify[i].name; i++) {
- if (!(emerge->gennotify & flagdesc_gennotify[i].flag))
- continue;
+ std::map<std::string, std::vector<v3s16> >event_map;
+ std::map<std::string, std::vector<v3s16> >::iterator it;
- std::vector<v3s16> *posvec = mg->gen_notifications[i];
- if (!posvec)
- return 0;
+ mg->gennotify.getEvents(event_map);
+ lua_newtable(L);
+ 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;
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;
<< 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);