aboutsummaryrefslogtreecommitdiff
path: root/src/mapgen/mapgen_v7.h
blob: 5db10a304975800afdaa0fdfdcff0a5496e906aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
Minetest
Copyright (C) 2014-2020 paramat
Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#pragma once

#include "mapgen.h"

///////////// Mapgen V7 flags
#define MGV7_MOUNTAINS   0x01
#define MGV7_RIDGES      0x02
#define MGV7_FLOATLANDS  0x04
#define MGV7_CAVERNS     0x08
#define MGV7_BIOMEREPEAT 0x10 // Now unused

class BiomeManager;

extern FlagDesc flagdesc_mapgen_v7[];


struct MapgenV7Params : public MapgenParams {
	s16 mount_zero_level = 0;
	s16 floatland_ymin = 1024;
	s16 floatland_ymax = 4096;
	s16 floatland_taper = 256;
	float float_taper_exp = 2.0f;
	float floatland_density = -0.6f;
	s16 floatland_ywater = -31000;

	float cave_width = 0.09f;
	s16 large_cave_depth = -33;
	u16 small_cave_num_min = 0;
	u16 small_cave_num_max = 0;
	u16 large_cave_num_min = 0;
	u16 large_cave_num_max = 2;
	float large_cave_flooded = 0.5f;
	s16 cavern_limit = -256;
	s16 cavern_taper = 256;
	float cavern_threshold = 0.7f;
	s16 dungeon_ymin = -31000;
	s16 dungeon_ymax = 31000;

	NoiseParams np_terrain_base;
	NoiseParams np_terrain_alt;
	NoiseParams np_terrain_persist;
	NoiseParams np_height_select;
	NoiseParams np_filler_depth;
	NoiseParams np_mount_height;
	NoiseParams np_ridge_uwater;
	NoiseParams np_mountain;
	NoiseParams np_ridge;
	NoiseParams np_floatland;
	NoiseParams np_cavern;
	NoiseParams np_cave1;
	NoiseParams np_cave2;
	NoiseParams np_dungeons;

	MapgenV7Params();
	~MapgenV7Params() = default;

	void readParams(const Settings *settings);
	void writeParams(Settings *settings) const;
	void setDefaultSettings(Settings *settings);
};


class MapgenV7 : public MapgenBasic {
public:
	MapgenV7(MapgenV7Params *params, EmergeParams *emerge);
	~MapgenV7();

	virtual MapgenType getType() const { return MAPGEN_V7; }

	virtual void makeChunk(BlockMakeData *data);
	int getSpawnLevelAtPoint(v2s16 p);

	float baseTerrainLevelAtPoint(s16 x, s16 z);
	float baseTerrainLevelFromMap(int index);
	bool getMountainTerrainAtPoint(s16 x, s16 y, s16 z);
	bool getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y);
	bool getRiverChannelFromMap(int idx_xyz, int idx_xz, s16 y);
	bool getFloatlandTerrainFromMap(int idx_xyz, float float_offset);

	int generateTerrain();

