mirror of
https://github.com/minetest/minetest.git
synced 2024-12-23 14:42:24 +01:00
mapgen stuff
This commit is contained in:
parent
7f2aa30bf2
commit
ea6740e900
@ -58,7 +58,6 @@ set(common_SRCS
|
||||
socket.cpp
|
||||
mapblock.cpp
|
||||
mapsector.cpp
|
||||
heightmap.cpp
|
||||
map.cpp
|
||||
player.cpp
|
||||
utility.cpp
|
||||
|
@ -97,12 +97,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
/*
|
||||
This is good to be a bit different than 0 so that water level
|
||||
is not between to MapBlocks
|
||||
is not between two MapBlocks
|
||||
*/
|
||||
#define WATER_LEVEL 3
|
||||
#define WATER_LEVEL 1
|
||||
|
||||
// Length of cracking animation in count of images
|
||||
#define CRACK_ANIMATION_LENGTH 5
|
||||
|
||||
// Some stuff needed by old code moved to here from heightmap.h
|
||||
#define GROUNDHEIGHT_NOTFOUND_SETVALUE (-10e6)
|
||||
#define GROUNDHEIGHT_VALID_MINVALUE ( -9e6)
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -115,6 +115,7 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
|
||||
L"- Mouse left: dig blocks\n"
|
||||
L"- Mouse right: place blocks\n"
|
||||
L"- Mouse wheel: select item\n"
|
||||
L"- 0...9: select item\n"
|
||||
L"- R: Toggle viewing all loaded chunks\n"
|
||||
L"- I: Inventory menu\n"
|
||||
L"- ESC: This menu\n"
|
||||
|
1060
src/heightmap.cpp
1060
src/heightmap.cpp
File diff suppressed because it is too large
Load Diff
572
src/heightmap.h
572
src/heightmap.h
@ -1,572 +0,0 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU 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.
|
||||
*/
|
||||
|
||||
#ifndef HEIGHTMAP_HEADER
|
||||
#define HEIGHTMAP_HEADER
|
||||
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "debug.h"
|
||||
#include "common_irrlicht.h"
|
||||
#include "exceptions.h"
|
||||
#include "utility.h"
|
||||
#include "serialization.h"
|
||||
|
||||
#define GROUNDHEIGHT_NOTFOUND_SETVALUE (-10e6)
|
||||
#define GROUNDHEIGHT_VALID_MINVALUE ( -9e6)
|
||||
|
||||
class Heightmappish
|
||||
{
|
||||
public:
|
||||
virtual f32 getGroundHeight(v2s16 p, bool generate=true) = 0;
|
||||
virtual void setGroundHeight(v2s16 p, f32 y, bool generate=true) = 0;
|
||||
|
||||
v2f32 getSlope(v2s16 p)
|
||||
{
|
||||
f32 y0 = getGroundHeight(p, false);
|
||||
|
||||
v2s16 dirs[] = {
|
||||
v2s16(1,0),
|
||||
v2s16(0,1),
|
||||
};
|
||||
|
||||
v2f32 fdirs[] = {
|
||||
v2f32(1,0),
|
||||
v2f32(0,1),
|
||||
};
|
||||
|
||||
v2f32 slopevector(0.0, 0.0);
|
||||
|
||||
for(u16 i=0; i<2; i++){
|
||||
f32 y1 = 0.0;
|
||||
f32 y2 = 0.0;
|
||||
f32 count = 0.0;
|
||||
|
||||
v2s16 p1 = p - dirs[i];
|
||||
y1 = getGroundHeight(p1, false);
|
||||
if(y1 > GROUNDHEIGHT_VALID_MINVALUE){
|
||||
y1 -= y0;
|
||||
count += 1.0;
|
||||
}
|
||||
else
|
||||
y1 = 0;
|
||||
|
||||
v2s16 p2 = p + dirs[i];
|
||||
y2 = getGroundHeight(p2, false);
|
||||
if(y2 > GROUNDHEIGHT_VALID_MINVALUE){
|
||||
y2 -= y0;
|
||||
count += 1.0;
|
||||
}
|
||||
else
|
||||
y2 = 0;
|
||||
|
||||
if(count < 0.001)
|
||||
return v2f32(0.0, 0.0);
|
||||
|
||||
/*
|
||||
If y2 is higher than y1, slope is positive
|
||||
*/
|
||||
f32 slope = (y2 - y1)/count;
|
||||
|
||||
slopevector += fdirs[i] * slope;
|
||||
}
|
||||
|
||||
return slopevector;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// TODO: Get rid of this dummy wrapper
|
||||
class Heightmap : public Heightmappish /*, public ReferenceCounted*/
|
||||
{
|
||||
};
|
||||
|
||||
class WrapperHeightmap : public Heightmap
|
||||
{
|
||||
Heightmappish *m_target;
|
||||
public:
|
||||
|
||||
WrapperHeightmap(Heightmappish *target):
|
||||
m_target(target)
|
||||
{
|
||||
if(target == NULL)
|
||||
throw NullPointerException();
|
||||
}
|
||||
|
||||
f32 getGroundHeight(v2s16 p, bool generate=true)
|
||||
{
|
||||
return m_target->getGroundHeight(p, generate);
|
||||
}
|
||||
void setGroundHeight(v2s16 p, f32 y, bool generate=true)
|
||||
{
|
||||
m_target->setGroundHeight(p, y, generate);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Base class that defines a generator that gives out values at
|
||||
positions in 2-dimensional space.
|
||||
Can be given to UnlimitedHeightmap to feed stuff.
|
||||
|
||||
These are always serialized as readable text ending in "\n"
|
||||
*/
|
||||
class ValueGenerator
|
||||
{
|
||||
public:
|
||||
ValueGenerator(){}
|
||||
virtual ~ValueGenerator(){}
|
||||
|
||||
static ValueGenerator* deSerialize(std::string line);
|
||||
|
||||
static ValueGenerator* deSerialize(std::istream &is)
|
||||
{
|
||||
std::string line;
|
||||
std::getline(is, line, '\n');
|
||||
return deSerialize(line);
|
||||
}
|
||||
|
||||
void serializeBase(std::ostream &os)
|
||||
{
|
||||
os<<getName()<<" ";
|
||||
}
|
||||
|
||||
// Virtual methods
|
||||
virtual const char * getName() const = 0;
|
||||
virtual f32 getValue(v2s16 p) = 0;
|
||||
virtual void serialize(std::ostream &os) = 0;
|
||||
};
|
||||
|
||||
class ConstantGenerator : public ValueGenerator
|
||||
{
|
||||
public:
|
||||
f32 m_value;
|
||||
|
||||
ConstantGenerator(f32 value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
const char * getName() const
|
||||
{
|
||||
return "constant";
|
||||
}
|
||||
|
||||
f32 getValue(v2s16 p)
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os)
|
||||
{
|
||||
serializeBase(os);
|
||||
|
||||
std::ostringstream ss;
|
||||
//ss.imbue(std::locale("C"));
|
||||
|
||||
ss<<m_value<<"\n";
|
||||
|
||||
os<<ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class LinearGenerator : public ValueGenerator
|
||||
{
|
||||
public:
|
||||
f32 m_height;
|
||||
v2f m_slope;
|
||||
|
||||
LinearGenerator(f32 height, v2f slope)
|
||||
{
|
||||
m_height = height;
|
||||
m_slope = slope;
|
||||
}
|
||||
|
||||
const char * getName() const
|
||||
{
|
||||
return "linear";
|
||||
}
|
||||
|
||||
f32 getValue(v2s16 p)
|
||||
{
|
||||
return m_height + m_slope.X * p.X + m_slope.Y * p.Y;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os)
|
||||
{
|
||||
serializeBase(os);
|
||||
|
||||
std::ostringstream ss;
|
||||
//ss.imbue(std::locale("C"));
|
||||
|
||||
ss<<m_height<<" "<<m_slope.X<<" "<<m_slope.Y<<"\n";
|
||||
|
||||
os<<ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class PowerGenerator : public ValueGenerator
|
||||
{
|
||||
public:
|
||||
f32 m_height;
|
||||
v2f m_slope;
|
||||
f32 m_power;
|
||||
|
||||
PowerGenerator(f32 height, v2f slope, f32 power)
|
||||
{
|
||||
m_height = height;
|
||||
m_slope = slope;
|
||||
m_power = power;
|
||||
}
|
||||
|
||||
const char * getName() const
|
||||
{
|
||||
return "power";
|
||||
}
|
||||
|
||||
f32 getValue(v2s16 p)
|
||||
{
|
||||
return m_height
|
||||
+ m_slope.X * pow((f32)p.X, m_power)
|
||||
+ m_slope.Y * pow((f32)p.Y, m_power);
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os)
|
||||
{
|
||||
serializeBase(os);
|
||||
|
||||
std::ostringstream ss;
|
||||
//ss.imbue(std::locale("C"));
|
||||
|
||||
ss<<m_height<<" "
|
||||
<<m_slope.X<<" "
|
||||
<<m_slope.Y<<" "
|
||||
<<m_power<<"\n";
|
||||
|
||||
os<<ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
class FixedHeightmap : public Heightmap
|
||||
{
|
||||
// A meta-heightmap on which this heightmap is located
|
||||
// (at m_pos_on_master * m_blocksize)
|
||||
Heightmap * m_master;
|
||||
// Position on master heightmap (in blocks)
|
||||
v2s16 m_pos_on_master;
|
||||
s32 m_blocksize; // This is (W-1) = (H-1)
|
||||
// These are the actual size of the data
|
||||
s32 W;
|
||||
s32 H;
|
||||
f32 *m_data;
|
||||
|
||||
public:
|
||||
|
||||
FixedHeightmap(Heightmap * master,
|
||||
v2s16 pos_on_master, s32 blocksize):
|
||||
m_master(master),
|
||||
m_pos_on_master(pos_on_master),
|
||||
m_blocksize(blocksize)
|
||||
{
|
||||
W = m_blocksize+1;
|
||||
H = m_blocksize+1;
|
||||
m_data = NULL;
|
||||
m_data = new f32[(blocksize+1)*(blocksize+1)];
|
||||
|
||||
for(s32 i=0; i<(blocksize+1)*(blocksize+1); i++){
|
||||
m_data[i] = GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
}
|
||||
}
|
||||
|
||||
~FixedHeightmap()
|
||||
{
|
||||
if(m_data)
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
v2s16 getPosOnMaster()
|
||||
{
|
||||
return m_pos_on_master;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: BorderWrapper class or something to allow defining
|
||||
borders that wrap to an another heightmap. The algorithm
|
||||
should be allowed to edit stuff over the border and on
|
||||
the border in that case, too.
|
||||
This will allow non-square heightmaps, too. (probably)
|
||||
*/
|
||||
|
||||
void print()
|
||||
{
|
||||
printf("FixedHeightmap::print(): size is %ix%i\n", W, H);
|
||||
for(s32 y=0; y<H; y++){
|
||||
for(s32 x=0; x<W; x++){
|
||||
/*if(getSeeded(v2s16(x,y)))
|
||||
printf("S");*/
|
||||
f32 n = getGroundHeight(v2s16(x,y));
|
||||
if(n < GROUNDHEIGHT_VALID_MINVALUE)
|
||||
printf(" - ");
|
||||
else
|
||||
printf("% -5.1f ", getGroundHeight(v2s16(x,y)));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool overborder(v2s16 p)
|
||||
{
|
||||
return (p.X < 0 || p.X >= W || p.Y < 0 || p.Y >= H);
|
||||
}
|
||||
|
||||
bool atborder(v2s16 p)
|
||||
{
|
||||
if(overborder(p))
|
||||
return false;
|
||||
return (p.X == 0 || p.X == W-1 || p.Y == 0 || p.Y == H-1);
|
||||
}
|
||||
|
||||
void setGroundHeight(v2s16 p, f32 y, bool generate=false)
|
||||
{
|
||||
/*dstream<<"FixedHeightmap::setGroundHeight(("
|
||||
<<p.X<<","<<p.Y
|
||||
<<"), "<<y<<")"<<std::endl;*/
|
||||
if(overborder(p))
|
||||
throw InvalidPositionException();
|
||||
m_data[p.Y*W + p.X] = y;
|
||||
}
|
||||
|
||||
// Returns true on success, false on railure.
|
||||
bool setGroundHeightParent(v2s16 p, f32 y, bool generate=false)
|
||||
{
|
||||
/*// Position on master
|
||||
v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
|
||||
v2s16 nodepos_master = blockpos_nodes + p;
|
||||
dstream<<"FixedHeightmap::setGroundHeightParent(("
|
||||
<<p.X<<","<<p.Y
|
||||
<<"), "<<y<<"): nodepos_master=("
|
||||
<<nodepos_master.X<<","
|
||||
<<nodepos_master.Y<<")"<<std::endl;
|
||||
m_master->setGroundHeight(nodepos_master, y, false);*/
|
||||
|
||||
// Try to set on master
|
||||
bool master_got_it = false;
|
||||
if(overborder(p) || atborder(p))
|
||||
{
|
||||
try{
|
||||
// Position on master
|
||||
v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
|
||||
v2s16 nodepos_master = blockpos_nodes + p;
|
||||
m_master->setGroundHeight(nodepos_master, y, false);
|
||||
|
||||
master_got_it = true;
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if(overborder(p))
|
||||
return master_got_it;
|
||||
|
||||
setGroundHeight(p, y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
f32 getGroundHeight(v2s16 p, bool generate=false)
|
||||
{
|
||||
if(overborder(p))
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
return m_data[p.Y*W + p.X];
|
||||
}
|
||||
|
||||
f32 getGroundHeightParent(v2s16 p)
|
||||
{
|
||||
/*v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
|
||||
return m_master->getGroundHeight(blockpos_nodes + p, false);*/
|
||||
|
||||
if(overborder(p) == false){
|
||||
f32 h = getGroundHeight(p);
|
||||
if(h > GROUNDHEIGHT_VALID_MINVALUE)
|
||||
return h;
|
||||
}
|
||||
|
||||
// Position on master
|
||||
v2s16 blockpos_nodes = m_pos_on_master * m_blocksize;
|
||||
f32 h = m_master->getGroundHeight(blockpos_nodes + p, false);
|
||||
return h;
|
||||
}
|
||||
|
||||
f32 avgNeighbours(v2s16 p, s16 d);
|
||||
|
||||
f32 avgDiagNeighbours(v2s16 p, s16 d);
|
||||
|
||||
void makeDiamond(
|
||||
v2s16 center,
|
||||
s16 a,
|
||||
f32 randmax,
|
||||
core::map<v2s16, bool> &next_squares);
|
||||
|
||||
void makeSquare(
|
||||
v2s16 center,
|
||||
s16 a,
|
||||
f32 randmax,
|
||||
core::map<v2s16, bool> &next_diamonds);
|
||||
|
||||
void DiamondSquare(f32 randmax, f32 randfactor);
|
||||
|
||||
/*
|
||||
corners: [i]=XY: [0]=00, [1]=10, [2]=11, [3]=10
|
||||
*/
|
||||
void generateContinued(f32 randmax, f32 randfactor, f32 *corners);
|
||||
|
||||
|
||||
static u32 serializedLength(u8 version, u16 blocksize);
|
||||
u32 serializedLength(u8 version);
|
||||
void serialize(u8 *dest, u8 version);
|
||||
void deSerialize(u8 *source, u8 version);
|
||||
/*static FixedHeightmap * deSerialize(u8 *source, u32 size,
|
||||
u32 &usedsize, Heightmap *master, u8 version);*/
|
||||
};
|
||||
|
||||
class OneChildHeightmap : public Heightmap
|
||||
{
|
||||
s16 m_blocksize;
|
||||
|
||||
public:
|
||||
|
||||
FixedHeightmap m_child;
|
||||
|
||||
OneChildHeightmap(s16 blocksize):
|
||||
m_blocksize(blocksize),
|
||||
m_child(this, v2s16(0,0), blocksize)
|
||||
{
|
||||
}
|
||||
|
||||
f32 getGroundHeight(v2s16 p, bool generate=true)
|
||||
{
|
||||
if(p.X < 0 || p.X > m_blocksize
|
||||
|| p.Y < 0 || p.Y > m_blocksize)
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
return m_child.getGroundHeight(p);
|
||||
}
|
||||
void setGroundHeight(v2s16 p, f32 y, bool generate=true)
|
||||
{
|
||||
//dstream<<"OneChildHeightmap::setGroundHeight()"<<std::endl;
|
||||
if(p.X < 0 || p.X > m_blocksize
|
||||
|| p.Y < 0 || p.Y > m_blocksize)
|
||||
throw InvalidPositionException();
|
||||
m_child.setGroundHeight(p, y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
This is a dynamic container of an arbitrary number of heightmaps
|
||||
at arbitrary positions.
|
||||
|
||||
It is able to redirect queries to the corresponding heightmaps and
|
||||
it generates new heightmaps on-the-fly according to the relevant
|
||||
parameters.
|
||||
|
||||
It doesn't have a master heightmap because it is meant to be used
|
||||
as such itself.
|
||||
|
||||
Child heightmaps are spaced at m_blocksize distances, and are of
|
||||
size (m_blocksize+1)*(m_blocksize+1)
|
||||
|
||||
This is used as the master heightmap of a Map object.
|
||||
*/
|
||||
class UnlimitedHeightmap: public Heightmap
|
||||
{
|
||||
private:
|
||||
|
||||
core::map<v2s16, FixedHeightmap*> m_heightmaps;
|
||||
s16 m_blocksize;
|
||||
|
||||
// TODO: Remove ValueGenerators
|
||||
/*ValueGenerator *m_randmax_generator;
|
||||
ValueGenerator *m_randfactor_generator;
|
||||
ValueGenerator *m_base_generator;*/
|
||||
|
||||
PointAttributeDatabase *m_padb;
|
||||
|
||||
public:
|
||||
|
||||
UnlimitedHeightmap(
|
||||
s16 blocksize,
|
||||
/*ValueGenerator *randmax_generator,
|
||||
ValueGenerator *randfactor_generator,
|
||||
ValueGenerator *base_generator,*/
|
||||
PointAttributeDatabase *padb
|
||||
):
|
||||
m_blocksize(blocksize),
|
||||
/*m_randmax_generator(randmax_generator),
|
||||
m_randfactor_generator(randfactor_generator),
|
||||
m_base_generator(base_generator),*/
|
||||
m_padb(padb)
|
||||
{
|
||||
/*assert(m_randmax_generator != NULL);
|
||||
assert(m_randfactor_generator != NULL);
|
||||
assert(m_base_generator != NULL);*/
|
||||
assert(m_padb);
|
||||
}
|
||||
|
||||
~UnlimitedHeightmap()
|
||||
{
|
||||
core::map<v2s16, FixedHeightmap*>::Iterator i;
|
||||
i = m_heightmaps.getIterator();
|
||||
for(; i.atEnd() == false; i++)
|
||||
{
|
||||
delete i.getNode()->getValue();
|
||||
}
|
||||
|
||||
/*delete m_randmax_generator;
|
||||
delete m_randfactor_generator;
|
||||
delete m_base_generator;*/
|
||||
}
|
||||
|
||||
void print();
|
||||
|
||||
v2s16 getNodeHeightmapPos(v2s16 p)
|
||||
{
|
||||
return v2s16(
|
||||
(p.X>=0 ? p.X : p.X-m_blocksize+1) / m_blocksize,
|
||||
(p.Y>=0 ? p.Y : p.Y-m_blocksize+1) / m_blocksize);
|
||||
}
|
||||
|
||||
// Can throw an InvalidPositionException
|
||||
FixedHeightmap * getHeightmap(v2s16 p, bool generate=true);
|
||||
|
||||
f32 getGroundHeight(v2s16 p, bool generate=true);
|
||||
void setGroundHeight(v2s16 p, f32 y, bool generate=true);
|
||||
|
||||
/*static UnlimitedHeightmap * deSerialize(u8 *source, u32 maxsize,
|
||||
u32 &usedsize, u8 version);*/
|
||||
|
||||
//SharedBuffer<u8> serialize(u8 version);
|
||||
void serialize(std::ostream &os, u8 version);
|
||||
static UnlimitedHeightmap * deSerialize(std::istream &istr,
|
||||
PointAttributeDatabase *padb);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
70
src/main.cpp
70
src/main.cpp
@ -320,40 +320,42 @@ Doing now (most important at the top):
|
||||
# maybe done
|
||||
* not done
|
||||
|
||||
* Perlin noise stuff sucks in heightmap generation, fix it
|
||||
* Create perlin noise functions and use them to get natural randomness
|
||||
in everything. No need for attributes or fractal terrain.
|
||||
* Do something about AttributeDatabase/List being too slow
|
||||
- Remove it
|
||||
=== Stuff to do before release
|
||||
* Save map seed to a metafile (with version information)
|
||||
- map/meta.txt, which should contain only plain text, something like this:
|
||||
seed = O7+BZT9Vk/iVYiBlZ2dsb6zemp4xdGVysJqYmNt2X+MQ+Kg1
|
||||
chunksize = 8
|
||||
- map/chunks/
|
||||
-
|
||||
- Compressed bunch of data... um, actually no.
|
||||
- Make a directory for every chunk instead, which contains
|
||||
sectors and blocks
|
||||
* Save chunk metadata on disk
|
||||
* Remove all kinds of systems that are made redundant by the new map
|
||||
generator
|
||||
- Sector heightmaps? At least they should be made redundant.
|
||||
- Sector objects
|
||||
* Fix the strange mineral occurences
|
||||
- Do they appear anymore?
|
||||
* Make server find the spawning place from the real map data, not from
|
||||
the heightmap
|
||||
- But the changing borders of chunk have to be avoided, because
|
||||
there is time to generate only one chunk.
|
||||
* only_from_disk might not work anymore - check and fix it.
|
||||
* Make the generator to run in background and not blocking block
|
||||
placement and transfer
|
||||
* only_from_disk might not work anymore - check and fix it.
|
||||
|
||||
=== Stuff to do after release
|
||||
* Add some kind of erosion and other stuff that now is possible
|
||||
* Make client to fetch stuff asynchronously
|
||||
- Needs method SyncProcessData
|
||||
* What is the problem with the server constantly saving one or a few
|
||||
* Fix the problem with the server constantly saving one or a few
|
||||
blocks? List the first saved block, maybe it explains.
|
||||
- Does it still do this?
|
||||
- It is probably caused by oscillating water
|
||||
* Water doesn't start flowing after map generation like it should
|
||||
- Are there still problems?
|
||||
* Better water generation (spread it to underwater caverns)
|
||||
* Better water generation (spread it to underwater caverns but don't
|
||||
fill dungeons that don't touch outside air)
|
||||
* When generating a chunk and the neighboring chunk doesn't have mud
|
||||
and stuff yet and the ground is fairly flat, the mud will flow to
|
||||
the other chunk making nasty straight walls when the other chunk
|
||||
is generated. Fix it.
|
||||
* Save map seed to a metafile (with version information)
|
||||
- Remove master heightmap
|
||||
* Make a small history check to transformLiquids to detect and log
|
||||
continuous oscillations, in such detail that they can be fixed.
|
||||
|
||||
======================================================================
|
||||
|
||||
@ -666,7 +668,7 @@ public:
|
||||
}
|
||||
|
||||
// Material selection
|
||||
if(event.KeyInput.Key == irr::KEY_KEY_F)
|
||||
/*if(event.KeyInput.Key == irr::KEY_KEY_F)
|
||||
{
|
||||
if(g_selected_item < PLAYER_INVENTORY_SIZE-1)
|
||||
g_selected_item++;
|
||||
@ -674,6 +676,18 @@ public:
|
||||
g_selected_item = 0;
|
||||
dstream<<DTIME<<"Selected item: "
|
||||
<<g_selected_item<<std::endl;
|
||||
}*/
|
||||
|
||||
if(event.KeyInput.Key >= irr::KEY_KEY_0
|
||||
&& event.KeyInput.Key <= irr::KEY_KEY_9)
|
||||
{
|
||||
u16 s1 = event.KeyInput.Key - irr::KEY_KEY_0;
|
||||
if(event.KeyInput.Key == irr::KEY_KEY_0)
|
||||
s1 = 10;
|
||||
if(s1 < PLAYER_INVENTORY_SIZE)
|
||||
g_selected_item = s1-1;
|
||||
dstream<<DTIME<<"Selected item: "
|
||||
<<g_selected_item<<std::endl;
|
||||
}
|
||||
|
||||
// Viewing range selection
|
||||
@ -1009,7 +1023,7 @@ public:
|
||||
if(counter1 < 0.0)
|
||||
{
|
||||
counter1 = 0.1*Rand(1, 40);
|
||||
keydown[irr::KEY_KEY_2] = !keydown[irr::KEY_KEY_2];
|
||||
keydown[irr::KEY_KEY_E] = !keydown[irr::KEY_KEY_E];
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -1595,18 +1609,6 @@ int main(int argc, char *argv[])
|
||||
run_tests();
|
||||
}
|
||||
|
||||
// Read map parameters from settings
|
||||
|
||||
HMParams hm_params;
|
||||
/*hm_params.blocksize = g_settings.getU16("heightmap_blocksize");
|
||||
hm_params.randmax = g_settings.get("height_randmax");
|
||||
hm_params.randfactor = g_settings.get("height_randfactor");
|
||||
hm_params.base = g_settings.get("height_base");*/
|
||||
|
||||
MapParams map_params;
|
||||
map_params.plants_amount = g_settings.getFloat("plants_amount");
|
||||
map_params.ravines_amount = g_settings.getFloat("ravines_amount");
|
||||
|
||||
/*
|
||||
Some parameters
|
||||
*/
|
||||
@ -1631,7 +1633,7 @@ int main(int argc, char *argv[])
|
||||
DSTACK("Dedicated server branch");
|
||||
|
||||
// Create server
|
||||
Server server(map_dir.c_str(), hm_params, map_params);
|
||||
Server server(map_dir.c_str());
|
||||
server.start(port);
|
||||
|
||||
// Run server
|
||||
@ -1946,7 +1948,7 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
SharedPtr<Server> server;
|
||||
if(address == ""){
|
||||
server = new Server(map_dir, hm_params, map_params);
|
||||
server = new Server(map_dir);
|
||||
server->start(port);
|
||||
}
|
||||
|
||||
@ -2266,7 +2268,7 @@ int main(int argc, char *argv[])
|
||||
g_input->isKeyDown(irr::KEY_KEY_A),
|
||||
g_input->isKeyDown(irr::KEY_KEY_D),
|
||||
g_input->isKeyDown(irr::KEY_SPACE),
|
||||
g_input->isKeyDown(irr::KEY_KEY_2),
|
||||
g_input->isKeyDown(irr::KEY_KEY_E),
|
||||
camera_pitch,
|
||||
camera_yaw
|
||||
);
|
||||
|
856
src/map.cpp
856
src/map.cpp
File diff suppressed because it is too large
Load Diff
60
src/map.h
60
src/map.h
@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#endif
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "heightmap.h"
|
||||
//#include "heightmap.h"
|
||||
#include "mapnode.h"
|
||||
#include "mapblock.h"
|
||||
#include "mapsector.h"
|
||||
@ -46,7 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define MAPTYPE_SERVER 1
|
||||
#define MAPTYPE_CLIENT 2
|
||||
|
||||
class Map : public NodeContainer, public Heightmappish
|
||||
class Map : public NodeContainer
|
||||
{
|
||||
public:
|
||||
|
||||
@ -273,42 +273,12 @@ protected:
|
||||
MapSector *m_sector_cache;
|
||||
v2s16 m_sector_cache_p;
|
||||
|
||||
WrapperHeightmap m_hwrapper;
|
||||
//WrapperHeightmap m_hwrapper;
|
||||
|
||||
// Queued transforming water nodes
|
||||
UniqueQueue<v3s16> m_transforming_liquid;
|
||||
};
|
||||
|
||||
// Master heightmap parameters
|
||||
struct HMParams
|
||||
{
|
||||
HMParams()
|
||||
{
|
||||
blocksize = 64;
|
||||
randmax = "constant 70.0";
|
||||
randfactor = "constant 0.6";
|
||||
base = "linear 0 80 0";
|
||||
}
|
||||
s16 blocksize;
|
||||
std::string randmax;
|
||||
std::string randfactor;
|
||||
std::string base;
|
||||
};
|
||||
|
||||
// Map parameters
|
||||
struct MapParams
|
||||
{
|
||||
MapParams()
|
||||
{
|
||||
plants_amount = 1.0;
|
||||
ravines_amount = 1.0;
|
||||
//max_objects_in_block = 30;
|
||||
}
|
||||
float plants_amount;
|
||||
float ravines_amount;
|
||||
//u16 max_objects_in_block;
|
||||
};
|
||||
|
||||
/*
|
||||
ServerMap
|
||||
|
||||
@ -321,7 +291,7 @@ public:
|
||||
/*
|
||||
savedir: directory to which map data should be saved
|
||||
*/
|
||||
ServerMap(std::string savedir, HMParams hmp, MapParams mp);
|
||||
ServerMap(std::string savedir);
|
||||
~ServerMap();
|
||||
|
||||
s32 mapType() const
|
||||
@ -504,7 +474,16 @@ public:
|
||||
|
||||
void save(bool only_changed);
|
||||
void loadAll();
|
||||
|
||||
|
||||
// TODO
|
||||
void saveMapMeta();
|
||||
void loadMapMeta();
|
||||
|
||||
// TODO
|
||||
void saveChunkMeta();
|
||||
void loadChunkMeta();
|
||||
|
||||
// DEPRECATED
|
||||
void saveMasterHeightmap();
|
||||
void loadMasterHeightmap();
|
||||
|
||||
@ -512,6 +491,7 @@ public:
|
||||
|
||||
// This only saves sector-specific data such as the heightmap
|
||||
// (no MapBlocks)
|
||||
// DEPRECATED? Sectors have no metadata anymore.
|
||||
void saveSectorMeta(ServerMapSector *sector);
|
||||
MapSector* loadSectorMeta(std::string dirname);
|
||||
|
||||
@ -527,17 +507,13 @@ public:
|
||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
||||
|
||||
// Gets from master heightmap
|
||||
// DEPRECATED?
|
||||
void getSectorCorners(v2s16 p2d, s16 *corners);
|
||||
|
||||
// For debug printing
|
||||
virtual void PrintInfo(std::ostream &out);
|
||||
|
||||
private:
|
||||
// Generator parameters
|
||||
UnlimitedHeightmap *m_heightmap;
|
||||
MapParams m_params;
|
||||
PointAttributeDatabase m_padb;
|
||||
|
||||
// Seed used for all kinds of randomness
|
||||
u64 m_seed;
|
||||
|
||||
@ -664,8 +640,8 @@ private:
|
||||
core::aabbox3d<f32> m_box;
|
||||
|
||||
// This is the master heightmap mesh
|
||||
scene::SMesh *mesh;
|
||||
JMutex mesh_mutex;
|
||||
//scene::SMesh *mesh;
|
||||
//JMutex mesh_mutex;
|
||||
|
||||
MapDrawControl &m_control;
|
||||
};
|
||||
|
@ -612,7 +612,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
bool new_style_water = g_settings.getBool("new_style_water");
|
||||
float node_water_level = 1.0;
|
||||
if(new_style_water)
|
||||
node_water_level = 0.8;
|
||||
node_water_level = 0.9;
|
||||
|
||||
/*
|
||||
We are including the faces of the trailing edges of the block.
|
||||
|
@ -176,168 +176,22 @@ void MapSector::getBlocks(core::list<MapBlock*> &dest)
|
||||
ServerMapSector
|
||||
*/
|
||||
|
||||
ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split):
|
||||
MapSector(parent, pos),
|
||||
m_hm_split(hm_split),
|
||||
m_objects(NULL)
|
||||
ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos):
|
||||
MapSector(parent, pos)
|
||||
{
|
||||
// hm_split has to be 1 or 2^x
|
||||
assert(hm_split == 0 || hm_split == 1 || (hm_split & (hm_split-1)) == 0);
|
||||
assert(hm_split * hm_split <= MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT);
|
||||
|
||||
for(u16 i=0; i<hm_split*hm_split; i++)
|
||||
m_heightmaps[i] = NULL;
|
||||
}
|
||||
|
||||
ServerMapSector::~ServerMapSector()
|
||||
{
|
||||
u16 hm_count = m_hm_split * m_hm_split;
|
||||
|
||||
// Write heightmaps
|
||||
for(u16 i=0; i<hm_count; i++)
|
||||
{
|
||||
if(m_heightmaps[i])
|
||||
delete m_heightmaps[i];
|
||||
}
|
||||
|
||||
if(m_objects)
|
||||
delete m_objects;
|
||||
}
|
||||
|
||||
void ServerMapSector::setHeightmap(v2s16 hm_p, FixedHeightmap *hm)
|
||||
{
|
||||
assert(isInArea(hm_p, m_hm_split));
|
||||
|
||||
s16 i = hm_p.Y * m_hm_split + hm_p.X;
|
||||
|
||||
// Don't allow setting already set heightmaps as of now
|
||||
assert(m_heightmaps[i] == NULL);
|
||||
|
||||
/*std::cout<<"MapSector::setHeightmap for sector "
|
||||
<<"("<<m_pos.X<<","<<m_pos.Y<<"): "
|
||||
<<"Setting heightmap "
|
||||
<<"("<<hm_p.X<<","<<hm_p.Y<<")"
|
||||
<<" which is i="<<i
|
||||
<<" to pointer "<<(long long)hm
|
||||
<<std::endl;*/
|
||||
|
||||
m_heightmaps[i] = hm;
|
||||
|
||||
differs_from_disk = true;
|
||||
}
|
||||
|
||||
FixedHeightmap * ServerMapSector::getHeightmap(v2s16 hm_p)
|
||||
{
|
||||
assert(isInArea(hm_p, m_hm_split));
|
||||
|
||||
s16 i = hm_p.Y * m_hm_split + hm_p.X;
|
||||
|
||||
return m_heightmaps[i];
|
||||
}
|
||||
|
||||
f32 ServerMapSector::getGroundHeight(v2s16 p, bool generate)
|
||||
{
|
||||
// If no heightmaps
|
||||
if(m_hm_split == 0)
|
||||
{
|
||||
/*std::cout<<"Sector has no heightmap"
|
||||
<<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
|
||||
<<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
|
||||
<<std::endl;*/
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
}
|
||||
|
||||
// Side length of heightmap
|
||||
s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
|
||||
|
||||
// Position of selected heightmap
|
||||
v2s16 hm_p = getContainerPos(p, hm_d);
|
||||
if(isInArea(hm_p, m_hm_split) == false)
|
||||
{
|
||||
/*std::cout<<"Sector has no heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
|
||||
<<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
|
||||
<<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
|
||||
<<std::endl;*/
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
}
|
||||
|
||||
// Selected heightmap
|
||||
FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
|
||||
|
||||
if(hm == NULL)
|
||||
{
|
||||
/*std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
|
||||
" is NULL"
|
||||
<<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
|
||||
<<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
|
||||
<<std::endl;*/
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
}
|
||||
|
||||
// Position in selected heighmap
|
||||
v2s16 p_in_hm = p - hm_p * hm_d;
|
||||
if(isInArea(p_in_hm, hm_d+1) == false)
|
||||
{
|
||||
/*std::cout<<"Position ("<<p_in_hm.X<<","<<p_in_hm.Y<<")"
|
||||
" not in sector heightmap area"
|
||||
<<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
|
||||
<<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
|
||||
<<std::endl;*/
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
}
|
||||
|
||||
f32 h = hm->getGroundHeight(p_in_hm);
|
||||
|
||||
/*if(h < GROUNDHEIGHT_VALID_MINVALUE)
|
||||
{
|
||||
std::cout<<"Sector heightmap ("<<hm_p.X<<","<<hm_p.Y<<")"
|
||||
" returned invalid value"
|
||||
<<" while trying to get height at ("<<p.X<<","<<p.Y<<")"
|
||||
<<" which is ("<<p_in_hm.X<<","<<p_in_hm.Y<<") in heightmap"
|
||||
<<" for sector ("<<m_pos.X<<","<<m_pos.Y<<")"
|
||||
<<std::endl;
|
||||
}*/
|
||||
|
||||
return h;
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
}
|
||||
|
||||
void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
|
||||
{
|
||||
/*
|
||||
NOTE:
|
||||
This causes glitches because the sector cannot be actually
|
||||
modified according to heightmap changes.
|
||||
|
||||
This is useful when generating continued sub-heightmaps
|
||||
inside the sector.
|
||||
*/
|
||||
|
||||
// If no heightmaps
|
||||
if(m_hm_split == 0)
|
||||
return;
|
||||
|
||||
// Side length of heightmap
|
||||
s16 hm_d = MAP_BLOCKSIZE / m_hm_split;
|
||||
|
||||
// Position of selected heightmap
|
||||
v2s16 hm_p = getContainerPos(p, hm_d);
|
||||
if(isInArea(hm_p, m_hm_split) == false)
|
||||
return;
|
||||
|
||||
// Selected heightmap
|
||||
FixedHeightmap *hm = m_heightmaps[hm_p.Y * m_hm_split + hm_p.X];
|
||||
|
||||
if(hm == NULL)
|
||||
return;
|
||||
|
||||
// Position in selected heighmap
|
||||
v2s16 p_in_hm = p - hm_p * hm_d;
|
||||
if(isInArea(p_in_hm, hm_d) == false)
|
||||
return;
|
||||
|
||||
hm->setGroundHeight(p_in_hm, y);
|
||||
|
||||
differs_from_disk = true;
|
||||
}
|
||||
|
||||
void ServerMapSector::serialize(std::ostream &os, u8 version)
|
||||
@ -351,118 +205,21 @@ void ServerMapSector::serialize(std::ostream &os, u8 version)
|
||||
*/
|
||||
|
||||
// Server has both of these, no need to support not having them.
|
||||
assert(m_objects != NULL);
|
||||
//assert(m_objects != NULL);
|
||||
|
||||
// Write version
|
||||
os.write((char*)&version, 1);
|
||||
|
||||
/*
|
||||
Serialize heightmap(s)
|
||||
Add stuff here, if needed
|
||||
*/
|
||||
|
||||
// Version with single heightmap
|
||||
if(version <= 7)
|
||||
{
|
||||
u32 heightmap_size =
|
||||
FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
|
||||
|
||||
SharedBuffer<u8> data(heightmap_size);
|
||||
m_heightmaps[0]->serialize(*data, version);
|
||||
|
||||
os.write((const char*)*data, heightmap_size);
|
||||
|
||||
if(version >= 5)
|
||||
{
|
||||
/*
|
||||
Write objects
|
||||
*/
|
||||
|
||||
u16 object_count;
|
||||
if(m_objects->size() > 65535)
|
||||
object_count = 65535;
|
||||
else
|
||||
object_count = m_objects->size();
|
||||
|
||||
u8 b[2];
|
||||
writeU16(b, object_count);
|
||||
os.write((char*)b, 2);
|
||||
|
||||
core::map<v3s16, u8>::Iterator i;
|
||||
i = m_objects->getIterator();
|
||||
for(; i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
u8 d = i.getNode()->getValue();
|
||||
u8 b[7];
|
||||
writeV3S16(&b[0], p);
|
||||
b[6] = d;
|
||||
os.write((char*)b, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Version with multiple heightmaps
|
||||
else
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
if(m_hm_split > 255)
|
||||
throw SerializationError("Sector has too many heightmaps");
|
||||
|
||||
// Write heightmap split ratio
|
||||
writeU8(buf, m_hm_split);
|
||||
os.write((char*)buf, 1);
|
||||
|
||||
// If there are heightmaps, write them
|
||||
if(m_hm_split != 0)
|
||||
{
|
||||
u16 hm_d = MAP_BLOCKSIZE / m_hm_split;
|
||||
|
||||
u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
|
||||
SharedBuffer<u8> data(hm_size);
|
||||
|
||||
u16 hm_count = m_hm_split * m_hm_split;
|
||||
|
||||
// Write heightmaps
|
||||
for(u16 i=0; i<hm_count; i++)
|
||||
{
|
||||
m_heightmaps[i]->serialize(*data, version);
|
||||
os.write((const char*)*data, hm_size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Write objects
|
||||
*/
|
||||
|
||||
u16 object_count;
|
||||
if(m_objects->size() > 65535)
|
||||
object_count = 65535;
|
||||
else
|
||||
object_count = m_objects->size();
|
||||
|
||||
u8 b[2];
|
||||
writeU16(b, object_count);
|
||||
os.write((char*)b, 2);
|
||||
|
||||
core::map<v3s16, u8>::Iterator i;
|
||||
i = m_objects->getIterator();
|
||||
for(; i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
u8 d = i.getNode()->getValue();
|
||||
u8 b[7];
|
||||
writeV3S16(&b[0], p);
|
||||
b[6] = d;
|
||||
os.write((char*)b, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServerMapSector* ServerMapSector::deSerialize(
|
||||
std::istream &is,
|
||||
NodeContainer *parent,
|
||||
v2s16 p2d,
|
||||
Heightmap *master_hm,
|
||||
core::map<v2s16, MapSector*> & sectors
|
||||
)
|
||||
{
|
||||
@ -483,82 +240,8 @@ ServerMapSector* ServerMapSector::deSerialize(
|
||||
throw VersionMismatchException("ERROR: MapSector format not supported");
|
||||
|
||||
/*
|
||||
Read heightmap(s)
|
||||
Add necessary reading stuff here
|
||||
*/
|
||||
|
||||
FixedHeightmap *hms[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
|
||||
u16 hm_split = 0;
|
||||
|
||||
// Version with a single heightmap
|
||||
if(version <= 7)
|
||||
{
|
||||
hm_split = 1;
|
||||
|
||||
u32 hm_size =
|
||||
FixedHeightmap::serializedLength(version, MAP_BLOCKSIZE);
|
||||
|
||||
SharedBuffer<u8> data(hm_size);
|
||||
is.read((char*)*data, hm_size);
|
||||
|
||||
hms[0] = new FixedHeightmap(master_hm, p2d, MAP_BLOCKSIZE);
|
||||
hms[0]->deSerialize(*data, version);
|
||||
}
|
||||
// Version with multiple heightmaps
|
||||
else
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
// Read split ratio
|
||||
is.read((char*)buf, 1);
|
||||
hm_split = readU8(buf);
|
||||
|
||||
// If there are heightmaps, read them
|
||||
if(hm_split != 0)
|
||||
{
|
||||
u16 hm_count = hm_split * hm_split;
|
||||
|
||||
if(hm_count > MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT)
|
||||
throw SerializationError("Sector has too many heightmaps");
|
||||
|
||||
u16 hm_d = MAP_BLOCKSIZE / hm_split;
|
||||
|
||||
u32 hm_size = FixedHeightmap::serializedLength(version, hm_d);
|
||||
|
||||
u16 i=0;
|
||||
for(s16 y=0; y<hm_split; y++)
|
||||
for(s16 x=0; x<hm_split; x++)
|
||||
{
|
||||
SharedBuffer<u8> data(hm_size);
|
||||
is.read((char*)*data, hm_size);
|
||||
|
||||
hms[i] = new FixedHeightmap(master_hm, p2d+v2s16(x,y), hm_d);
|
||||
hms[i]->deSerialize(*data, version);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Read objects
|
||||
*/
|
||||
|
||||
core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
|
||||
|
||||
if(version >= 5)
|
||||
{
|
||||
u8 b[2];
|
||||
is.read((char*)b, 2);
|
||||
u16 object_count = readU16(b);
|
||||
|
||||
for(u16 i=0; i<object_count; i++)
|
||||
{
|
||||
u8 b[7];
|
||||
is.read((char*)b, 7);
|
||||
v3s16 p = readV3S16(&b[0]);
|
||||
u8 d = b[6];
|
||||
objects->insert(p, d);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Get or create sector
|
||||
@ -574,18 +257,13 @@ ServerMapSector* ServerMapSector::deSerialize(
|
||||
"at the moment, because code hasn't been tested."
|
||||
<<std::endl;
|
||||
|
||||
//assert(0);
|
||||
MapSector *sector = n->getValue();
|
||||
assert(sector->getId() == MAPSECTOR_SERVER);
|
||||
return (ServerMapSector*)sector;
|
||||
|
||||
// NOTE: At least hm_split mismatch would have to be checked
|
||||
|
||||
//sector = n->getValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = new ServerMapSector(parent, p2d, hm_split);
|
||||
sector = new ServerMapSector(parent, p2d);
|
||||
sectors.insert(p2d, sector);
|
||||
}
|
||||
|
||||
@ -593,26 +271,7 @@ ServerMapSector* ServerMapSector::deSerialize(
|
||||
Set stuff in sector
|
||||
*/
|
||||
|
||||
// Set heightmaps
|
||||
|
||||
sector->m_hm_split = hm_split;
|
||||
|
||||
u16 hm_count = hm_split * hm_split;
|
||||
|
||||
for(u16 i=0; i<hm_count; i++)
|
||||
{
|
||||
// Set (or change) heightmap
|
||||
FixedHeightmap *oldhm = sector->m_heightmaps[i];
|
||||
sector->m_heightmaps[i] = hms[i];
|
||||
if(oldhm != NULL)
|
||||
delete oldhm;
|
||||
}
|
||||
|
||||
// Set (or change) objects
|
||||
core::map<v3s16, u8> *oldfo = sector->m_objects;
|
||||
sector->m_objects = objects;
|
||||
if(oldfo)
|
||||
delete oldfo;
|
||||
// Nothing here
|
||||
|
||||
return sector;
|
||||
}
|
||||
@ -654,29 +313,21 @@ void ClientMapSector::deSerialize(std::istream &is)
|
||||
|
||||
if(!ser_ver_supported(version))
|
||||
throw VersionMismatchException("ERROR: MapSector format not supported");
|
||||
if(version <= 7)
|
||||
throw VersionMismatchException("ERROR: MapSector format not supported");
|
||||
|
||||
u8 buf[2];
|
||||
|
||||
// Read corners
|
||||
// Dummy read corners
|
||||
is.read((char*)buf, 2);
|
||||
s16 c0 = readU16(buf);
|
||||
is.read((char*)buf, 2);
|
||||
s16 c1 = readU16(buf);
|
||||
is.read((char*)buf, 2);
|
||||
s16 c2 = readU16(buf);
|
||||
is.read((char*)buf, 2);
|
||||
s16 c3 = readU16(buf);
|
||||
|
||||
/*
|
||||
Set stuff in sector
|
||||
*/
|
||||
|
||||
m_corners[0] = c0;
|
||||
m_corners[1] = c1;
|
||||
m_corners[2] = c2;
|
||||
m_corners[3] = c3;
|
||||
// Nothing here
|
||||
|
||||
}
|
||||
#endif // !SERVER
|
||||
|
||||
|
@ -27,26 +27,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <jmutex.h>
|
||||
#include "common_irrlicht.h"
|
||||
#include "mapblock.h"
|
||||
#include "heightmap.h"
|
||||
//#include "heightmap.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
/*
|
||||
This is an Y-wise stack of MapBlocks.
|
||||
*/
|
||||
|
||||
#define SECTOR_OBJECT_TEST 0
|
||||
#define SECTOR_OBJECT_TREE_1 1
|
||||
#define SECTOR_OBJECT_BUSH_1 2
|
||||
#define SECTOR_OBJECT_RAVINE 3
|
||||
|
||||
//#define MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT 4
|
||||
#define MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT \
|
||||
(SECTOR_HEIGHTMAP_SPLIT * SECTOR_HEIGHTMAP_SPLIT)
|
||||
|
||||
#define MAPSECTOR_SERVER 0
|
||||
#define MAPSECTOR_CLIENT 1
|
||||
|
||||
class MapSector: public NodeContainer, public Heightmappish
|
||||
class MapSector: public NodeContainer
|
||||
{
|
||||
public:
|
||||
|
||||
@ -198,6 +189,7 @@ public:
|
||||
blockref->setNode(relpos, n);
|
||||
}
|
||||
|
||||
// DEPRECATED?
|
||||
virtual f32 getGroundHeight(v2s16 p, bool generate=false)
|
||||
{
|
||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||
@ -245,44 +237,15 @@ protected:
|
||||
class ServerMapSector : public MapSector
|
||||
{
|
||||
public:
|
||||
ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split);
|
||||
ServerMapSector(NodeContainer *parent, v2s16 pos);
|
||||
~ServerMapSector();
|
||||
|
||||
u32 getId() const
|
||||
{
|
||||
return MAPSECTOR_SERVER;
|
||||
}
|
||||
|
||||
void setHeightmap(v2s16 hm_p, FixedHeightmap *hm);
|
||||
FixedHeightmap * getHeightmap(v2s16 hm_p);
|
||||
|
||||
void printHeightmaps()
|
||||
{
|
||||
for(s16 y=0; y<m_hm_split; y++)
|
||||
for(s16 x=0; x<m_hm_split; x++)
|
||||
{
|
||||
std::cout<<"Sector "
|
||||
<<"("<<m_pos.X<<","<<m_pos.Y<<")"
|
||||
" heightmap "
|
||||
"("<<x<<","<<y<<"):"
|
||||
<<std::endl;
|
||||
FixedHeightmap *hm = getHeightmap(v2s16(x,y));
|
||||
hm->print();
|
||||
}
|
||||
}
|
||||
|
||||
void setObjects(core::map<v3s16, u8> *objects)
|
||||
{
|
||||
m_objects = objects;
|
||||
differs_from_disk = true;
|
||||
}
|
||||
|
||||
core::map<v3s16, u8> * getObjects()
|
||||
{
|
||||
differs_from_disk = true;
|
||||
return m_objects;
|
||||
}
|
||||
|
||||
// DEPRECATED?
|
||||
f32 getGroundHeight(v2s16 p, bool generate=false);
|
||||
void setGroundHeight(v2s16 p, f32 y, bool generate=false);
|
||||
|
||||
@ -296,20 +259,10 @@ public:
|
||||
std::istream &is,
|
||||
NodeContainer *parent,
|
||||
v2s16 p2d,
|
||||
Heightmap *master_hm,
|
||||
core::map<v2s16, MapSector*> & sectors
|
||||
);
|
||||
|
||||
private:
|
||||
// Heightmap(s) for the sector
|
||||
FixedHeightmap *m_heightmaps[MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT];
|
||||
// Sector is split in m_hm_split^2 heightmaps.
|
||||
// Value of 0 means there is no heightmap.
|
||||
u16 m_hm_split;
|
||||
// These are removed when they are drawn to blocks.
|
||||
// - Each is drawn when generating blocks; When the last one of
|
||||
// the needed blocks is being generated.
|
||||
core::map<v3s16, u8> *m_objects;
|
||||
};
|
||||
|
||||
#ifndef SERVER
|
||||
@ -326,14 +279,14 @@ public:
|
||||
|
||||
void deSerialize(std::istream &is);
|
||||
|
||||
s16 getCorner(u16 i)
|
||||
/*s16 getCorner(u16 i)
|
||||
{
|
||||
return m_corners[i];
|
||||
}
|
||||
}*/
|
||||
|
||||
private:
|
||||
// The ground height of the corners is stored in here
|
||||
s16 m_corners[4];
|
||||
//s16 m_corners[4];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1022,11 +1022,9 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
||||
*/
|
||||
|
||||
Server::Server(
|
||||
std::string mapsavedir,
|
||||
HMParams hm_params,
|
||||
MapParams map_params
|
||||
std::string mapsavedir
|
||||
):
|
||||
m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server),
|
||||
m_env(new ServerMap(mapsavedir), dout_server),
|
||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||
m_thread(this),
|
||||
m_emergethread(this),
|
||||
@ -1406,8 +1404,10 @@ void Server::AsyncRunStep()
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger emergethread (it gets somehow gets to a
|
||||
// non-triggered but bysy state sometimes)
|
||||
/*
|
||||
Trigger emergethread (it somehow gets to a non-triggered but
|
||||
bysy state sometimes)
|
||||
*/
|
||||
{
|
||||
float &counter = m_emergethread_trigger_timer;
|
||||
counter += dtime;
|
||||
|
@ -377,9 +377,7 @@ public:
|
||||
NOTE: Every public method should be thread-safe
|
||||
*/
|
||||
Server(
|
||||
std::string mapsavedir,
|
||||
HMParams hm_params,
|
||||
MapParams map_params
|
||||
std::string mapsavedir
|
||||
);
|
||||
~Server();
|
||||
void start(unsigned short port);
|
||||
|
@ -263,18 +263,6 @@ int main(int argc, char *argv[])
|
||||
init_mapnode(&irrlicht);
|
||||
init_mineral(&irrlicht);
|
||||
|
||||
// Read map parameters from settings
|
||||
|
||||
HMParams hm_params;
|
||||
/*hm_params.blocksize = g_settings.getU16("heightmap_blocksize");
|
||||
hm_params.randmax = g_settings.get("height_randmax");
|
||||
hm_params.randfactor = g_settings.get("height_randfactor");
|
||||
hm_params.base = g_settings.get("height_base");*/
|
||||
|
||||
MapParams map_params;
|
||||
map_params.plants_amount = g_settings.getFloat("plants_amount");
|
||||
map_params.ravines_amount = g_settings.getFloat("ravines_amount");
|
||||
|
||||
/*
|
||||
Check parameters
|
||||
*/
|
||||
@ -316,7 +304,7 @@ int main(int argc, char *argv[])
|
||||
map_dir = g_settings.get("map-dir");
|
||||
|
||||
// Create server
|
||||
Server server(map_dir.c_str(), hm_params, map_params);
|
||||
Server server(map_dir.c_str());
|
||||
server.start(port);
|
||||
|
||||
// Run server
|
||||
|
134
src/test.cpp
134
src/test.cpp
@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "map.h"
|
||||
#include "player.h"
|
||||
#include "main.h"
|
||||
#include "heightmap.h"
|
||||
#include "socket.h"
|
||||
#include "connection.h"
|
||||
#include "utility.h"
|
||||
@ -628,9 +627,7 @@ struct TestMapSector
|
||||
parent.position_valid = false;
|
||||
|
||||
// Create one with no heightmaps
|
||||
ServerMapSector sector(&parent, v2s16(1,1), 0);
|
||||
//ConstantGenerator *dummyheightmap = new ConstantGenerator();
|
||||
//sector->setHeightmap(dummyheightmap);
|
||||
ServerMapSector sector(&parent, v2s16(1,1));
|
||||
|
||||
EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(0));
|
||||
EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(1));
|
||||
@ -654,134 +651,6 @@ struct TestMapSector
|
||||
}
|
||||
};
|
||||
|
||||
struct TestHeightmap
|
||||
{
|
||||
void TestSingleFixed()
|
||||
{
|
||||
const s16 BS1 = 4;
|
||||
OneChildHeightmap hm1(BS1);
|
||||
|
||||
// Test that it is filled with < GROUNDHEIGHT_VALID_MINVALUE
|
||||
for(s16 y=0; y<=BS1; y++){
|
||||
for(s16 x=0; x<=BS1; x++){
|
||||
v2s16 p(x,y);
|
||||
assert(hm1.m_child.getGroundHeight(p)
|
||||
< GROUNDHEIGHT_VALID_MINVALUE);
|
||||
}
|
||||
}
|
||||
|
||||
hm1.m_child.setGroundHeight(v2s16(1,0), 2.0);
|
||||
//hm1.m_child.print();
|
||||
assert(fabs(hm1.getGroundHeight(v2s16(1,0))-2.0)<0.001);
|
||||
hm1.setGroundHeight(v2s16(0,1), 3.0);
|
||||
assert(fabs(hm1.m_child.getGroundHeight(v2s16(0,1))-3.0)<0.001);
|
||||
|
||||
// Fill with -1.0
|
||||
for(s16 y=0; y<=BS1; y++){
|
||||
for(s16 x=0; x<=BS1; x++){
|
||||
v2s16 p(x,y);
|
||||
hm1.m_child.setGroundHeight(p, -1.0);
|
||||
}
|
||||
}
|
||||
|
||||
f32 corners[] = {0.0, 0.0, 1.0, 1.0};
|
||||
hm1.m_child.generateContinued(0.0, 0.0, corners);
|
||||
|
||||
hm1.m_child.print();
|
||||
assert(fabs(hm1.m_child.getGroundHeight(v2s16(1,0))-0.2)<0.05);
|
||||
assert(fabs(hm1.m_child.getGroundHeight(v2s16(4,3))-0.7)<0.05);
|
||||
assert(fabs(hm1.m_child.getGroundHeight(v2s16(4,4))-1.0)<0.05);
|
||||
}
|
||||
|
||||
void TestUnlimited()
|
||||
{
|
||||
//g_heightmap_debugprint = true;
|
||||
const s16 BS1 = 4;
|
||||
/*UnlimitedHeightmap hm1(BS1,
|
||||
new ConstantGenerator(0.0),
|
||||
new ConstantGenerator(0.0),
|
||||
new ConstantGenerator(5.0));*/
|
||||
PointAttributeDatabase padb;
|
||||
UnlimitedHeightmap hm1(BS1, &padb);
|
||||
// Go through it so it generates itself
|
||||
for(s16 y=0; y<=BS1; y++){
|
||||
for(s16 x=0; x<=BS1; x++){
|
||||
v2s16 p(x,y);
|
||||
hm1.getGroundHeight(p);
|
||||
}
|
||||
}
|
||||
// Print it
|
||||
dstream<<"UnlimitedHeightmap hm1:"<<std::endl;
|
||||
hm1.print();
|
||||
|
||||
dstream<<"testing UnlimitedHeightmap set/get"<<std::endl;
|
||||
v2s16 p1(0,3);
|
||||
f32 v1(234.01);
|
||||
// Get first heightmap and try setGroundHeight
|
||||
FixedHeightmap * href = hm1.getHeightmap(v2s16(0,0));
|
||||
href->setGroundHeight(p1, v1);
|
||||
// Read from UnlimitedHeightmap
|
||||
assert(fabs(hm1.getGroundHeight(p1)-v1)<0.001);
|
||||
}
|
||||
|
||||
void Random()
|
||||
{
|
||||
dstream<<"Running random code (get a human to check this)"<<std::endl;
|
||||
dstream<<"myrand() values: ";
|
||||
for(u16 i=0; i<5; i++)
|
||||
dstream<<(u16)myrand()<<" ";
|
||||
dstream<<std::endl;
|
||||
|
||||
const s16 BS1 = 8;
|
||||
/*UnlimitedHeightmap hm1(BS1,
|
||||
new ConstantGenerator(10.0),
|
||||
new ConstantGenerator(0.3),
|
||||
new ConstantGenerator(0.0));*/
|
||||
|
||||
PointAttributeDatabase padb;
|
||||
|
||||
padb.getList("hm_baseheight")->addPoint(v2s16(-BS1,0), Attribute(0));
|
||||
padb.getList("hm_randmax")->addPoint(v2s16(-BS1,0), Attribute(0));
|
||||
padb.getList("hm_randfactor")->addPoint(v2s16(-BS1,0), Attribute(0.0));
|
||||
|
||||
padb.getList("hm_baseheight")->addPoint(v2s16(0,0), Attribute(-20));
|
||||
padb.getList("hm_randmax")->addPoint(v2s16(0,0), Attribute(0));
|
||||
padb.getList("hm_randfactor")->addPoint(v2s16(0,0), Attribute(0.5));
|
||||
|
||||
padb.getList("hm_baseheight")->addPoint(v2s16(BS1*2,BS1), Attribute(0));
|
||||
padb.getList("hm_randmax")->addPoint(v2s16(BS1*2,BS1), Attribute(30));
|
||||
padb.getList("hm_randfactor")->addPoint(v2s16(BS1*2,BS1), Attribute(0.63));
|
||||
|
||||
UnlimitedHeightmap hm1(BS1, &padb);
|
||||
|
||||
// Force hm1 to generate a some heightmap
|
||||
hm1.getGroundHeight(v2s16(0,0));
|
||||
hm1.getGroundHeight(v2s16(0,BS1));
|
||||
/*hm1.getGroundHeight(v2s16(BS1,-1));
|
||||
hm1.getGroundHeight(v2s16(BS1-1,-1));*/
|
||||
hm1.print();
|
||||
|
||||
// Get the (0,0) and (1,0) heightmaps
|
||||
/*FixedHeightmap * hr00 = hm1.getHeightmap(v2s16(0,0));
|
||||
FixedHeightmap * hr01 = hm1.getHeightmap(v2s16(1,0));
|
||||
f32 corners[] = {1.0, 1.0, 1.0, 1.0};
|
||||
hr00->generateContinued(0.0, 0.0, corners);
|
||||
hm1.print();*/
|
||||
|
||||
//assert(0);
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
//srand(7); // Get constant random
|
||||
srand(time(0)); // Get better random
|
||||
|
||||
TestSingleFixed();
|
||||
TestUnlimited();
|
||||
Random();
|
||||
}
|
||||
};
|
||||
|
||||
struct TestSocket
|
||||
{
|
||||
void Run()
|
||||
@ -1149,7 +1018,6 @@ void run_tests()
|
||||
TEST(TestVoxelManipulator);
|
||||
TEST(TestMapBlock);
|
||||
TEST(TestMapSector);
|
||||
TEST(TestHeightmap);
|
||||
if(INTERNET_SIMULATOR == false){
|
||||
TEST(TestSocket);
|
||||
dout_con<<"=== BEGIN RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;
|
||||
|
230
src/utility.cpp
230
src/utility.cpp
@ -144,236 +144,6 @@ void mysrand(unsigned seed)
|
||||
next = seed;
|
||||
}
|
||||
|
||||
/*
|
||||
PointAttributeList
|
||||
*/
|
||||
|
||||
// Float with distance
|
||||
struct DFloat
|
||||
{
|
||||
float v;
|
||||
u32 d;
|
||||
};
|
||||
|
||||
float PointAttributeList::getInterpolatedFloat(v2s16 p)
|
||||
{
|
||||
const u32 near_wanted_count = 5;
|
||||
// Last is nearest, first is farthest
|
||||
core::list<DFloat> near_list;
|
||||
|
||||
for(core::list<PointWithAttr>::Iterator
|
||||
i = m_points.begin();
|
||||
i != m_points.end(); i++)
|
||||
{
|
||||
PointWithAttr &pwa = *i;
|
||||
u32 d = pwa.p.getDistanceFrom(p);
|
||||
|
||||
DFloat df;
|
||||
df.v = pwa.attr.getFloat();
|
||||
df.d = d;
|
||||
|
||||
// If near list is empty, add directly and continue
|
||||
if(near_list.size() == 0)
|
||||
{
|
||||
near_list.push_back(df);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get distance of farthest in near list
|
||||
u32 near_d = 100000;
|
||||
if(near_list.size() > 0)
|
||||
{
|
||||
core::list<DFloat>::Iterator i = near_list.begin();
|
||||
near_d = i->d;
|
||||
}
|
||||
|
||||
/*
|
||||
If point is closer than the farthest in the near list or
|
||||
there are not yet enough points on the list
|
||||
*/
|
||||
if(d < near_d || near_list.size() < near_wanted_count)
|
||||
{
|
||||
// Find the right place in the near list and put it there
|
||||
|
||||
// Go from farthest to near in the near list
|
||||
core::list<DFloat>::Iterator i = near_list.begin();
|
||||
for(; i != near_list.end(); i++)
|
||||
{
|
||||
// Stop when i is at the first nearer node
|
||||
if(i->d < d)
|
||||
break;
|
||||
}
|
||||
// Add df to before i
|
||||
if(i == near_list.end())
|
||||
near_list.push_back(df);
|
||||
else
|
||||
near_list.insert_before(i, df);
|
||||
|
||||
// Keep near list at right size
|
||||
if(near_list.size() > near_wanted_count)
|
||||
{
|
||||
core::list<DFloat>::Iterator j = near_list.begin();
|
||||
near_list.erase(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return if no values found
|
||||
if(near_list.size() == 0)
|
||||
return 0.0;
|
||||
|
||||
/*
|
||||
20:58:29 < tejeez> joka pisteelle a += arvo / etäisyys^6; b += 1 / etäisyys^6; ja
|
||||
lopuks sit otetaan a/b
|
||||
*/
|
||||
|
||||
float a = 0;
|
||||
float b = 0;
|
||||
for(core::list<DFloat>::Iterator i = near_list.begin();
|
||||
i != near_list.end(); i++)
|
||||
{
|
||||
if(i->d == 0)
|
||||
return i->v;
|
||||
|
||||
//float dd = pow((float)i->d, 6);
|
||||
float dd = pow((float)i->d, 5);
|
||||
float v = i->v;
|
||||
//dstream<<"dd="<<dd<<", v="<<v<<std::endl;
|
||||
a += v / dd;
|
||||
b += 1 / dd;
|
||||
}
|
||||
|
||||
return a / b;
|
||||
}
|
||||
|
||||
#if 0
|
||||
float PointAttributeList::getInterpolatedFloat(v3s16 p)
|
||||
{
|
||||
const u32 near_wanted_count = 2;
|
||||
const u32 nearest_wanted_count = 2;
|
||||
// Last is near
|
||||
core::list<DFloat> near;
|
||||
|
||||
for(core::list<PointWithAttr>::Iterator
|
||||
i = m_points.begin();
|
||||
i != m_points.end(); i++)
|
||||
{
|
||||
PointWithAttr &pwa = *i;
|
||||
u32 d = pwa.p.getDistanceFrom(p);
|
||||
|
||||
DFloat df;
|
||||
df.v = pwa.attr.getFloat();
|
||||
df.d = d;
|
||||
|
||||
// If near list is empty, add directly and continue
|
||||
if(near_list.size() == 0)
|
||||
{
|
||||
near_list.push_back(df);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get distance of farthest in near list
|
||||
u32 near_d = 100000;
|
||||
if(near_list.size() > 0)
|
||||
{
|
||||
core::list<DFloat>::Iterator i = near_list.begin();
|
||||
near_d = i->d;
|
||||
}
|
||||
|
||||
/*
|
||||
If point is closer than the farthest in the near list or
|
||||
there are not yet enough points on the list
|
||||
*/
|
||||
if(d < near_d || near_list.size() < near_wanted_count)
|
||||
{
|
||||
// Find the right place in the near list and put it there
|
||||
|
||||
// Go from farthest to near in the near list
|
||||
core::list<DFloat>::Iterator i = near_list.begin();
|
||||
for(; i != near_list.end(); i++)
|
||||
{
|
||||
// Stop when i is at the first nearer node
|
||||
if(i->d < d)
|
||||
break;
|
||||
}
|
||||
// Add df to before i
|
||||
if(i == near_list.end())
|
||||
near_list.push_back(df);
|
||||
else
|
||||
near_list.insert_before(i, df);
|
||||
|
||||
// Keep near list at right size
|
||||
if(near_list.size() > near_wanted_count)
|
||||
{
|
||||
core::list<DFloat>::Iterator j = near_list.begin();
|
||||
near_list.erase(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return if no values found
|
||||
if(near_list.size() == 0)
|
||||
return 0.0;
|
||||
|
||||
/*
|
||||
Get nearest ones
|
||||
*/
|
||||
|
||||
u32 nearest_count = nearest_wanted_count;
|
||||
if(nearest_count > near_list.size())
|
||||
nearest_count = near_list.size();
|
||||
core::list<DFloat> nearest;
|
||||
{
|
||||
core::list<DFloat>::Iterator i = near_list.getLast();
|
||||
for(u32 j=0; j<nearest_count; j++)
|
||||
{
|
||||
nearest.push_front(*i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Try this:
|
||||
20:58:29 < tejeez> joka pisteelle a += arvo / etäisyys^6; b += 1 / etäisyys^6; ja
|
||||
lopuks sit otetaan a/b
|
||||
*/
|
||||
|
||||
/*
|
||||
Get total distance to nearest points
|
||||
*/
|
||||
|
||||
float nearest_d_sum = 0;
|
||||
for(core::list<DFloat>::Iterator i = nearest.begin();
|
||||
i != nearest.end(); i++)
|
||||
{
|
||||
nearest_d_sum += (float)i->d;
|
||||
}
|
||||
|
||||
/*
|
||||
Interpolate a value between the first ones
|
||||
*/
|
||||
|
||||
dstream<<"nearest.size()="<<nearest.size()<<std::endl;
|
||||
|
||||
float interpolated = 0;
|
||||
|
||||
for(core::list<DFloat>::Iterator i = nearest.begin();
|
||||
i != nearest.end(); i++)
|
||||
{
|
||||
float weight;
|
||||
if(nearest_d_sum > 0.001)
|
||||
weight = (float)i->d / nearest_d_sum;
|
||||
else
|
||||
weight = 1. / nearest.size();
|
||||
/*dstream<<"i->d="<<i->d<<" nearest_d_sum="<<nearest_d_sum
|
||||
<<" weight="<<weight<<std::endl;*/
|
||||
interpolated += weight * i->v;
|
||||
}
|
||||
|
||||
return interpolated;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
blockpos: position of block in block coordinates
|
||||
camera_pos: position of camera in nodes
|
||||
|
177
src/utility.h
177
src/utility.h
@ -1482,183 +1482,6 @@ inline int myrand_range(int min, int max)
|
||||
return (myrand()%(max-min+1))+min;
|
||||
}
|
||||
|
||||
/*
|
||||
Some kind of a thing that stores attributes related to
|
||||
coordinate points
|
||||
*/
|
||||
|
||||
struct Attribute
|
||||
{
|
||||
Attribute()
|
||||
{
|
||||
}
|
||||
|
||||
Attribute(const std::string &value):
|
||||
m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
Attribute(float value)
|
||||
{
|
||||
m_value = ftos(value);
|
||||
}
|
||||
|
||||
void set(const std::string &value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
std::string get()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool getBool()
|
||||
{
|
||||
return is_yes(get());
|
||||
}
|
||||
|
||||
float getFloat()
|
||||
{
|
||||
float f;
|
||||
std::istringstream vis(get());
|
||||
vis>>f;
|
||||
return f;
|
||||
}
|
||||
|
||||
u16 getU16()
|
||||
{
|
||||
return stoi(get(), 0, 65535);
|
||||
}
|
||||
|
||||
s16 getS16()
|
||||
{
|
||||
return stoi(get(), -32768, 32767);
|
||||
}
|
||||
|
||||
s32 getS32()
|
||||
{
|
||||
return stoi(get());
|
||||
}
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
class PointAttributeList
|
||||
{
|
||||
struct PointWithAttr
|
||||
{
|
||||
v2s16 p;
|
||||
Attribute attr;
|
||||
};
|
||||
|
||||
public:
|
||||
~PointAttributeList()
|
||||
{
|
||||
}
|
||||
|
||||
Attribute getNearAttr(v2s16 p)
|
||||
{
|
||||
core::list<PointWithAttr>::Iterator
|
||||
nearest_i = m_points.end();
|
||||
s16 nearest_d = 32767;
|
||||
for(core::list<PointWithAttr>::Iterator
|
||||
i = m_points.begin();
|
||||
i != m_points.end(); i++)
|
||||
{
|
||||
PointWithAttr &pwa = *i;
|
||||
s16 d = pwa.p.getDistanceFrom(p);
|
||||
if(d < nearest_d)
|
||||
{
|
||||
nearest_i = i;
|
||||
nearest_d = d;
|
||||
}
|
||||
}
|
||||
|
||||
if(nearest_i == m_points.end())
|
||||
Attribute();
|
||||
|
||||
return nearest_i->attr;
|
||||
}
|
||||
|
||||
Attribute getNearAttr(v3s16 p)
|
||||
{
|
||||
return getNearAttr(v2s16(p.X, p.Z));
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return (m_points.size() == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Take all points in range, or at least the nearest point,
|
||||
and interpolate the values as floats
|
||||
*/
|
||||
float getInterpolatedFloat(v2s16 p);
|
||||
|
||||
float getInterpolatedFloat(v3s16 p)
|
||||
{
|
||||
return getInterpolatedFloat(v2s16(p.X, p.Z));
|
||||
}
|
||||
|
||||
void addPoint(v2s16 p, const Attribute &attr)
|
||||
{
|
||||
PointWithAttr pattr;
|
||||
pattr.p = p;
|
||||
pattr.attr = attr;
|
||||
m_points.push_back(pattr);
|
||||
}
|
||||
|
||||
void addPoint(v3s16 p, const Attribute &attr)
|
||||
{
|
||||
addPoint(v2s16(p.X, p.Z), attr);
|
||||
}
|
||||
|
||||
private:
|
||||
core::list<PointWithAttr> m_points;
|
||||
};
|
||||
|
||||
/*
|
||||
Basically just a wrapper to core::map<PointAttributeList*>
|
||||
*/
|
||||
|
||||
class PointAttributeDatabase
|
||||
{
|
||||
public:
|
||||
~PointAttributeDatabase()
|
||||
{
|
||||
for(core::map<std::string, PointAttributeList*>::Iterator
|
||||
i = m_lists.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
delete i.getNode()->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
PointAttributeList *getList(const std::string &name)
|
||||
{
|
||||
PointAttributeList *list = NULL;
|
||||
|
||||
core::map<std::string, PointAttributeList*>::Node *n;
|
||||
n = m_lists.find(name);
|
||||
|
||||
if(n == NULL)
|
||||
{
|
||||
list = new PointAttributeList();
|
||||
m_lists.insert(name, list);
|
||||
}
|
||||
else
|
||||
{
|
||||
list = n->getValue();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
private:
|
||||
core::map<std::string, PointAttributeList*> m_lists;
|
||||
};
|
||||
|
||||
/*
|
||||
Miscellaneous functions
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user