mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01:00
mapgen stuff
This commit is contained in:
parent
7f2aa30bf2
commit
ea6740e900
@ -58,7 +58,6 @@ set(common_SRCS
|
|||||||
socket.cpp
|
socket.cpp
|
||||||
mapblock.cpp
|
mapblock.cpp
|
||||||
mapsector.cpp
|
mapsector.cpp
|
||||||
heightmap.cpp
|
|
||||||
map.cpp
|
map.cpp
|
||||||
player.cpp
|
player.cpp
|
||||||
utility.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
|
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
|
// Length of cracking animation in count of images
|
||||||
#define CRACK_ANIMATION_LENGTH 5
|
#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
|
#endif
|
||||||
|
|
||||||
|
@ -115,6 +115,7 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
|
|||||||
L"- Mouse left: dig blocks\n"
|
L"- Mouse left: dig blocks\n"
|
||||||
L"- Mouse right: place blocks\n"
|
L"- Mouse right: place blocks\n"
|
||||||
L"- Mouse wheel: select item\n"
|
L"- Mouse wheel: select item\n"
|
||||||
|
L"- 0...9: select item\n"
|
||||||
L"- R: Toggle viewing all loaded chunks\n"
|
L"- R: Toggle viewing all loaded chunks\n"
|
||||||
L"- I: Inventory menu\n"
|
L"- I: Inventory menu\n"
|
||||||
L"- ESC: This 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
|
# maybe done
|
||||||
* not done
|
* not done
|
||||||
|
|
||||||
* Perlin noise stuff sucks in heightmap generation, fix it
|
=== Stuff to do before release
|
||||||
* Create perlin noise functions and use them to get natural randomness
|
* Save map seed to a metafile (with version information)
|
||||||
in everything. No need for attributes or fractal terrain.
|
- map/meta.txt, which should contain only plain text, something like this:
|
||||||
* Do something about AttributeDatabase/List being too slow
|
seed = O7+BZT9Vk/iVYiBlZ2dsb6zemp4xdGVysJqYmNt2X+MQ+Kg1
|
||||||
- Remove it
|
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
|
* 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
|
* Make server find the spawning place from the real map data, not from
|
||||||
the heightmap
|
the heightmap
|
||||||
- But the changing borders of chunk have to be avoided, because
|
- But the changing borders of chunk have to be avoided, because
|
||||||
there is time to generate only one chunk.
|
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
|
* Make the generator to run in background and not blocking block
|
||||||
placement and transfer
|
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
|
* Add some kind of erosion and other stuff that now is possible
|
||||||
* Make client to fetch stuff asynchronously
|
* Make client to fetch stuff asynchronously
|
||||||
- Needs method SyncProcessData
|
- 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.
|
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
|
* Water doesn't start flowing after map generation like it should
|
||||||
- Are there still problems?
|
- 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
|
* 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
|
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
|
the other chunk making nasty straight walls when the other chunk
|
||||||
is generated. Fix it.
|
is generated. Fix it.
|
||||||
* Save map seed to a metafile (with version information)
|
* Make a small history check to transformLiquids to detect and log
|
||||||
- Remove master heightmap
|
continuous oscillations, in such detail that they can be fixed.
|
||||||
|
|
||||||
======================================================================
|
======================================================================
|
||||||
|
|
||||||
@ -666,7 +668,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Material selection
|
// 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)
|
if(g_selected_item < PLAYER_INVENTORY_SIZE-1)
|
||||||
g_selected_item++;
|
g_selected_item++;
|
||||||
@ -674,6 +676,18 @@ public:
|
|||||||
g_selected_item = 0;
|
g_selected_item = 0;
|
||||||
dstream<<DTIME<<"Selected item: "
|
dstream<<DTIME<<"Selected item: "
|
||||||
<<g_selected_item<<std::endl;
|
<<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
|
// Viewing range selection
|
||||||
@ -1009,7 +1023,7 @@ public:
|
|||||||
if(counter1 < 0.0)
|
if(counter1 < 0.0)
|
||||||
{
|
{
|
||||||
counter1 = 0.1*Rand(1, 40);
|
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();
|
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
|
Some parameters
|
||||||
*/
|
*/
|
||||||
@ -1631,7 +1633,7 @@ int main(int argc, char *argv[])
|
|||||||
DSTACK("Dedicated server branch");
|
DSTACK("Dedicated server branch");
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
Server server(map_dir.c_str(), hm_params, map_params);
|
Server server(map_dir.c_str());
|
||||||
server.start(port);
|
server.start(port);
|
||||||
|
|
||||||
// Run server
|
// Run server
|
||||||
@ -1946,7 +1948,7 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
SharedPtr<Server> server;
|
SharedPtr<Server> server;
|
||||||
if(address == ""){
|
if(address == ""){
|
||||||
server = new Server(map_dir, hm_params, map_params);
|
server = new Server(map_dir);
|
||||||
server->start(port);
|
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_A),
|
||||||
g_input->isKeyDown(irr::KEY_KEY_D),
|
g_input->isKeyDown(irr::KEY_KEY_D),
|
||||||
g_input->isKeyDown(irr::KEY_SPACE),
|
g_input->isKeyDown(irr::KEY_SPACE),
|
||||||
g_input->isKeyDown(irr::KEY_KEY_2),
|
g_input->isKeyDown(irr::KEY_KEY_E),
|
||||||
camera_pitch,
|
camera_pitch,
|
||||||
camera_yaw
|
camera_yaw
|
||||||
);
|
);
|
||||||
|
770
src/map.cpp
770
src/map.cpp
File diff suppressed because it is too large
Load Diff
58
src/map.h
58
src/map.h
@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "common_irrlicht.h"
|
#include "common_irrlicht.h"
|
||||||
#include "heightmap.h"
|
//#include "heightmap.h"
|
||||||
#include "mapnode.h"
|
#include "mapnode.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#include "mapsector.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_SERVER 1
|
||||||
#define MAPTYPE_CLIENT 2
|
#define MAPTYPE_CLIENT 2
|
||||||
|
|
||||||
class Map : public NodeContainer, public Heightmappish
|
class Map : public NodeContainer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -273,42 +273,12 @@ protected:
|
|||||||
MapSector *m_sector_cache;
|
MapSector *m_sector_cache;
|
||||||
v2s16 m_sector_cache_p;
|
v2s16 m_sector_cache_p;
|
||||||
|
|
||||||
WrapperHeightmap m_hwrapper;
|
//WrapperHeightmap m_hwrapper;
|
||||||
|
|
||||||
// Queued transforming water nodes
|
// Queued transforming water nodes
|
||||||
UniqueQueue<v3s16> m_transforming_liquid;
|
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
|
ServerMap
|
||||||
|
|
||||||
@ -321,7 +291,7 @@ public:
|
|||||||
/*
|
/*
|
||||||
savedir: directory to which map data should be saved
|
savedir: directory to which map data should be saved
|
||||||
*/
|
*/
|
||||||
ServerMap(std::string savedir, HMParams hmp, MapParams mp);
|
ServerMap(std::string savedir);
|
||||||
~ServerMap();
|
~ServerMap();
|
||||||
|
|
||||||
s32 mapType() const
|
s32 mapType() const
|
||||||
@ -505,6 +475,15 @@ public:
|
|||||||
void save(bool only_changed);
|
void save(bool only_changed);
|
||||||
void loadAll();
|
void loadAll();
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
void saveMapMeta();
|
||||||
|
void loadMapMeta();
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
void saveChunkMeta();
|
||||||
|
void loadChunkMeta();
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
void saveMasterHeightmap();
|
void saveMasterHeightmap();
|
||||||
void loadMasterHeightmap();
|
void loadMasterHeightmap();
|
||||||
|
|
||||||
@ -512,6 +491,7 @@ public:
|
|||||||
|
|
||||||
// This only saves sector-specific data such as the heightmap
|
// This only saves sector-specific data such as the heightmap
|
||||||
// (no MapBlocks)
|
// (no MapBlocks)
|
||||||
|
// DEPRECATED? Sectors have no metadata anymore.
|
||||||
void saveSectorMeta(ServerMapSector *sector);
|
void saveSectorMeta(ServerMapSector *sector);
|
||||||
MapSector* loadSectorMeta(std::string dirname);
|
MapSector* loadSectorMeta(std::string dirname);
|
||||||
|
|
||||||
@ -527,17 +507,13 @@ public:
|
|||||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
||||||
|
|
||||||
// Gets from master heightmap
|
// Gets from master heightmap
|
||||||
|
// DEPRECATED?
|
||||||
void getSectorCorners(v2s16 p2d, s16 *corners);
|
void getSectorCorners(v2s16 p2d, s16 *corners);
|
||||||
|
|
||||||
// For debug printing
|
// For debug printing
|
||||||
virtual void PrintInfo(std::ostream &out);
|
virtual void PrintInfo(std::ostream &out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Generator parameters
|
|
||||||
UnlimitedHeightmap *m_heightmap;
|
|
||||||
MapParams m_params;
|
|
||||||
PointAttributeDatabase m_padb;
|
|
||||||
|
|
||||||
// Seed used for all kinds of randomness
|
// Seed used for all kinds of randomness
|
||||||
u64 m_seed;
|
u64 m_seed;
|
||||||
|
|
||||||
@ -664,8 +640,8 @@ private:
|
|||||||
core::aabbox3d<f32> m_box;
|
core::aabbox3d<f32> m_box;
|
||||||
|
|
||||||
// This is the master heightmap mesh
|
// This is the master heightmap mesh
|
||||||
scene::SMesh *mesh;
|
//scene::SMesh *mesh;
|
||||||
JMutex mesh_mutex;
|
//JMutex mesh_mutex;
|
||||||
|
|
||||||
MapDrawControl &m_control;
|
MapDrawControl &m_control;
|
||||||
};
|
};
|
||||||
|
@ -612,7 +612,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
|||||||
bool new_style_water = g_settings.getBool("new_style_water");
|
bool new_style_water = g_settings.getBool("new_style_water");
|
||||||
float node_water_level = 1.0;
|
float node_water_level = 1.0;
|
||||||
if(new_style_water)
|
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.
|
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::ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split):
|
ServerMapSector::ServerMapSector(NodeContainer *parent, v2s16 pos):
|
||||||
MapSector(parent, pos),
|
MapSector(parent, pos)
|
||||||
m_hm_split(hm_split),
|
|
||||||
m_objects(NULL)
|
|
||||||
{
|
{
|
||||||
// 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()
|
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)
|
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;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerMapSector::setGroundHeight(v2s16 p, f32 y, bool generate)
|
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)
|
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.
|
// Server has both of these, no need to support not having them.
|
||||||
assert(m_objects != NULL);
|
//assert(m_objects != NULL);
|
||||||
|
|
||||||
// Write version
|
// Write version
|
||||||
os.write((char*)&version, 1);
|
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(
|
ServerMapSector* ServerMapSector::deSerialize(
|
||||||
std::istream &is,
|
std::istream &is,
|
||||||
NodeContainer *parent,
|
NodeContainer *parent,
|
||||||
v2s16 p2d,
|
v2s16 p2d,
|
||||||
Heightmap *master_hm,
|
|
||||||
core::map<v2s16, MapSector*> & sectors
|
core::map<v2s16, MapSector*> & sectors
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -483,83 +240,9 @@ ServerMapSector* ServerMapSector::deSerialize(
|
|||||||
throw VersionMismatchException("ERROR: MapSector format not supported");
|
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
|
Get or create sector
|
||||||
*/
|
*/
|
||||||
@ -574,18 +257,13 @@ ServerMapSector* ServerMapSector::deSerialize(
|
|||||||
"at the moment, because code hasn't been tested."
|
"at the moment, because code hasn't been tested."
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
//assert(0);
|
|
||||||
MapSector *sector = n->getValue();
|
MapSector *sector = n->getValue();
|
||||||
assert(sector->getId() == MAPSECTOR_SERVER);
|
assert(sector->getId() == MAPSECTOR_SERVER);
|
||||||
return (ServerMapSector*)sector;
|
return (ServerMapSector*)sector;
|
||||||
|
|
||||||
// NOTE: At least hm_split mismatch would have to be checked
|
|
||||||
|
|
||||||
//sector = n->getValue();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sector = new ServerMapSector(parent, p2d, hm_split);
|
sector = new ServerMapSector(parent, p2d);
|
||||||
sectors.insert(p2d, sector);
|
sectors.insert(p2d, sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,26 +271,7 @@ ServerMapSector* ServerMapSector::deSerialize(
|
|||||||
Set stuff in sector
|
Set stuff in sector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Set heightmaps
|
// Nothing here
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
return sector;
|
return sector;
|
||||||
}
|
}
|
||||||
@ -654,29 +313,21 @@ void ClientMapSector::deSerialize(std::istream &is)
|
|||||||
|
|
||||||
if(!ser_ver_supported(version))
|
if(!ser_ver_supported(version))
|
||||||
throw VersionMismatchException("ERROR: MapSector format not supported");
|
throw VersionMismatchException("ERROR: MapSector format not supported");
|
||||||
if(version <= 7)
|
|
||||||
throw VersionMismatchException("ERROR: MapSector format not supported");
|
|
||||||
|
|
||||||
u8 buf[2];
|
u8 buf[2];
|
||||||
|
|
||||||
// Read corners
|
// Dummy read corners
|
||||||
is.read((char*)buf, 2);
|
is.read((char*)buf, 2);
|
||||||
s16 c0 = readU16(buf);
|
|
||||||
is.read((char*)buf, 2);
|
is.read((char*)buf, 2);
|
||||||
s16 c1 = readU16(buf);
|
|
||||||
is.read((char*)buf, 2);
|
is.read((char*)buf, 2);
|
||||||
s16 c2 = readU16(buf);
|
|
||||||
is.read((char*)buf, 2);
|
is.read((char*)buf, 2);
|
||||||
s16 c3 = readU16(buf);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set stuff in sector
|
Set stuff in sector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
m_corners[0] = c0;
|
// Nothing here
|
||||||
m_corners[1] = c1;
|
|
||||||
m_corners[2] = c2;
|
|
||||||
m_corners[3] = c3;
|
|
||||||
}
|
}
|
||||||
#endif // !SERVER
|
#endif // !SERVER
|
||||||
|
|
||||||
|
@ -27,26 +27,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <jmutex.h>
|
#include <jmutex.h>
|
||||||
#include "common_irrlicht.h"
|
#include "common_irrlicht.h"
|
||||||
#include "mapblock.h"
|
#include "mapblock.h"
|
||||||
#include "heightmap.h"
|
//#include "heightmap.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is an Y-wise stack of MapBlocks.
|
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_SERVER 0
|
||||||
#define MAPSECTOR_CLIENT 1
|
#define MAPSECTOR_CLIENT 1
|
||||||
|
|
||||||
class MapSector: public NodeContainer, public Heightmappish
|
class MapSector: public NodeContainer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -198,6 +189,7 @@ public:
|
|||||||
blockref->setNode(relpos, n);
|
blockref->setNode(relpos, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEPRECATED?
|
||||||
virtual f32 getGroundHeight(v2s16 p, bool generate=false)
|
virtual f32 getGroundHeight(v2s16 p, bool generate=false)
|
||||||
{
|
{
|
||||||
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
return GROUNDHEIGHT_NOTFOUND_SETVALUE;
|
||||||
@ -245,7 +237,7 @@ protected:
|
|||||||
class ServerMapSector : public MapSector
|
class ServerMapSector : public MapSector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ServerMapSector(NodeContainer *parent, v2s16 pos, u16 hm_split);
|
ServerMapSector(NodeContainer *parent, v2s16 pos);
|
||||||
~ServerMapSector();
|
~ServerMapSector();
|
||||||
|
|
||||||
u32 getId() const
|
u32 getId() const
|
||||||
@ -253,36 +245,7 @@ public:
|
|||||||
return MAPSECTOR_SERVER;
|
return MAPSECTOR_SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHeightmap(v2s16 hm_p, FixedHeightmap *hm);
|
// DEPRECATED?
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 getGroundHeight(v2s16 p, bool generate=false);
|
f32 getGroundHeight(v2s16 p, bool generate=false);
|
||||||
void setGroundHeight(v2s16 p, f32 y, bool generate=false);
|
void setGroundHeight(v2s16 p, f32 y, bool generate=false);
|
||||||
|
|
||||||
@ -296,20 +259,10 @@ public:
|
|||||||
std::istream &is,
|
std::istream &is,
|
||||||
NodeContainer *parent,
|
NodeContainer *parent,
|
||||||
v2s16 p2d,
|
v2s16 p2d,
|
||||||
Heightmap *master_hm,
|
|
||||||
core::map<v2s16, MapSector*> & sectors
|
core::map<v2s16, MapSector*> & sectors
|
||||||
);
|
);
|
||||||
|
|
||||||
private:
|
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
|
#ifndef SERVER
|
||||||
@ -326,14 +279,14 @@ public:
|
|||||||
|
|
||||||
void deSerialize(std::istream &is);
|
void deSerialize(std::istream &is);
|
||||||
|
|
||||||
s16 getCorner(u16 i)
|
/*s16 getCorner(u16 i)
|
||||||
{
|
{
|
||||||
return m_corners[i];
|
return m_corners[i];
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The ground height of the corners is stored in here
|
// The ground height of the corners is stored in here
|
||||||
s16 m_corners[4];
|
//s16 m_corners[4];
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1022,11 +1022,9 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Server::Server(
|
Server::Server(
|
||||||
std::string mapsavedir,
|
std::string mapsavedir
|
||||||
HMParams hm_params,
|
|
||||||
MapParams map_params
|
|
||||||
):
|
):
|
||||||
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_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||||
m_thread(this),
|
m_thread(this),
|
||||||
m_emergethread(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;
|
float &counter = m_emergethread_trigger_timer;
|
||||||
counter += dtime;
|
counter += dtime;
|
||||||
|
@ -377,9 +377,7 @@ public:
|
|||||||
NOTE: Every public method should be thread-safe
|
NOTE: Every public method should be thread-safe
|
||||||
*/
|
*/
|
||||||
Server(
|
Server(
|
||||||
std::string mapsavedir,
|
std::string mapsavedir
|
||||||
HMParams hm_params,
|
|
||||||
MapParams map_params
|
|
||||||
);
|
);
|
||||||
~Server();
|
~Server();
|
||||||
void start(unsigned short port);
|
void start(unsigned short port);
|
||||||
|
@ -263,18 +263,6 @@ int main(int argc, char *argv[])
|
|||||||
init_mapnode(&irrlicht);
|
init_mapnode(&irrlicht);
|
||||||
init_mineral(&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
|
Check parameters
|
||||||
*/
|
*/
|
||||||
@ -316,7 +304,7 @@ int main(int argc, char *argv[])
|
|||||||
map_dir = g_settings.get("map-dir");
|
map_dir = g_settings.get("map-dir");
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
Server server(map_dir.c_str(), hm_params, map_params);
|
Server server(map_dir.c_str());
|
||||||
server.start(port);
|
server.start(port);
|
||||||
|
|
||||||
// Run server
|
// 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 "map.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "heightmap.h"
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
@ -628,9 +627,7 @@ struct TestMapSector
|
|||||||
parent.position_valid = false;
|
parent.position_valid = false;
|
||||||
|
|
||||||
// Create one with no heightmaps
|
// Create one with no heightmaps
|
||||||
ServerMapSector sector(&parent, v2s16(1,1), 0);
|
ServerMapSector sector(&parent, v2s16(1,1));
|
||||||
//ConstantGenerator *dummyheightmap = new ConstantGenerator();
|
|
||||||
//sector->setHeightmap(dummyheightmap);
|
|
||||||
|
|
||||||
EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(0));
|
EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(0));
|
||||||
EXCEPTION_CHECK(InvalidPositionException, sector.getBlockNoCreate(1));
|
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
|
struct TestSocket
|
||||||
{
|
{
|
||||||
void Run()
|
void Run()
|
||||||
@ -1149,7 +1018,6 @@ void run_tests()
|
|||||||
TEST(TestVoxelManipulator);
|
TEST(TestVoxelManipulator);
|
||||||
TEST(TestMapBlock);
|
TEST(TestMapBlock);
|
||||||
TEST(TestMapSector);
|
TEST(TestMapSector);
|
||||||
TEST(TestHeightmap);
|
|
||||||
if(INTERNET_SIMULATOR == false){
|
if(INTERNET_SIMULATOR == false){
|
||||||
TEST(TestSocket);
|
TEST(TestSocket);
|
||||||
dout_con<<"=== BEGIN RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;
|
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;
|
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
|
blockpos: position of block in block coordinates
|
||||||
camera_pos: position of camera in nodes
|
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;
|
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
|
Miscellaneous functions
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user