private:
	s16 mount_zero_level;
	s16 floatland_ymin;
	s16 floatland_ymax;
	s16 floatland_taper;
	float float_taper_exp;
	float floatland_density;
	s16 floatland_ywater;

	float *float_offset_cache = nullptr;

	Noise *noise_terrain_base;
	Noise *noise_terrain_alt;
	Noise *noise_terrain_persist;
	Noise *noise_height_select;
	Noise *noise_mount_height;
	Noise *noise_ridge_uwater;
	Noise *noise_mountain;
	Noise *noise_ridge;
	Noise *noise_floatland;
};
32("world_start_time"); m_time_of_day_f = (float)m_time_of_day / 24000.0f; } u32 Environment::getDayNightRatio() { MutexAutoLock lock(this->m_time_lock); if (m_enable_day_night_ratio_override) return m_day_night_ratio_override; return time_to_daynight_ratio(m_time_of_day_f * 24000, m_cache_enable_shaders); } void Environment::setTimeOfDaySpeed(float speed) { m_time_of_day_speed = speed; } void Environment::setDayNightRatioOverride(bool enable, u32 value) { MutexAutoLock lock(this->m_time_lock); m_enable_day_night_ratio_override = enable; m_day_night_ratio_override = value; } void Environment::setTimeOfDay(u32 time) { MutexAutoLock lock(this->m_time_lock); if (m_time_of_day > time) ++m_day_count; m_time_of_day = time; m_time_of_day_f = (float)time / 24000.0; } u32 Environment::getTimeOfDay() { MutexAutoLock lock(this->m_time_lock); return m_time_of_day; } float Environment::getTimeOfDayF() { MutexAutoLock lock(this->m_time_lock); return m_time_of_day_f; } bool Environment::line_of_sight(v3f pos1, v3f pos2, v3s16 *p) { // Iterate trough nodes on the line voxalgo::VoxelLineIterator iterator(pos1 / BS, (pos2 - pos1) / BS); do { MapNode n = getMap().getNode(iterator.m_current_node_pos); // Return non-air if (n.param0 != CONTENT_AIR) { if (p) *p = iterator.m_current_node_pos; return false; } iterator.next(); } while (iterator.m_current_index <= iterator.m_last_index); return true; } /* Check if a node is pointable */ inline static bool isPointableNode(const MapNode &n, const NodeDefManager *nodedef , bool liquids_pointable) { const ContentFeatures &features = nodedef->get(n); return features.pointable || (liquids_pointable && features.isLiquid()); } void Environment::continueRaycast(RaycastState *state, PointedThing *result) { const NodeDefManager *nodedef = getMap().getNodeDefManager(); if (state->m_initialization_needed) { // Add objects if (state->m_objects_pointable) { std::vector<PointedThing> found; getSelectedActiveObjects(state->m_shootline, found); for (const PointedThing &pointed : found) { state->m_found.push(pointed); } } // Set search range core::aabbox3d<s16> maximal_exceed = nodedef->getSelectionBoxIntUnion(); state->m_search_range.MinEdge = -maximal_exceed.MaxEdge; state->m_search_range.MaxEdge = -maximal_exceed.MinEdge; // Setting is done state->m_initialization_needed = false; } // The index of the first pointed thing that was not returned // before. The last index which needs to be tested. s16 lastIndex = state->m_iterator.m_last_index; if (!state->m_found.empty()) { lastIndex = state->m_iterator.getIndex( floatToInt(state->m_found.top().intersection_point, BS)); } Map &map = getMap(); // If a node is found, this is the center of the // first nodebox the shootline meets. v3f found_boxcenter(0, 0, 0); // The untested nodes are in this range. core::aabbox3d<s16> new_nodes; while (state->m_iterator.m_current_index <= lastIndex) { // Test the nodes around the current node in search_range. new_nodes = state->m_search_range; new_nodes.MinEdge += state->m_iterator.m_current_node_pos; new_nodes.MaxEdge += state->m_iterator.m_current_node_pos; // Only check new nodes v3s16 delta = state->m_iterator.m_current_node_pos - state->m_previous_node; if (delta.X > 0) { new_nodes.MinEdge.X = new_nodes.MaxEdge.X; } else if (delta.X < 0) { new_nodes.MaxEdge.X = new_nodes.MinEdge.X; } else if (delta.Y > 0) { new_nodes.MinEdge.Y = new_nodes.MaxEdge.Y; } else if (delta.Y < 0) { new_nodes.MaxEdge.Y = new_nodes.MinEdge.Y; } else if (delta.Z > 0) { new_nodes.MinEdge.Z = new_nodes.MaxEdge.Z; } else if (delta.Z < 0) { new_nodes.MaxEdge.Z = new_nodes.MinEdge.Z; } // For each untested node for (s16 x = new_nodes.MinEdge.X; x <= new_nodes.MaxEdge.X; x++) for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) { MapNode n; v3s16 np(x, y, z); bool is_valid_position; n = map.getNode(np, &is_valid_position); if (!(is_valid_position && isPointableNode(n, nodedef, state->m_liquids_pointable))) { continue; } PointedThing result; std::vector<aabb3f> boxes; n.getSelectionBoxes(nodedef, &boxes, n.getNeighbors(np, &map)); // Is there a collision with a selection box? bool is_colliding = false; // Minimal distance of all collisions float min_distance_sq = 10000000; // ID of the current box (loop counter) u16 id = 0; v3f npf = intToFloat(np, BS); // This loop translates the boxes to their in-world place. for (aabb3f &box : boxes) { box.MinEdge += npf; box.MaxEdge += npf; v3f intersection_point; v3s16 intersection_normal; if (!boxLineCollision(box, state->m_shootline.start, state->m_shootline.getVector(), &intersection_point, &intersection_normal)) { ++id; continue; } f32 distanceSq = (intersection_point - state->m_shootline.start).getLengthSQ(); // If this is the nearest collision, save it if (min_distance_sq > distanceSq) { min_distance_sq = distanceSq; result.intersection_point = intersection_point; result.intersection_normal = intersection_normal; result.box_id = id; found_boxcenter = box.getCenter(); is_colliding = true; } ++id; } // If there wasn't a collision, stop if (!is_colliding) { continue; } result.type = POINTEDTHING_NODE; result.node_undersurface = np; result.distanceSq = min_distance_sq; // Set undersurface and abovesurface nodes f32 d = 0.002 * BS; v3f fake_intersection = result.intersection_point; // Move intersection towards its source block. if (fake_intersection.X < found_boxcenter.X) { fake_intersection.X += d; } else { fake_intersection.X -= d; } if (fake_intersection.Y < found_boxcenter.Y) { fake_intersection.Y += d; } else { fake_intersection.Y -= d; } if (fake_intersection.Z < found_boxcenter.Z) { fake_intersection.Z += d; } else { fake_intersection.Z -= d; } result.node_real_undersurface = floatToInt( fake_intersection, BS); result.node_abovesurface = result.node_real_undersurface + result.intersection_normal; // Push found PointedThing state->m_found.push(result); // If this is nearer than the old nearest object, // the search can be shorter s16 newIndex = state->m_iterator.getIndex( result.node_real_undersurface); if (newIndex < lastIndex) { lastIndex = newIndex; } } // Next node state->m_previous_node = state->m_iterator.m_current_node_pos; state->m_iterator.next(); } // Return empty PointedThing if nothing left on the ray if (state->m_found.empty()) { result->type = POINTEDTHING_NOTHING; } else { *result = state->m_found.top(); state->m_found.pop(); } } void Environment::stepTimeOfDay(float dtime) { MutexAutoLock lock(this->m_time_lock); // Cached in order to prevent the two reads we do to give // different results (can be written by code not under the lock) f32 cached_time_of_day_speed = m_time_of_day_speed; f32 speed = cached_time_of_day_speed * 24000. / (24. * 3600); m_time_conversion_skew += dtime; u32 units = (u32)(m_time_conversion_skew * speed); bool sync_f = false; if (units > 0) { // Sync at overflow if (m_time_of_day + units >= 24000) { sync_f = true; ++m_day_count; } m_time_of_day = (m_time_of_day + units) % 24000; if (sync_f) m_time_of_day_f = (float)m_time_of_day / 24000.0; } if (speed > 0) { m_time_conversion_skew -= (f32)units / speed; } if (!sync_f) { m_time_of_day_f += cached_time_of_day_speed / 24 / 3600 * dtime; if (m_time_of_day_f > 1.0) m_time_of_day_f -= 1.0; if (m_time_of_day_f < 0.0) m_time_of_day_f += 1.0; } } u32 Environment::getDayCount() { // Atomic<u32> counter return m_day_count; }