aboutsummaryrefslogtreecommitdiff
path: root/src/network/serverpackethandler.cpp
Commit message (Expand)AuthorAge
...
* [CSM] Add flavour limits controlled by server (#5930)Loïc Blot2017-07-18
* Chat protocol rewrite (#5117)Loïc Blot2017-07-16
* C++11 cleanup inventorymanager (#6077)Vincent Glize2017-07-01
* Remove legacy content_abm.{cpp,h}Loïc Blot2017-06-14
* Use thread_local instead from some static settings (#5955)Loïc Blot2017-06-11
* Have the server send the player list to the client (#5924)red-0012017-06-08
* Remove old network code (#5921)red-0012017-06-06
* C++11 patchset 2: remove util/cpp11.h and util/cpp11_container.h (#5821)Loïc Blot2017-06-04
* Rename Scripting API files for consistencyShadowNinja2017-04-25
* Network:Remove old opcodes and fix documentation. (#5573)red-0012017-04-22
* Fix MSVC build broken by 34d32ceSmallJoker2017-04-17
* Implement delayed server shutdown with cancelation (#4664)Loïc Blot2017-04-15
* Fix "error: ‘playerSAO’ was not declared"Auke Kok2017-04-06
* Fix spacingEkdohibs2017-04-06
* Fix problems when overriding the hand:Ekdohibs2017-04-06
* Fix multiple death messages (#5305)presstabstart2017-04-06
* Update server min protocol version to v24 (#5411)Loïc Blot2017-03-19
* [CSM] Client side moddingLoic Blot2017-03-13
* Wrap to positive degree values (#5106)raymoo2017-01-24
* Cleanup some header inclusions to improve compilation timesLoic Blot2017-01-11
* Breath cheat fix: server sideLoic Blot2017-01-01
* Fix interact range check (thanks to @lhofhansl)sfan52016-12-29
* Various anticheat improvementssfan52016-12-26
* Optimize block sent: Fix rendering issueLars Hofhansl2016-12-03
* Optimize/adjust blocks/ActiveObjects sent at the server based on client setti...lhofhansl2016-11-30
* Wieldhand: Allow overriding the handTeTpaAka2016-11-26
* Add control information to player interacts (#4685)raymoo2016-11-12
* Fix overloading problems mentioned by clangLoic Blot2016-10-30
* PlayerSAO/LocalPlayer refactor: (#4612)Ner'zhul2016-10-30
* More code cleanup (UNORDERED + RemotePlayer/LocalPlayer)Loic Blot2016-10-08
* Player/LocalPlayer/RemotePlayer inheritance cleanup (part 2 on X)Loic Blot2016-10-08
* Player/LocalPlayer/RemotePlayer inheritance cleanup (part 1 on X)Loic Blot2016-10-08
* use unordered containers where possible (patch 4 on X)Loic Blot2016-10-06
* Chat: new settings to prevent spamLoic Blot2016-10-05
* Fix small formatting issue in SRP debug outputsfan52016-03-29
* Much better API for auth.{cpp, h}est312016-03-15
* GOTBLOCKS & DELETEBLOCKS: test packet size only oncenerzhul2016-02-23
* Cache disable_anticheat and check it for "interacted_too_far"ASL972016-01-09
* Add on_secondary_use when right clicking an item in the airAlex Ford2015-12-02
* Only allow players with shout to chatest312015-11-13
* Add server side ncurses terminalest312015-11-06
* Use warningstream for log messages with WARNINGShadowNinja2015-10-14
* Fix how address is logged when a wrong password is suppliedKahrl2015-10-12
* Remove redundant code in player interact handlerkwolekr2015-10-04
* Serialisation: documentation fixes, clarifying renames and whitespace fixesest312015-09-14
* Ask auth handler to create auth when a default password is setest312015-07-21
* Fix damage flash when damage disabledkwolekr2015-07-10
* Use UTF-8 instead of narrowest312015-07-08
* Use actionstream instead of errorstream when failing to emerge playerCraig Davison2015-06-23
* Deny empty username early in the protocolest312015-05-22
'n508' href='#n508'>508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
/*
Minetest
Copyright (C) 2015-2020 paramat
Copyright (C) 2014-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.
*/

#include "mg_ore.h"
#include "mapgen.h"
#include "noise.h"
#include "map.h"
#include "log.h"
#include "util/numeric.h"
#include <cmath>
#include <algorithm>


FlagDesc flagdesc_ore[] = {
	{"absheight",                 OREFLAG_ABSHEIGHT}, // Non-functional
	{"puff_cliffs",               OREFLAG_PUFF_CLIFFS},
	{"puff_additive_composition", OREFLAG_PUFF_ADDITIVE},
	{NULL,                        0}
};


///////////////////////////////////////////////////////////////////////////////


OreManager::OreManager(IGameDef *gamedef) :
	ObjDefManager(gamedef, OBJDEF_ORE)
{
}


size_t OreManager::placeAllOres(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
{
	size_t nplaced = 0;

	for (size_t i = 0; i != m_objects.size(); i++) {
		Ore *ore = (Ore *)m_objects[i];
		if (!ore)
			continue;

		nplaced += ore->placeOre(mg, blockseed, nmin, nmax);
		blockseed++;
	}

	return nplaced;
}


void OreManager::clear()
{
	for (ObjDef *object : m_objects) {
		Ore *ore = (Ore *) object;
		delete ore;
	}
	m_objects.clear();
}


OreManager *OreManager::clone() const
{
	auto mgr = new OreManager();
	ObjDefManager::cloneTo(mgr);
	return mgr;
}


///////////////////////////////////////////////////////////////////////////////


Ore::~Ore()
{
	delete noise;
}


void Ore::resolveNodeNames()
{
	getIdFromNrBacklog(&c_ore, "", CONTENT_AIR);
	getIdsFromNrBacklog(&c_wherein);
}


size_t Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
{
	if (nmin.Y > y_max || nmax.Y < y_min)
		return 0;

	int actual_ymin = MYMAX(nmin.Y, y_min);
	int actual_ymax = MYMIN(nmax.Y, y_max);
	if (clust_size >= actual_ymax - actual_ymin + 1)
		return 0;

	nmin.Y = actual_ymin;
	nmax.Y = actual_ymax;
	generate(mg->vm, mg->seed, blockseed, nmin, nmax, mg->biomemap);

	return 1;
}


void Ore::cloneTo(Ore *def) const
{
	ObjDef::cloneTo(def);
	NodeResolver::cloneTo(def);
	def->c_ore = c_ore;
	def->c_wherein = c_wherein;
	def->clust_scarcity = clust_scarcity;
	def->clust_num_ores = clust_num_ores;
	def->clust_size = clust_size;
	def->y_min = y_min;
	def->y_max = y_max;
	def->ore_param2 = ore_param2;
	def->flags = flags;
	def->nthresh = nthresh;
	def->np = np;
	def->noise = nullptr; // cannot be shared! so created on demand
	def->biomes = biomes;
}


///////////////////////////////////////////////////////////////////////////////


ObjDef *OreScatter::clone() const
{
	auto def = new OreScatter();
	Ore::cloneTo(def);
	return def;
}


void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed,
	v3s16 nmin, v3s16 nmax, biome_t *biomemap)
{
	PcgRandom pr(blockseed);
	MapNode n_ore(c_ore, 0, ore_param2);

	u32 sizex  = (nmax.X - nmin.X + 1);
	u32 volume = (nmax.X - nmin.X + 1) *
				 (nmax.Y - nmin.Y + 1) *
				 (nmax.Z - nmin.Z + 1);
	u32 csize     = clust_size;
	u32 cvolume    = csize * csize * csize;
	u32 nclusters = volume / clust_scarcity;

	for (u32 i = 0; i != nclusters; i++) {
		int x0 = pr.range(nmin.X, nmax.X - csize + 1);
		int y0 = pr.range(nmin.Y, nmax.Y - csize + 1);
		int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);

		if ((flags & OREFLAG_USE_NOISE) &&
			(NoisePerlin3D(&np, x0, y0, z0, mapseed) < nthresh))
			continue;

		if (biomemap && !biomes.empty()) {
			u32 index = sizex * (z0 - nmin.Z) + (x0 - nmin.X);
			auto it = biomes.find(biomemap[index]);
			if (it == biomes.end())
				continue;
		}

		for (u32 z1 = 0; z1 != csize; z1++)
		for (u32 y1 = 0; y1 != csize; y1++)
		for (u32 x1 = 0; x1 != csize; x1++) {
			if (pr.range(1, cvolume) > clust_num_ores)
				continue;

			u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
			if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
				continue;

			vm->m_data[i] = n_ore;
		}
	}
}


///////////////////////////////////////////////////////////////////////////////


ObjDef *OreSheet::clone() const
{
	auto def = new OreSheet();
	Ore::cloneTo(def);

	def->column_height_max = column_height_max;
	def->column_height_min = column_height_min;
	def->column_midpoint_factor = column_midpoint_factor;

	return def;
}


void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed,
	v3s16 nmin, v3s16 nmax, biome_t *biomemap)
{
	PcgRandom pr(blockseed + 4234);
	MapNode n_ore(c_ore, 0, ore_param2);

	u16 max_height = column_height_max;
	int y_start_min = nmin.Y + max_height;
	int y_start_max = nmax.Y - max_height;

	int y_start = y_start_min < y_start_max ?
		pr.range(y_start_min, y_start_max) :
		(y_start_min + y_start_max) / 2;

	if (!noise) {
		int sx = nmax.X - nmin.X + 1;
		int sz = nmax.Z - nmin.Z + 1;
		noise = new Noise(&np, 0, sx, sz);
	}
	noise->seed = mapseed + y_start;
	noise->perlinMap2D(nmin.X, nmin.Z);

	size_t index = 0;
	for (int z = nmin.Z; z <= nmax.Z; z++)
	for (int x = nmin.X; x <= nmax.X; x++, index++) {
		float noiseval = noise->result[index];
		if (noiseval < nthresh)
			continue;

		if (biomemap && !biomes.empty()) {
			auto it = biomes.find(biomemap[index]);
			if (it == biomes.end())
				continue;
		}

		u16 height = pr.range(column_height_min, column_height_max);
		int ymidpoint = y_start + noiseval;
		int y0 = MYMAX(nmin.Y, ymidpoint - height * (1 - column_midpoint_factor));
		int y1 = MYMIN(nmax.Y, y0 + height - 1);

		for (int y = y0; y <= y1; y++) {
			u32 i = vm->m_area.index(x, y, z);
			if (!vm->m_area.contains(i))
				continue;
			if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
				continue;

			vm->m_data[i] = n_ore;
		}
	}
}


///////////////////////////////////////////////////////////////////////////////


OrePuff::~OrePuff()
{
	delete noise_puff_top;
	delete noise_puff_bottom;
}


ObjDef *OrePuff::clone() const
{
	auto def = new OrePuff();
	Ore::cloneTo(def);

	def->np_puff_top = np_puff_top;
	def->np_puff_bottom = np_puff_bottom;
	def->noise_puff_top = nullptr; // cannot be shared, on-demand
	def->noise_puff_bottom = nullptr;

	return def;
}


void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed,
	v3s16 nmin, v3s16 nmax, biome_t *biomemap)
{
	PcgRandom pr(blockseed + 4234);
	MapNode n_ore(c_ore, 0, ore_param2);

	int y_start = pr.range(nmin.Y, nmax.Y);

	if (!noise) {
		int sx = nmax.X - nmin.X + 1;
		int sz = nmax.Z - nmin.Z + 1;
		noise = new Noise(&np, 0, sx, sz);
		noise_puff_top = new Noise(&np_puff_top, 0, sx, sz);
		noise_puff_bottom = new Noise(&np_puff_bottom, 0, sx, sz);
	}

	noise->seed = mapseed + y_start;
	noise->perlinMap2D(nmin.X, nmin.Z);
	bool noise_generated = false;

	size_t index = 0;
	for (int z = nmin.Z; z <= nmax.Z; z++)
	for (int x = nmin.X; x <= nmax.X; x++, index++) {
		float noiseval = noise->result[index];
		if (noiseval < nthresh)
			continue;

		if (biomemap && !biomes.empty()) {
			auto it = biomes.find(biomemap[index]);
			if (it == biomes.end())
				continue;
		}

		if (!noise_generated) {
			noise_generated = true;
			noise_puff_top->perlinMap2D(nmin.X, nmin.Z);
			noise_puff_bottom->perlinMap2D(nmin.X, nmin.Z);
		}

		float ntop    = noise_puff_top->result[index];
		float nbottom = noise_puff_bottom->result[index];

		if (!(flags & OREFLAG_PUFF_CLIFFS)) {
			float ndiff = noiseval - nthresh;
			if (ndiff < 1.0f) {
				ntop *= ndiff;
				nbottom *= ndiff;
			}
		}

		int ymid = y_start;
		int y0 = ymid - nbottom;
		int y1 = ymid + ntop;

		if ((flags & OREFLAG_PUFF_ADDITIVE) && (y0 > y1))
			SWAP(int, y0, y1);

		for (int y = y0; y <= y1; y++) {
			u32 i = vm->m_area.index(x, y, z);
			if (!vm->m_area.contains(i))
				continue;
			if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
				continue;

			vm->m_data[i] = n_ore;
		}
	}
}


///////////////////////////////////////////////////////////////////////////////


ObjDef *OreBlob::clone() const
{
	auto def = new OreBlob();
	Ore::cloneTo(def);
	return def;
}


void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed,
	v3s16 nmin, v3s16 nmax, biome_t *biomemap)
{
	PcgRandom pr(blockseed + 2404);
	MapNode n_ore(c_ore, 0, ore_param2);

	u32 sizex  = (nmax.X - nmin.X + 1);
	u32 volume = (nmax.X - nmin.X + 1) *
				 (nmax.Y - nmin.Y + 1) *
				 (nmax.Z - nmin.Z + 1);
	u32 csize  = clust_size;
	u32 nblobs = volume / clust_scarcity;

	if (!noise)
		noise = new Noise(&np, mapseed, csize, csize, csize);

	for (u32 i = 0; i != nblobs; i++) {
		int x0 = pr.range(nmin.X, nmax.X - csize + 1);
		int y0 = pr.range(nmin.Y, nmax.Y - csize + 1);
		int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);

		if (biomemap && !biomes.empty()) {
			u32 bmapidx = sizex * (z0 - nmin.Z) + (x0 - nmin.X);
			auto it = biomes.find(biomemap[bmapidx]);
			if (it == biomes.end())
				continue;
		}

		bool noise_generated = false;
		noise->seed = blockseed + i;

		size_t index = 0;
		for (u32 z1 = 0; z1 != csize; z1++)
		for (u32 y1 = 0; y1 != csize; y1++)
		for (u32 x1 = 0; x1 != csize; x1++, index++) {
			u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1);
			if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
				continue;

			// Lazily generate noise only if there's a chance of ore being placed
			// This simple optimization makes calls 6x faster on average
			if (!noise_generated) {
				noise_generated = true;
				noise->perlinMap3D(x0, y0, z0);
			}

			float noiseval = noise->result[index];

			float xdist = (s32)x1 - (s32)csize / 2;
			float ydist = (s32)y1 - (s32)csize / 2;
			float zdist = (s32)z1 - (s32)csize / 2;

			noiseval -= std::sqrt(xdist * xdist + ydist * ydist + zdist * zdist) / csize;

			if (noiseval < nthresh)
				continue;

			vm->m_data[i] = n_ore;
		}
	}
}


///////////////////////////////////////////////////////////////////////////////


OreVein::~OreVein()
{
	delete noise2;
}


ObjDef *OreVein::clone() const
{
	auto def = new OreVein();
	Ore::cloneTo(def);

	def->random_factor = random_factor;
	def->noise2 = nullptr; // cannot be shared, on-demand
	def->sizey_prev = sizey_prev;

	return def;
}


void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed,
	v3s16 nmin, v3s16 nmax, biome_t *biomemap)
{
	PcgRandom pr(blockseed + 520);
	MapNode n_ore(c_ore, 0, ore_param2);

	int sizex = nmax.X - nmin.X + 1;
	int sizey = nmax.Y - nmin.Y + 1;
	// Because this ore uses 3D noise the perlinmap Y size can be different in
	// different mapchunks due to ore Y limits. So recreate the noise objects
	// if Y size has changed.
	// Because these noise objects are created multiple times for this ore type
	// it is necessary to 'delete' them here.
	if (!noise || sizey != sizey_prev) {
		delete noise;
		delete noise2;
		int sizez = nmax.Z - nmin.Z + 1;
		noise  = new Noise(&np, mapseed, sizex, sizey, sizez);
		noise2 = new Noise(&np, mapseed + 436, sizex, sizey, sizez);
		sizey_prev = sizey;
	}

	bool noise_generated = false;
	size_t index = 0;
	for (int z = nmin.Z; z <= nmax.Z; z++)
	for (int y = nmin.Y; y <= nmax.Y; y++)
	for (int x = nmin.X; x <= nmax.X; x++, index++) {
		u32 i = vm->m_area.index(x, y, z);
		if (!vm->m_area.contains(i))
			continue;
		if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
			continue;

		if (biomemap && !biomes.empty()) {
			u32 bmapidx = sizex * (z - nmin.Z) + (x - nmin.X);
			auto it = biomes.find(biomemap[bmapidx]);
			if (it == biomes.end())
				continue;
		}

		// Same lazy generation optimization as in OreBlob
		if (!noise_generated) {
			noise_generated = true;
			noise->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
			noise2->perlinMap3D(nmin.X, nmin.Y, nmin.Z);
		}

		// randval ranges from -1..1
		/*
			Note: can generate values slightly larger than 1
			but this can't be changed as mapgen must be deterministic accross versions.
		*/
		float randval   = (float)pr.next() / float(pr.RANDOM_RANGE / 2) - 1.f;
		float noiseval  = contour(noise->result[index]);
		float noiseval2 = contour(noise2->result[index]);
		if (noiseval * noiseval2 + randval * random_factor < nthresh)
			continue;

		vm->m_data[i] = n_ore;
	}
}


///////////////////////////////////////////////////////////////////////////////


OreStratum::~OreStratum()
{
	delete noise_stratum_thickness;
}


ObjDef *OreStratum::clone() const
{
	auto def = new OreStratum();
	Ore::cloneTo(def);

	def->np_stratum_thickness = np_stratum_thickness;
	def->noise_stratum_thickness = nullptr; // cannot be shared, on-demand
	def->stratum_thickness = stratum_thickness;

	return def;
}


void OreStratum::generate(MMVManip *vm, int mapseed, u32 blockseed,
	v3s16 nmin, v3s16 nmax, biome_t *biomemap)
{
	PcgRandom pr(blockseed + 4234);
	MapNode n_ore(c_ore, 0, ore_param2);

	if (flags & OREFLAG_USE_NOISE) {
		if (!noise) {
			int sx = nmax.X - nmin.X + 1;
			int sz = nmax.Z - nmin.Z + 1;
			noise = new Noise(&np, 0, sx, sz);
		}
		noise->perlinMap2D(nmin.X, nmin.Z);
	}

	if (flags & OREFLAG_USE_NOISE2) {
		if (!noise_stratum_thickness) {
			int sx = nmax.X - nmin.X + 1;
			int sz = nmax.Z - nmin.Z + 1;
			noise_stratum_thickness = new Noise(&np_stratum_thickness, 0, sx, sz);
		}
		noise_stratum_thickness->perlinMap2D(nmin.X, nmin.Z);
	}

	size_t index = 0;

	for (int z = nmin.Z; z <= nmax.Z; z++)
	for (int x = nmin.X; x <= nmax.X; x++, index++) {
		if (biomemap && !biomes.empty()) {
			auto it = biomes.find(biomemap[index]);
			if (it == biomes.end())
				continue;
		}

		int y0;
		int y1;

		if (flags & OREFLAG_USE_NOISE) {
			float nhalfthick = ((flags & OREFLAG_USE_NOISE2) ?
				noise_stratum_thickness->result[index] : (float)stratum_thickness) /
				2.0f;
			float nmid = noise->result[index];
			y0 = MYMAX(nmin.Y, std::ceil(nmid - nhalfthick));
			y1 = MYMIN(nmax.Y, nmid + nhalfthick);
		} else { // Simple horizontal stratum
			y0 = nmin.Y;
			y1 = nmax.Y;
		}

		for (int y = y0; y <= y1; y++) {
			if (pr.range(1, clust_scarcity) != 1)
				continue;

			u32 i = vm->m_area.index(x, y, z);
			if (!vm->m_area.contains(i))
				continue;
			if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
				continue;

			vm->m_data[i] = n_ore;
		}
	}
}