forked from Mirrorlandia_minetest/minetest
sitä sun tätä tekeillä, toimii kivasti
This commit is contained in:
parent
e8fd5eb8ee
commit
c707e00195
12
Makefile
12
Makefile
@ -2,7 +2,7 @@
|
||||
# It's usually sufficient to change just the target name and source file list
|
||||
# and be sure that CXX is set to a valid compiler
|
||||
TARGET = test
|
||||
SOURCE_FILES = mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp
|
||||
SOURCE_FILES = voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp
|
||||
SOURCES = $(addprefix src/, $(SOURCE_FILES))
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
FASTTARGET = fasttest
|
||||
@ -13,7 +13,7 @@ JTHREADPATH = ../jthread/jthread-1.2.1
|
||||
CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src
|
||||
|
||||
#CXXFLAGS = -O2 -ffast-math -Wall -fomit-frame-pointer -pipe
|
||||
CXXFLAGS = -O2 -ffast-math -Wall -g
|
||||
CXXFLAGS = -O2 -ffast-math -Wall -g -pipe
|
||||
#CXXFLAGS = -O1 -ffast-math -Wall -g
|
||||
#CXXFLAGS = -Wall -g -O0
|
||||
|
||||
@ -21,8 +21,8 @@ CXXFLAGS = -O2 -ffast-math -Wall -g
|
||||
#CXXFLAGS = -O3 -ffast-math -Wall -g
|
||||
#CXXFLAGS = -O2 -ffast-math -Wall -g
|
||||
|
||||
#FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=pentium3
|
||||
FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686
|
||||
#FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686
|
||||
FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686 -fwhole-program
|
||||
|
||||
#Default target
|
||||
|
||||
@ -53,7 +53,9 @@ all_linux all_win32: $(DESTPATH)
|
||||
fast_linux: $(FASTDESTPATH)
|
||||
|
||||
$(FASTDESTPATH): $(SOURCES)
|
||||
$(CXX) -o $(FASTDESTPATH) $(SOURCES) $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE
|
||||
@#$(CXX) -o $(FASTDESTPATH) $(SOURCES) $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE
|
||||
@# Errno doesn't work ("error: ‘__errno_location’ was not declared in this scope")
|
||||
cat $(SOURCES) | $(CXX) -o $(FASTDESTPATH) -x c++ - -Isrc/ $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE -DDISABLE_ERRNO
|
||||
|
||||
$(DESTPATH): $(OBJECTS)
|
||||
$(CXX) -o $@ $(OBJECTS) $(LDFLAGS)
|
||||
|
BIN
data/mud.png
Normal file
BIN
data/mud.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 831 B |
@ -32,6 +32,7 @@ cp -r data/light.png $PACKAGEPATH/data/
|
||||
cp -r data/sign.png $PACKAGEPATH/data/
|
||||
cp -r data/sign_back.png $PACKAGEPATH/data/
|
||||
cp -r data/rat.png $PACKAGEPATH/data/
|
||||
cp -r data/mud.png $PACKAGEPATH/data/
|
||||
|
||||
cp -r doc/README.txt $PACKAGEPATH/doc/README.txt
|
||||
|
||||
|
@ -44,4 +44,8 @@ creative_mode = false
|
||||
# Player and object positions are sent at intervals specified by this
|
||||
objectdata_inverval = 0.2
|
||||
|
||||
active_object_range = 2
|
||||
|
||||
max_simultaneous_block_sends_per_client = 2
|
||||
max_simultaneous_block_sends_server_total = 4
|
||||
|
||||
|
@ -31,7 +31,7 @@ void * ClientUpdateThread::Thread()
|
||||
bool was = m_client->AsyncProcessData();
|
||||
|
||||
if(was == false)
|
||||
sleep_ms(50);
|
||||
sleep_ms(10);
|
||||
}
|
||||
#if CATCH_UNHANDLED_EXCEPTIONS
|
||||
}
|
||||
@ -159,13 +159,17 @@ void Client::step(float dtime)
|
||||
{
|
||||
/*
|
||||
Delete unused sectors
|
||||
|
||||
NOTE: This jams the game for a while because deleting sectors
|
||||
clear caches
|
||||
*/
|
||||
|
||||
static float counter = -0.001;
|
||||
counter -= dtime;
|
||||
if(counter <= 0.0)
|
||||
{
|
||||
counter = 10.0;
|
||||
// 3 minute interval
|
||||
counter = 180.0;
|
||||
|
||||
JMutexAutoLock lock(m_env_mutex);
|
||||
|
||||
@ -381,6 +385,8 @@ float Client::asyncStep()
|
||||
/*float dtime;
|
||||
{
|
||||
JMutexAutoLock lock1(m_step_dtime_mutex);
|
||||
if(m_step_dtime < 0.001)
|
||||
return 0.0;
|
||||
dtime = m_step_dtime;
|
||||
m_step_dtime = 0.0;
|
||||
}
|
||||
@ -1207,6 +1213,18 @@ bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater)
|
||||
|
||||
bool Client::AsyncProcessData()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
// We want to update the meshes as soon as a single packet has
|
||||
// been processed
|
||||
LazyMeshUpdater mesh_updater(&m_env);
|
||||
bool r = AsyncProcessPacket(mesh_updater);
|
||||
if(r == false)
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
||||
/*
|
||||
LazyMeshUpdater mesh_updater(&m_env);
|
||||
for(;;)
|
||||
{
|
||||
@ -1214,7 +1232,7 @@ bool Client::AsyncProcessData()
|
||||
if(r == false)
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
return false;*/
|
||||
}
|
||||
|
||||
void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
|
||||
|
@ -28,19 +28,20 @@
|
||||
// The absolute working limit is (2^15 - viewing_range).
|
||||
#define MAP_GENERATION_LIMIT (31000)
|
||||
|
||||
#define MAX_SIMULTANEOUS_BLOCK_SENDS 2
|
||||
//#define MAX_SIMULTANEOUS_BLOCK_SENDS 2
|
||||
|
||||
#define FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING 2.0
|
||||
#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 1
|
||||
//#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 1
|
||||
#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 0
|
||||
|
||||
#define MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL 4
|
||||
// Override for the previous one when distance is low
|
||||
#define BLOCK_SEND_DISABLE_LIMITS_MAX_D 1
|
||||
|
||||
//#define MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL 4
|
||||
|
||||
// Viewing range stuff
|
||||
|
||||
#define FPS_DEFAULT_WANTED 30
|
||||
#define FPS_DEFAULT_MAX 60
|
||||
|
||||
#define HEIGHTMAP_RANGE_NODES 300
|
||||
//#define HEIGHTMAP_RANGE_NODES 300
|
||||
|
||||
//#define FREETIME_RATIO 0.2
|
||||
#define FREETIME_RATIO 0.15
|
||||
@ -56,7 +57,7 @@
|
||||
//#define ACTIVE_OBJECT_D_BLOCKS 2
|
||||
|
||||
// Wether to catch all std::exceptions
|
||||
#define CATCH_UNJANDLED_EXCEPTIONS 1
|
||||
#define CATCH_UNHANDLED_EXCEPTIONS 0
|
||||
|
||||
/*
|
||||
Collecting active blocks is stopped after object data
|
||||
|
@ -81,6 +81,22 @@ public:
|
||||
{}
|
||||
};
|
||||
|
||||
class SettingNotFoundException : public BaseException
|
||||
{
|
||||
public:
|
||||
SettingNotFoundException(const char *s):
|
||||
BaseException(s)
|
||||
{}
|
||||
};
|
||||
|
||||
class InvalidFilenameException : public BaseException
|
||||
{
|
||||
public:
|
||||
InvalidFilenameException(const char *s):
|
||||
BaseException(s)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
Some "old-style" interrupts:
|
||||
*/
|
||||
|
342
src/main.cpp
342
src/main.cpp
@ -21,11 +21,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
=============================== NOTES ==============================
|
||||
|
||||
NOTE: VBO cannot be turned on for fast-changing stuff because there
|
||||
is an apparanet memory leak in irrlicht when using it
|
||||
is an apparanet memory leak in irrlicht when using it (not sure)
|
||||
|
||||
NOTE: iostream.imbue(std::locale("C")) is very slow
|
||||
NOTE: Global locale is now set at initialization
|
||||
|
||||
SUGGESTION: add a second lighting value to the MS nibble of param of
|
||||
air to tell how bright the air node is when there is no sunlight.
|
||||
When day changes to night, these two values can be interpolated.
|
||||
|
||||
TODO: Fix address to be ipv6 compatible
|
||||
|
||||
TODO: ESC Pause mode in which the cursor is not kept at the center of window.
|
||||
@ -93,9 +97,7 @@ TODO: Expose Connection's seqnums and ACKs to server and client.
|
||||
- This also enables server to check if client has received the
|
||||
most recent block sent, for example.
|
||||
|
||||
SUGG: Add a time value to the param of footstepped grass and check it
|
||||
against a global timer when a block is accessed, to make old
|
||||
steps fade away.
|
||||
TODO: Add a sane bandwidth throttling system to Connection
|
||||
|
||||
FIXME: There still are *some* tiny glitches in lighting as seen from
|
||||
the client side. The server calculates them right but sometimes
|
||||
@ -105,8 +107,9 @@ FIXME: There still are *some* tiny glitches in lighting as seen from
|
||||
the sender sends the block as it was before emerging?
|
||||
TODO: How about adding a "revision" field to MapBlocks?
|
||||
|
||||
TODO: More fine-grained control of client's dumping of blocks from
|
||||
SUGG: More fine-grained control of client's dumping of blocks from
|
||||
memory
|
||||
- ...What does this mean in the first place?
|
||||
|
||||
TODO: Somehow prioritize the sending of blocks and combine the block
|
||||
send queue lengths
|
||||
@ -130,9 +133,6 @@ SUGG: Make client send GOTBLOCKS before updating meshes
|
||||
|
||||
TODO: Server to load starting inventory from disk
|
||||
|
||||
NOTE: iostream.imbue(std::locale("C")) is very slow
|
||||
NOTE: Global locale is now set at initialization
|
||||
|
||||
TODO: PLayers to only be hidden when the client quits.
|
||||
TODO: - Players to be saved on disk, with inventory
|
||||
TODO: Players to be saved as text in map/players/<name>
|
||||
@ -158,12 +158,18 @@ Block object server side:
|
||||
- A "near blocks" buffer, in which some nearby blocks are stored.
|
||||
- For all blocks in the buffer, objects are stepped(). This
|
||||
means they are active.
|
||||
- TODO All blocks going in and out of the buffer are recorded.
|
||||
- TODO For outgoing blocks, a timestamp is written.
|
||||
- TODO For incoming blocks, the time difference is calculated and
|
||||
- TODO: A global active buffer is needed for the server
|
||||
- TODO: All blocks going in and out of the buffer are recorded.
|
||||
- TODO: For outgoing blocks, a timestamp is written.
|
||||
- TODO: For incoming blocks, the time difference is calculated and
|
||||
objects are stepped according to it.
|
||||
TODO: A timestamp to blocks
|
||||
|
||||
SUGG: Add a time value to the param of footstepped grass and check it
|
||||
against a global timer when a block is accessed, to make old
|
||||
steps fade away.
|
||||
|
||||
|
||||
TODO: Add config parameters for server's sending and generating distance
|
||||
|
||||
TODO: Copy the text of the last picked sign to inventory in creative
|
||||
@ -185,12 +191,16 @@ SUGG: Split MapBlockObject serialization to to-client and to-disk
|
||||
- This will allow saving ages of rats on disk but not sending
|
||||
them to clients
|
||||
|
||||
TODO: Fix the long-lived Server Block Emerge Jam bug
|
||||
- Is it related to the client deleting blocks?
|
||||
TODO: Get rid of GotSplitPacketException
|
||||
|
||||
Before release:
|
||||
|
||||
TODO: Check what goes wrong with caching map to disk (Kray)
|
||||
|
||||
Doing now:
|
||||
======================================================================
|
||||
|
||||
TODO: Implement lighting using VoxelManipulator
|
||||
|
||||
======================================================================
|
||||
|
||||
@ -202,7 +212,7 @@ Doing now:
|
||||
the starting place to a static direction.
|
||||
|
||||
This allows one to move around with the player and see what
|
||||
is actually drawn behind solid things etc.
|
||||
is actually drawn behind solid things and behind the player.
|
||||
*/
|
||||
#define FIELD_OF_VIEW_TEST 0
|
||||
|
||||
@ -265,7 +275,8 @@ const char *g_material_filenames[MATERIALS_COUNT] =
|
||||
"../data/tree.png",
|
||||
"../data/leaves.png",
|
||||
"../data/grass_footsteps.png",
|
||||
"../data/mese.png"
|
||||
"../data/mese.png",
|
||||
"../data/mud.png"
|
||||
};
|
||||
|
||||
video::SMaterial g_materials[MATERIALS_COUNT];
|
||||
@ -296,28 +307,39 @@ bool g_viewing_range_all = false;
|
||||
These are loaded from the config file.
|
||||
*/
|
||||
|
||||
std::string g_dedicated_server;
|
||||
Settings g_settings;
|
||||
|
||||
// Client stuff
|
||||
float g_wanted_fps = FPS_DEFAULT_WANTED;
|
||||
float g_fps_max = FPS_DEFAULT_MAX;
|
||||
s16 g_viewing_range_nodes_max = 300;
|
||||
s16 g_viewing_range_nodes_min = 20;
|
||||
std::string g_screenW;
|
||||
std::string g_screenH;
|
||||
std::string g_host_game;
|
||||
std::string g_port;
|
||||
std::string g_address;
|
||||
std::string g_name;
|
||||
bool g_random_input = false;
|
||||
float g_client_delete_unused_sectors_timeout = 1200;
|
||||
// Sets default settings
|
||||
void set_default_settings()
|
||||
{
|
||||
g_settings.set("dedicated_server", "");
|
||||
|
||||
// Server stuff
|
||||
bool g_creative_mode = false;
|
||||
HMParams g_hm_params;
|
||||
MapParams g_map_params;
|
||||
float g_objectdata_interval = 0.2;
|
||||
u16 g_active_object_range = 2;
|
||||
// Client stuff
|
||||
g_settings.set("wanted_fps", "30");
|
||||
g_settings.set("fps_max", "60");
|
||||
g_settings.set("viewing_range_nodes_max", "300");
|
||||
g_settings.set("viewing_range_nodes_min", "20");
|
||||
g_settings.set("screenW", "");
|
||||
g_settings.set("screenH", "");
|
||||
g_settings.set("host_game", "");
|
||||
g_settings.set("port", "");
|
||||
g_settings.set("address", "");
|
||||
g_settings.set("name", "");
|
||||
g_settings.set("random_input", "false");
|
||||
g_settings.set("client_delete_unused_sectors_timeout", "1200");
|
||||
|
||||
// Server stuff
|
||||
g_settings.set("creative_mode", "false");
|
||||
g_settings.set("heightmap_blocksize", "128");
|
||||
g_settings.set("height_randmax", "constant 70.0");
|
||||
g_settings.set("height_randfactor", "constant 0.6");
|
||||
g_settings.set("height_base", "linear 0 35 0");
|
||||
g_settings.set("plants_amount", "1.0");
|
||||
g_settings.set("objectdata_interval", "0.2");
|
||||
g_settings.set("active_object_range", "2");
|
||||
g_settings.set("max_simultaneous_block_sends_per_client", "2");
|
||||
g_settings.set("max_simultaneous_block_sends_server_total", "4");
|
||||
}
|
||||
|
||||
/*
|
||||
Random stuff
|
||||
@ -354,144 +376,6 @@ std::ostream *derr_server_ptr = &dstream;
|
||||
std::ostream *dout_client_ptr = &dstream;
|
||||
std::ostream *derr_client_ptr = &dstream;
|
||||
|
||||
/*
|
||||
Config stuff
|
||||
*/
|
||||
|
||||
// Returns false on EOF
|
||||
bool parseConfigObject(std::istream &is)
|
||||
{
|
||||
// float g_wanted_fps
|
||||
// s16 g_viewing_range_nodes_max
|
||||
|
||||
if(is.eof())
|
||||
return false;
|
||||
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
//dstream<<"got line: \""<<line<<"\""<<std::endl;
|
||||
|
||||
std::string trimmedline = trim(line);
|
||||
|
||||
// Ignore comments
|
||||
if(trimmedline[0] == '#')
|
||||
return true;
|
||||
|
||||
//dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
|
||||
|
||||
Strfnd sf(trim(line));
|
||||
|
||||
std::string name = sf.next("=");
|
||||
name = trim(name);
|
||||
|
||||
if(name == "")
|
||||
return true;
|
||||
|
||||
std::string value = sf.next("\n");
|
||||
value = trim(value);
|
||||
|
||||
dstream<<"Config name=\""<<name<<"\" value=\""
|
||||
<<value<<"\""<<std::endl;
|
||||
|
||||
if(name == "dedicated_server")
|
||||
g_dedicated_server = value;
|
||||
|
||||
// Client stuff
|
||||
else if(name == "wanted_fps")
|
||||
{
|
||||
g_wanted_fps = atof(value.c_str());
|
||||
}
|
||||
else if(name == "fps_max")
|
||||
{
|
||||
g_fps_max = atof(value.c_str());
|
||||
}
|
||||
else if(name == "viewing_range_nodes_max")
|
||||
{
|
||||
g_viewing_range_nodes_max = stoi(value, 0, 32767);
|
||||
}
|
||||
else if(name == "viewing_range_nodes_min")
|
||||
{
|
||||
g_viewing_range_nodes_min = stoi(value, 0, 32767);
|
||||
}
|
||||
else if(name=="screenW")
|
||||
g_screenW = value;
|
||||
else if(name=="screenH")
|
||||
g_screenH = value;
|
||||
else if(name == "host_game")
|
||||
g_host_game = value;
|
||||
else if(name == "port")
|
||||
g_port = value;
|
||||
else if(name == "address")
|
||||
g_address = value;
|
||||
else if(name == "name")
|
||||
g_name = value;
|
||||
else if(name == "random_input")
|
||||
g_random_input = is_yes(value);
|
||||
else if(name == "client_delete_unused_sectors_timeout")
|
||||
{
|
||||
std::istringstream vis(value);
|
||||
//vis.imbue(std::locale("C"));
|
||||
vis>>g_client_delete_unused_sectors_timeout;
|
||||
}
|
||||
|
||||
// Server stuff
|
||||
else if(name == "creative_mode")
|
||||
g_creative_mode = is_yes(value);
|
||||
else if(name == "mapgen_heightmap_blocksize")
|
||||
{
|
||||
s32 d = atoi(value.c_str());
|
||||
if(d > 0 && (d & (d-1)) == 0)
|
||||
g_hm_params.heightmap_blocksize = d;
|
||||
else
|
||||
dstream<<"Invalid value in config file: \""
|
||||
<<line<<"\""<<std::endl;
|
||||
}
|
||||
else if(name == "mapgen_height_randmax")
|
||||
g_hm_params.height_randmax = value;
|
||||
else if(name == "mapgen_height_randfactor")
|
||||
g_hm_params.height_randfactor = value;
|
||||
else if(name == "mapgen_height_base")
|
||||
g_hm_params.height_base = value;
|
||||
else if(name == "mapgen_plants_amount")
|
||||
{
|
||||
std::istringstream vis(value);
|
||||
vis>>g_map_params.plants_amount;
|
||||
}
|
||||
else if(name == "objectdata_inverval")
|
||||
{
|
||||
std::istringstream vis(value);
|
||||
vis>>g_objectdata_interval;
|
||||
}
|
||||
else if(name == "active_object_range")
|
||||
g_active_object_range = stoi(value, 0, 65535);
|
||||
|
||||
else
|
||||
{
|
||||
dstream<<"Unknown option in config file: \""
|
||||
<<line<<"\""<<std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true on success
|
||||
bool readConfigFile(const char *filename)
|
||||
{
|
||||
std::ifstream is(filename);
|
||||
if(is.good() == false)
|
||||
{
|
||||
dstream<<DTIME<<"Error opening configuration file: "
|
||||
<<filename<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
dstream<<DTIME<<"Parsing configuration file: "
|
||||
<<filename<<std::endl;
|
||||
|
||||
while(parseConfigObject(is));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Timestamp stuff
|
||||
@ -876,8 +760,10 @@ void updateViewingRange(f32 frametime, Client *client)
|
||||
if(g_viewing_range_all == true)
|
||||
return;
|
||||
|
||||
float wanted_fps = g_settings.getFloat("wanted_fps");
|
||||
|
||||
// Initialize to the target value
|
||||
static float frametime_avg = 1.0/g_wanted_fps;
|
||||
static float frametime_avg = 1.0/wanted_fps;
|
||||
frametime_avg = frametime_avg * 0.9 + frametime * 0.1;
|
||||
|
||||
static f32 counter = 0;
|
||||
@ -892,7 +778,7 @@ void updateViewingRange(f32 frametime, Client *client)
|
||||
//float freetime_ratio = 0.4;
|
||||
float freetime_ratio = FREETIME_RATIO;
|
||||
|
||||
float frametime_wanted = (1.0/(g_wanted_fps/(1.0-freetime_ratio)));
|
||||
float frametime_wanted = (1.0/(wanted_fps/(1.0-freetime_ratio)));
|
||||
|
||||
float fraction = sqrt(frametime_avg / frametime_wanted);
|
||||
|
||||
@ -925,11 +811,14 @@ void updateViewingRange(f32 frametime, Client *client)
|
||||
|
||||
JMutexAutoLock lock(g_range_mutex);
|
||||
|
||||
s16 viewing_range_nodes_min = g_settings.getS16("viewing_range_nodes_min");
|
||||
s16 viewing_range_nodes_max = g_settings.getS16("viewing_range_nodes_max");
|
||||
|
||||
s16 n = (float)g_viewing_range_nodes / fraction;
|
||||
if(n < g_viewing_range_nodes_min)
|
||||
n = g_viewing_range_nodes_min;
|
||||
if(n > g_viewing_range_nodes_max)
|
||||
n = g_viewing_range_nodes_max;
|
||||
if(n < viewing_range_nodes_min)
|
||||
n = viewing_range_nodes_min;
|
||||
if(n > viewing_range_nodes_max)
|
||||
n = viewing_range_nodes_max;
|
||||
|
||||
bool can_change = true;
|
||||
|
||||
@ -1050,10 +939,11 @@ int main(int argc, char *argv[])
|
||||
disable_stderr = true;
|
||||
#endif
|
||||
|
||||
// Initialize debug streams
|
||||
debugstreams_init(disable_stderr, DEBUGFILE);
|
||||
// Initialize debug stacks
|
||||
debug_stacks_init();
|
||||
|
||||
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
try
|
||||
@ -1063,6 +953,10 @@ int main(int argc, char *argv[])
|
||||
Basic initialization
|
||||
*/
|
||||
|
||||
// Initialize default settings
|
||||
set_default_settings();
|
||||
|
||||
// Print startup message
|
||||
dstream<<DTIME<<"minetest-c55"
|
||||
" with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
|
||||
<<", ENABLE_TESTS="<<ENABLE_TESTS
|
||||
@ -1096,7 +990,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if(argc >= 2)
|
||||
{
|
||||
readConfigFile(argv[1]);
|
||||
g_settings.readConfigFile(argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1108,7 +1002,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
for(u32 i=0; i<2; i++)
|
||||
{
|
||||
bool r = readConfigFile(filenames[i]);
|
||||
bool r = g_settings.readConfigFile(filenames[i]);
|
||||
if(r)
|
||||
break;
|
||||
}
|
||||
@ -1120,6 +1014,17 @@ int main(int argc, char *argv[])
|
||||
g_range_mutex.Init();
|
||||
assert(g_range_mutex.IsInitialized());
|
||||
|
||||
// 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");
|
||||
|
||||
/*
|
||||
Ask some stuff
|
||||
*/
|
||||
@ -1127,40 +1032,13 @@ int main(int argc, char *argv[])
|
||||
std::cout<<std::endl<<std::endl;
|
||||
char templine[100];
|
||||
|
||||
std::cout<<"Dedicated server? [y = yes]: ";
|
||||
if(g_dedicated_server != "")
|
||||
{
|
||||
std::cout<<g_dedicated_server<<std::endl;
|
||||
snprintf(templine, 100, "%s", g_dedicated_server.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cin.getline(templine, 100);
|
||||
}
|
||||
// Dedicated?
|
||||
bool dedicated = g_settings.getBoolAsk
|
||||
("dedicated_server", "Dedicated server?", false);
|
||||
std::cout<<"dedicated = "<<dedicated<<std::endl;
|
||||
|
||||
bool dedicated = false;
|
||||
if(templine[0] == 'y')
|
||||
dedicated = true;
|
||||
if(dedicated)
|
||||
std::cout<<"-> yes"<<std::endl;
|
||||
else
|
||||
std::cout<<"-> no"<<std::endl;
|
||||
|
||||
std::cout<<"Port [empty=30000]: ";
|
||||
if(g_port != "")
|
||||
{
|
||||
std::cout<<g_port<<std::endl;
|
||||
snprintf(templine, 100, "%s", g_port.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cin.getline(templine, 100);
|
||||
}
|
||||
unsigned short port;
|
||||
if(templine[0] == 0)
|
||||
port = 30000;
|
||||
else
|
||||
port = atoi(templine);
|
||||
// Port?
|
||||
u16 port = g_settings.getU16Ask("port", "Port", 30000);
|
||||
std::cout<<"-> "<<port<<std::endl;
|
||||
|
||||
if(dedicated)
|
||||
@ -1173,17 +1051,15 @@ int main(int argc, char *argv[])
|
||||
std::cout<<"========================"<<std::endl;
|
||||
std::cout<<std::endl;
|
||||
|
||||
Server server("../map", g_creative_mode, g_hm_params,
|
||||
g_map_params, g_objectdata_interval,
|
||||
g_active_object_range);
|
||||
Server server("../map", hm_params, map_params);
|
||||
server.start(port);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// This is kind of a hack but can be done like this
|
||||
// because server.step() is very light
|
||||
sleep_ms(100);
|
||||
server.step(0.1);
|
||||
sleep_ms(30);
|
||||
server.step(0.030);
|
||||
|
||||
static int counter = 0;
|
||||
counter--;
|
||||
@ -1214,10 +1090,10 @@ int main(int argc, char *argv[])
|
||||
char connect_name[100] = "";
|
||||
|
||||
std::cout<<"Address to connect to [empty = host a game]: ";
|
||||
if(g_address != "" && is_yes(g_host_game) == false)
|
||||
if(g_settings.get("address") != "" && is_yes(g_settings.get("host_game")) == false)
|
||||
{
|
||||
std::cout<<g_address<<std::endl;
|
||||
snprintf(connect_name, 100, "%s", g_address.c_str());
|
||||
std::cout<<g_settings.get("address")<<std::endl;
|
||||
snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1235,9 +1111,9 @@ int main(int argc, char *argv[])
|
||||
std::cout<<"-> "<<connect_name<<std::endl;
|
||||
|
||||
char playername[PLAYERNAME_SIZE] = "";
|
||||
if(g_name != "")
|
||||
if(g_settings.get("name") != "")
|
||||
{
|
||||
snprintf(playername, PLAYERNAME_SIZE, "%s", g_name.c_str());
|
||||
snprintf(playername, PLAYERNAME_SIZE, "%s", g_settings.get("name").c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1254,10 +1130,10 @@ int main(int argc, char *argv[])
|
||||
u16 screenH;
|
||||
bool fullscreen = false;
|
||||
|
||||
if(g_screenW != "" && g_screenH != "")
|
||||
if(g_settings.get("screenW") != "" && g_settings.get("screenH") != "")
|
||||
{
|
||||
screenW = atoi(g_screenW.c_str());
|
||||
screenH = atoi(g_screenH.c_str());
|
||||
screenW = atoi(g_settings.get("screenW").c_str());
|
||||
screenH = atoi(g_settings.get("screenH").c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1343,7 +1219,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
device->setResizable(true);
|
||||
|
||||
if(g_random_input)
|
||||
if(g_settings.getBool("random_input"))
|
||||
g_input = new RandomInputHandler();
|
||||
else
|
||||
g_input = new RealInputHandler(device, &receiver);
|
||||
@ -1443,9 +1319,7 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
SharedPtr<Server> server;
|
||||
if(hosting){
|
||||
server = new Server("../map", g_creative_mode, g_hm_params,
|
||||
g_map_params, g_objectdata_interval,
|
||||
g_active_object_range);
|
||||
server = new Server("../map", hm_params, map_params);
|
||||
server->start(port);
|
||||
}
|
||||
|
||||
@ -1455,7 +1329,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// TODO: Get rid of the g_materials parameter or it's globalness
|
||||
Client client(device, g_materials,
|
||||
g_client_delete_unused_sectors_timeout,
|
||||
g_settings.getFloat("client_delete_unused_sectors_timeout"),
|
||||
playername);
|
||||
|
||||
Address connect_address(0,0,0,0, port);
|
||||
@ -1648,7 +1522,7 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
|
||||
{
|
||||
float fps_max = g_fps_max;
|
||||
float fps_max = g_settings.getFloat("fps_max");
|
||||
u32 frametime_min = 1000./fps_max;
|
||||
|
||||
if(busytime_u32 < frametime_min)
|
||||
|
@ -16,6 +16,9 @@ extern s16 g_viewing_range_nodes;
|
||||
//extern s16 g_actual_viewing_range_nodes;
|
||||
extern bool g_viewing_range_all;
|
||||
|
||||
// Settings
|
||||
extern Settings g_settings;
|
||||
|
||||
#include <fstream>
|
||||
|
||||
// Debug streams
|
||||
|
405
src/map.cpp
405
src/map.cpp
@ -9,6 +9,7 @@
|
||||
#include "client.h"
|
||||
#include "filesys.h"
|
||||
#include "utility.h"
|
||||
#include "voxel.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@ -18,6 +19,47 @@
|
||||
#define sleep_ms(x) usleep(x*1000)
|
||||
#endif
|
||||
|
||||
MapBlockPointerCache::MapBlockPointerCache(Map *map)
|
||||
{
|
||||
m_map = map;
|
||||
m_map->m_blockcachelock.cacheCreated();
|
||||
|
||||
m_from_cache_count = 0;
|
||||
m_from_map_count = 0;
|
||||
}
|
||||
|
||||
MapBlockPointerCache::~MapBlockPointerCache()
|
||||
{
|
||||
m_map->m_blockcachelock.cacheRemoved();
|
||||
|
||||
dstream<<"MapBlockPointerCache:"
|
||||
<<" from_cache_count="<<m_from_cache_count
|
||||
<<" from_map_count="<<m_from_map_count
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
MapBlock * MapBlockPointerCache::getBlockNoCreate(v3s16 p)
|
||||
{
|
||||
core::map<v3s16, MapBlock*>::Node *n = NULL;
|
||||
n = m_blocks.find(p);
|
||||
if(n != NULL)
|
||||
{
|
||||
m_from_cache_count++;
|
||||
return n->getValue();
|
||||
}
|
||||
|
||||
m_from_map_count++;
|
||||
|
||||
// Throws InvalidPositionException if not found
|
||||
MapBlock *b = m_map->getBlockNoCreate(p);
|
||||
m_blocks[p] = b;
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
Map
|
||||
*/
|
||||
|
||||
Map::Map(std::ostream &dout):
|
||||
m_dout(dout),
|
||||
m_camera_position(0,0,0),
|
||||
@ -158,33 +200,11 @@ bool Map::isNodeUnderground(v3s16 p)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LKJnb
|
||||
//TODO: Remove: Not used.
|
||||
/*
|
||||
Goes recursively through the neighbours of the node.
|
||||
|
||||
Alters only transparent nodes.
|
||||
|
||||
If the lighting of the neighbour is lower than the lighting of
|
||||
the node was (before changing it to 0 at the step before), the
|
||||
lighting of the neighbour is set to 0 and then the same stuff
|
||||
repeats for the neighbour.
|
||||
|
||||
Some things are made strangely to make it as fast as possible.
|
||||
|
||||
Usage: (for clearing all possible spreaded light of a lamp)
|
||||
NOTE: This is outdated
|
||||
core::list<v3s16> light_sources;
|
||||
core::map<v3s16, MapBlock*> modified_blocks;
|
||||
u8 oldlight = node_at_pos.light;
|
||||
node_at_pos.setLight(0);
|
||||
unLightNeighbors(pos, oldlight, light_sources, modified_blocks);
|
||||
*/
|
||||
void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
||||
core::map<v3s16, bool> & light_sources,
|
||||
#if 0
|
||||
void Map::interpolate(v3s16 block,
|
||||
core::map<v3s16, MapBlock*> & modified_blocks)
|
||||
{
|
||||
v3s16 dirs[6] = {
|
||||
const v3s16 dirs[6] = {
|
||||
v3s16(0,0,1), // back
|
||||
v3s16(0,1,0), // top
|
||||
v3s16(1,0,0), // right
|
||||
@ -193,6 +213,15 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
||||
v3s16(-1,0,0), // left
|
||||
};
|
||||
|
||||
if(from_nodes.size() == 0)
|
||||
return;
|
||||
|
||||
u32 blockchangecount = 0;
|
||||
|
||||
core::map<v3s16, bool> lighted_nodes;
|
||||
core::map<v3s16, bool>::Iterator j;
|
||||
j = from_nodes.getIterator();
|
||||
|
||||
/*
|
||||
Initialize block cache
|
||||
*/
|
||||
@ -201,23 +230,22 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
||||
// Cache this a bit, too
|
||||
bool block_checked_in_modified = false;
|
||||
|
||||
// Loop through 6 neighbors
|
||||
for(u16 i=0; i<6; i++){
|
||||
// Get the position of the neighbor node
|
||||
v3s16 n2pos = pos + dirs[i];
|
||||
|
||||
// Get the block where the node is located
|
||||
v3s16 blockpos = getNodeBlockPos(n2pos);
|
||||
for(; j.atEnd() == false; j++)
|
||||
//for(; j != from_nodes.end(); j++)
|
||||
{
|
||||
v3s16 pos = j.getNode()->getKey();
|
||||
//v3s16 pos = *j;
|
||||
//dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
|
||||
v3s16 blockpos = getNodeBlockPos(pos);
|
||||
|
||||
// Only fetch a new block if the block position has changed
|
||||
try{
|
||||
if(block == NULL || blockpos != blockpos_last)
|
||||
{
|
||||
if(block == NULL || blockpos != blockpos_last){
|
||||
block = getBlockNoCreate(blockpos);
|
||||
blockpos_last = blockpos;
|
||||
|
||||
block_checked_in_modified = false;
|
||||
//blockchangecount++;
|
||||
blockchangecount++;
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
@ -228,32 +256,74 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
||||
if(block->isDummy())
|
||||
continue;
|
||||
|
||||
// Calculate relative position in block
|
||||
v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
|
||||
|
||||
// Get node straight from the block
|
||||
MapNode n = block->getNode(relpos);
|
||||
|
||||
u8 oldlight = n.getLight();
|
||||
u8 newlight = diminish_light(oldlight);
|
||||
|
||||
// Loop through 6 neighbors
|
||||
for(u16 i=0; i<6; i++){
|
||||
// Get the position of the neighbor node
|
||||
v3s16 n2pos = pos + dirs[i];
|
||||
|
||||
// Get the block where the node is located
|
||||
v3s16 blockpos = getNodeBlockPos(n2pos);
|
||||
|
||||
try
|
||||
{
|
||||
// Only fetch a new block if the block position has changed
|
||||
try{
|
||||
if(block == NULL || blockpos != blockpos_last){
|
||||
block = getBlockNoCreate(blockpos);
|
||||
blockpos_last = blockpos;
|
||||
|
||||
block_checked_in_modified = false;
|
||||
blockchangecount++;
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate relative position in block
|
||||
v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
|
||||
// Get node straight from the block
|
||||
MapNode n2 = block->getNode(relpos);
|
||||
|
||||
bool changed = false;
|
||||
/*
|
||||
If the neighbor is dimmer than what was specified
|
||||
as oldlight (the light of the previous node)
|
||||
If the neighbor is brighter than the current node,
|
||||
add to list (it will light up this node on its turn)
|
||||
*/
|
||||
if(n2.getLight() < oldlight)
|
||||
if(n2.getLight() > undiminish_light(oldlight))
|
||||
{
|
||||
lighted_nodes.insert(n2pos, true);
|
||||
//lighted_nodes.push_back(n2pos);
|
||||
changed = true;
|
||||
}
|
||||
/*
|
||||
And the neighbor is transparent and it has some light
|
||||
If the neighbor is dimmer than how much light this node
|
||||
would spread on it, add to list
|
||||
*/
|
||||
if(n2.light_propagates() && n2.getLight() != 0)
|
||||
if(n2.getLight() < newlight)
|
||||
{
|
||||
/*
|
||||
Set light to 0 and recurse.
|
||||
*/
|
||||
u8 current_light = n2.getLight();
|
||||
n2.setLight(0);
|
||||
if(n2.light_propagates())
|
||||
{
|
||||
n2.setLight(newlight);
|
||||
block->setNode(relpos, n2);
|
||||
unLightNeighbors(n2pos, current_light,
|
||||
light_sources, modified_blocks);
|
||||
lighted_nodes.insert(n2pos, true);
|
||||
//lighted_nodes.push_back(n2pos);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(block_checked_in_modified == false)
|
||||
// Add to modified_blocks
|
||||
if(changed == true && block_checked_in_modified == false)
|
||||
{
|
||||
// If the block is not found in modified_blocks, add.
|
||||
if(modified_blocks.find(blockpos) == NULL)
|
||||
@ -263,12 +333,20 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
||||
block_checked_in_modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
//light_sources.push_back(n2pos);
|
||||
light_sources.insert(n2pos, true);
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*dstream<<"spreadLight(): Changed block "
|
||||
<<blockchangecount<<" times"
|
||||
<<" for "<<from_nodes.size()<<" nodes"
|
||||
<<std::endl;*/
|
||||
|
||||
if(lighted_nodes.size() > 0)
|
||||
spreadLight(lighted_nodes, modified_blocks);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1090,6 +1168,13 @@ void Map::timerUpdate(float dtime)
|
||||
|
||||
void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
|
||||
{
|
||||
/*
|
||||
Wait for caches to be removed before continuing.
|
||||
|
||||
This disables the existence of caches while locked
|
||||
*/
|
||||
SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
|
||||
|
||||
core::list<v2s16>::Iterator j;
|
||||
for(j=list.begin(); j!=list.end(); j++)
|
||||
{
|
||||
@ -1215,13 +1300,13 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
|
||||
|
||||
// Create master heightmap
|
||||
ValueGenerator *maxgen =
|
||||
ValueGenerator::deSerialize(hmp.height_randmax);
|
||||
ValueGenerator::deSerialize(hmp.randmax);
|
||||
ValueGenerator *factorgen =
|
||||
ValueGenerator::deSerialize(hmp.height_randfactor);
|
||||
ValueGenerator::deSerialize(hmp.randfactor);
|
||||
ValueGenerator *basegen =
|
||||
ValueGenerator::deSerialize(hmp.height_base);
|
||||
ValueGenerator::deSerialize(hmp.base);
|
||||
m_heightmap = new UnlimitedHeightmap
|
||||
(hmp.heightmap_blocksize, maxgen, factorgen, basegen);
|
||||
(hmp.blocksize, maxgen, factorgen, basegen);
|
||||
|
||||
// Set map parameters
|
||||
m_params = mp;
|
||||
@ -1409,6 +1494,9 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
|
||||
SECTOR_OBJECT_TREE_1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Plant some bushes if sector is pit-like
|
||||
*/
|
||||
{
|
||||
// Pitness usually goes at around -0.5...0.5
|
||||
u32 bush_max = 0;
|
||||
@ -1429,6 +1517,22 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
|
||||
SECTOR_OBJECT_BUSH_1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Add ravine (randomly)
|
||||
*/
|
||||
{
|
||||
if(rand()%10 == 0)
|
||||
{
|
||||
s16 s = 6;
|
||||
s16 x = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
|
||||
s16 z = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
|
||||
/*s16 x = 8;
|
||||
s16 z = 8;*/
|
||||
s16 y = sector->getGroundHeight(v2s16(x,z))+1;
|
||||
objects->insert(v3s16(x, y, z),
|
||||
SECTOR_OBJECT_RAVINE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Insert to container
|
||||
@ -1533,9 +1637,16 @@ MapBlock * ServerMap::emergeBlock(
|
||||
}
|
||||
|
||||
// Randomize a bit. This makes dungeons.
|
||||
bool low_block_is_empty = false;
|
||||
/*bool low_block_is_empty = false;
|
||||
if(rand() % 4 == 0)
|
||||
low_block_is_empty = true;
|
||||
low_block_is_empty = true;*/
|
||||
|
||||
s32 ued = 4;
|
||||
bool underground_emptiness[ued*ued*ued];
|
||||
for(s32 i=0; i<ued*ued*ued; i++)
|
||||
{
|
||||
underground_emptiness[i] = ((rand() % 4) == 0);
|
||||
}
|
||||
|
||||
// This is the basic material of what the visible flat ground
|
||||
// will consist of
|
||||
@ -1551,9 +1662,7 @@ MapBlock * ServerMap::emergeBlock(
|
||||
{
|
||||
//dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
|
||||
float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
|
||||
|
||||
assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
|
||||
|
||||
s16 surface_y = surface_y_f;
|
||||
//avg_ground_y += surface_y;
|
||||
if(surface_y < lowest_ground_y)
|
||||
@ -1574,13 +1683,14 @@ MapBlock * ServerMap::emergeBlock(
|
||||
else
|
||||
surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
|
||||
|
||||
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++){
|
||||
for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
|
||||
{
|
||||
s16 real_y = block_y * MAP_BLOCKSIZE + y0;
|
||||
MapNode n;
|
||||
/*
|
||||
Calculate lighting
|
||||
|
||||
FIXME: If there are some man-made structures above the
|
||||
NOTE: If there are some man-made structures above the
|
||||
newly created block, they won't be taken into account.
|
||||
*/
|
||||
if(real_y > surface_y)
|
||||
@ -1589,12 +1699,17 @@ MapBlock * ServerMap::emergeBlock(
|
||||
Calculate material
|
||||
*/
|
||||
// If node is very low
|
||||
if(real_y <= surface_y - 10){
|
||||
if(real_y <= surface_y - 7){
|
||||
// Create dungeons
|
||||
if(low_block_is_empty){
|
||||
if(underground_emptiness[
|
||||
ued*ued*(z0*ued/MAP_BLOCKSIZE)
|
||||
+ued*(y0*ued/MAP_BLOCKSIZE)
|
||||
+(x0*ued/MAP_BLOCKSIZE)])
|
||||
{
|
||||
n.d = MATERIAL_AIR;
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
n.d = MATERIAL_STONE;
|
||||
}
|
||||
}
|
||||
@ -1603,7 +1718,14 @@ MapBlock * ServerMap::emergeBlock(
|
||||
n.d = MATERIAL_STONE;
|
||||
// If node is at or under heightmap y
|
||||
else if(real_y <= surface_y)
|
||||
{
|
||||
// If under water level, it's mud
|
||||
if(real_y < WATER_LEVEL)
|
||||
n.d = MATERIAL_MUD;
|
||||
// Else it's the main material
|
||||
else
|
||||
n.d = material;
|
||||
}
|
||||
// If node is over heightmap y
|
||||
else{
|
||||
// If under water level, it's water
|
||||
@ -1628,11 +1750,21 @@ MapBlock * ServerMap::emergeBlock(
|
||||
bool is_underground = (block_y+1) * MAP_BLOCKSIZE < lowest_ground_y;
|
||||
block->setIsUnderground(is_underground);
|
||||
|
||||
/*
|
||||
Force lighting update if underground.
|
||||
This is needed because of ravines.
|
||||
*/
|
||||
|
||||
if(is_underground)
|
||||
{
|
||||
lighting_invalidated_blocks[block->getPos()] = block;
|
||||
}
|
||||
|
||||
/*
|
||||
Add some minerals
|
||||
*/
|
||||
|
||||
if(is_underground && low_block_is_empty == false)
|
||||
if(is_underground)
|
||||
{
|
||||
s16 underground_level = lowest_ground_y/MAP_BLOCKSIZE - block_y;
|
||||
for(s16 i=0; i<underground_level*3; i++)
|
||||
@ -1640,9 +1772,6 @@ MapBlock * ServerMap::emergeBlock(
|
||||
if(rand()%2 == 0)
|
||||
{
|
||||
v3s16 cp(
|
||||
/*(rand()%(MAP_BLOCKSIZE-4))+2,
|
||||
(rand()%(MAP_BLOCKSIZE-4))+2,
|
||||
(rand()%(MAP_BLOCKSIZE-4))+2*/
|
||||
(rand()%(MAP_BLOCKSIZE-2))+1,
|
||||
(rand()%(MAP_BLOCKSIZE-2))+1,
|
||||
(rand()%(MAP_BLOCKSIZE-2))+1
|
||||
@ -1656,6 +1785,9 @@ MapBlock * ServerMap::emergeBlock(
|
||||
|
||||
for(u16 i=0; i<26; i++)
|
||||
{
|
||||
if(!is_ground_material(block->getNode(cp+g_26dirs[i]).d))
|
||||
continue;
|
||||
|
||||
if(rand()%8 == 0)
|
||||
block->setNode(cp+g_26dirs[i], n);
|
||||
}
|
||||
@ -1666,7 +1798,7 @@ MapBlock * ServerMap::emergeBlock(
|
||||
/*
|
||||
Create a few rats in empty blocks underground
|
||||
*/
|
||||
if(is_underground && low_block_is_empty == true)
|
||||
/*if(is_underground && low_block_is_empty == true)
|
||||
{
|
||||
//for(u16 i=0; i<2; i++)
|
||||
{
|
||||
@ -1674,42 +1806,54 @@ MapBlock * ServerMap::emergeBlock(
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(pos));
|
||||
block->addObject(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: REMOVE
|
||||
DEBUG
|
||||
Add some objects to the block for testing.
|
||||
*/
|
||||
/*if(p == v3s16(0,0,0))
|
||||
{
|
||||
//TestObject *obj = new TestObject(NULL, -1, v3f(BS*8,BS*8,BS*8));
|
||||
Test2Object *obj = new Test2Object(NULL, -1, v3f(BS*8,BS*15,BS*8));
|
||||
block->addObject(obj);
|
||||
}*/
|
||||
|
||||
/*
|
||||
{
|
||||
v3s16 pos(8, 11, 8);
|
||||
SignObject *obj = new SignObject(NULL, -1, intToFloat(pos));
|
||||
obj->setText("Moicka");
|
||||
obj->setYaw(45);
|
||||
block->addObject(obj);
|
||||
}
|
||||
|
||||
{
|
||||
v3s16 pos(8, 11, 8);
|
||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(pos));
|
||||
block->addObject(obj);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
Add block to sector.
|
||||
*/
|
||||
sector->insertBlock(block);
|
||||
|
||||
// An y-wise container if changed blocks
|
||||
/*
|
||||
Do some interpolation for dungeons
|
||||
*/
|
||||
|
||||
#if 0
|
||||
{
|
||||
TimeTaker timer("interpolation", g_device);
|
||||
|
||||
MapVoxelManipulator vmanip(this);
|
||||
|
||||
v3s16 relpos = block->getPosRelative();
|
||||
|
||||
vmanip.interpolate(VoxelArea(relpos-v3s16(1,1,1),
|
||||
relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE+1)));
|
||||
/*vmanip.interpolate(VoxelArea(relpos,
|
||||
relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE-1)));*/
|
||||
|
||||
core::map<v3s16, MapBlock*> modified_blocks;
|
||||
vmanip.blitBack(modified_blocks);
|
||||
dstream<<"blitBack modified "<<modified_blocks.size()
|
||||
<<" blocks"<<std::endl;
|
||||
|
||||
// Add modified blocks to changed_blocks and lighting_invalidated_blocks
|
||||
for(core::map<v3s16, MapBlock*>::Iterator
|
||||
i = modified_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
MapBlock *block = i.getNode()->getValue();
|
||||
|
||||
changed_blocks.insert(block->getPos(), block);
|
||||
//lighting_invalidated_blocks.insert(block->getPos(), block);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Sector object stuff
|
||||
*/
|
||||
|
||||
// An y-wise container of changed blocks
|
||||
core::map<s16, MapBlock*> changed_blocks_sector;
|
||||
|
||||
/*
|
||||
@ -1722,6 +1866,7 @@ MapBlock * ServerMap::emergeBlock(
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
v2s16 p2d(p.X,p.Z);
|
||||
u8 d = i.getNode()->getValue();
|
||||
|
||||
//v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
|
||||
@ -1795,6 +1940,66 @@ MapBlock * ServerMap::emergeBlock(
|
||||
objects_to_remove.push_back(p);
|
||||
}
|
||||
}
|
||||
else if(d == SECTOR_OBJECT_RAVINE)
|
||||
{
|
||||
s16 maxdepth = -20;
|
||||
v3s16 p_min = p + v3s16(-6,maxdepth,-6);
|
||||
v3s16 p_max = p + v3s16(6,6,6);
|
||||
if(sector->isValidArea(p_min, p_max,
|
||||
&changed_blocks_sector))
|
||||
{
|
||||
MapNode n;
|
||||
n.d = MATERIAL_STONE;
|
||||
MapNode n2;
|
||||
n2.d = MATERIAL_AIR;
|
||||
s16 depth = maxdepth + (rand()%10);
|
||||
s16 z = 0;
|
||||
s16 minz = -6 - (-2);
|
||||
s16 maxz = 6 -1;
|
||||
for(s16 x=-6; x<=6; x++)
|
||||
{
|
||||
z += -1 + (rand()%3);
|
||||
if(z < minz)
|
||||
z = minz;
|
||||
if(z > maxz)
|
||||
z = maxz;
|
||||
for(s16 y=depth+(rand()%2); y<=6; y++)
|
||||
{
|
||||
/*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
|
||||
<<std::endl;*/
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z-2);
|
||||
if(is_ground_material(sector->getNode(p2).d))
|
||||
sector->setNode(p2, n);
|
||||
}
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z-1);
|
||||
if(is_ground_material(sector->getNode(p2).d))
|
||||
sector->setNode(p2, n2);
|
||||
}
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z+0);
|
||||
if(is_ground_material(sector->getNode(p2).d))
|
||||
sector->setNode(p2, n2);
|
||||
}
|
||||
{
|
||||
v3s16 p2 = p + v3s16(x,y,z+1);
|
||||
if(is_ground_material(sector->getNode(p2).d))
|
||||
sector->setNode(p2, n);
|
||||
}
|
||||
|
||||
//if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
|
||||
//if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
|
||||
}
|
||||
}
|
||||
|
||||
objects_to_remove.push_back(p);
|
||||
|
||||
// Lighting has to be recalculated for this one.
|
||||
sector->getBlocksInArea(p_min, p_max,
|
||||
lighting_invalidated_blocks);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dstream<<"ServerMap::emergeBlock(): "
|
||||
@ -1807,7 +2012,7 @@ MapBlock * ServerMap::emergeBlock(
|
||||
{
|
||||
dstream<<"WARNING: "<<__FUNCTION_NAME
|
||||
<<": while inserting object "<<(int)d
|
||||
<<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
|
||||
<<" InvalidPositionException.what()="
|
||||
<<e.what()<<std::endl;
|
||||
// This is not too fatal and seems to happen sometimes.
|
||||
|
152
src/map.h
152
src/map.h
@ -26,12 +26,129 @@
|
||||
#include "mapsector.h"
|
||||
#include "constants.h"
|
||||
|
||||
class InvalidFilenameException : public BaseException
|
||||
class Map;
|
||||
|
||||
/*
|
||||
A cache for short-term fast access to map data
|
||||
|
||||
NOTE: This doesn't really make anything more efficient
|
||||
NOTE: Use VoxelManipulator, if possible
|
||||
TODO: Get rid of this?
|
||||
*/
|
||||
class MapBlockPointerCache : public NodeContainer
|
||||
{
|
||||
public:
|
||||
InvalidFilenameException(const char *s):
|
||||
BaseException(s)
|
||||
{}
|
||||
MapBlockPointerCache(Map *map);
|
||||
~MapBlockPointerCache();
|
||||
|
||||
virtual u16 nodeContainerId() const
|
||||
{
|
||||
return NODECONTAINER_ID_MAPBLOCKCACHE;
|
||||
}
|
||||
|
||||
MapBlock * getBlockNoCreate(v3s16 p);
|
||||
|
||||
// virtual from NodeContainer
|
||||
bool isValidPosition(v3s16 p)
|
||||
{
|
||||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
MapBlock *blockref;
|
||||
try{
|
||||
blockref = getBlockNoCreate(blockpos);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// virtual from NodeContainer
|
||||
MapNode getNode(v3s16 p)
|
||||
{
|
||||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
MapBlock * blockref = getBlockNoCreate(blockpos);
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
|
||||
return blockref->getNodeNoCheck(relpos);
|
||||
}
|
||||
|
||||
// virtual from NodeContainer
|
||||
void setNode(v3s16 p, MapNode & n)
|
||||
{
|
||||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
MapBlock * block = getBlockNoCreate(blockpos);
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
block->setNodeNoCheck(relpos, n);
|
||||
m_modified_blocks[blockpos] = block;
|
||||
}
|
||||
|
||||
core::map<v3s16, MapBlock*> m_modified_blocks;
|
||||
|
||||
private:
|
||||
Map *m_map;
|
||||
core::map<v3s16, MapBlock*> m_blocks;
|
||||
|
||||
u32 m_from_cache_count;
|
||||
u32 m_from_map_count;
|
||||
};
|
||||
|
||||
class CacheLock
|
||||
{
|
||||
public:
|
||||
CacheLock()
|
||||
{
|
||||
m_count = 0;
|
||||
m_count_mutex.Init();
|
||||
m_cache_mutex.Init();
|
||||
m_waitcache_mutex.Init();
|
||||
}
|
||||
|
||||
void cacheCreated()
|
||||
{
|
||||
JMutexAutoLock waitcachelock(m_waitcache_mutex);
|
||||
JMutexAutoLock countlock(m_count_mutex);
|
||||
|
||||
// If this is the first cache, grab the cache lock
|
||||
if(m_count == 0)
|
||||
m_cache_mutex.Lock();
|
||||
|
||||
m_count++;
|
||||
}
|
||||
|
||||
void cacheRemoved()
|
||||
{
|
||||
JMutexAutoLock countlock(m_count_mutex);
|
||||
|
||||
assert(m_count > 0);
|
||||
|
||||
m_count--;
|
||||
|
||||
// If this is the last one, release the cache lock
|
||||
if(m_count == 0)
|
||||
m_cache_mutex.Unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
This lock should be taken when removing stuff that can be
|
||||
pointed by the cache.
|
||||
|
||||
You'll want to grab this in a SharedPtr.
|
||||
*/
|
||||
JMutexAutoLock * waitCaches()
|
||||
{
|
||||
JMutexAutoLock waitcachelock(m_waitcache_mutex);
|
||||
return new JMutexAutoLock(m_cache_mutex);
|
||||
}
|
||||
|
||||
private:
|
||||
// Count of existing caches
|
||||
u32 m_count;
|
||||
JMutex m_count_mutex;
|
||||
// This is locked always when there are some caches
|
||||
JMutex m_cache_mutex;
|
||||
// Locked so that when waitCaches() is called, no more caches are created
|
||||
JMutex m_waitcache_mutex;
|
||||
};
|
||||
|
||||
#define MAPTYPE_BASE 0
|
||||
@ -61,6 +178,13 @@ public:
|
||||
|
||||
v3s16 drawoffset; // for drawbox()
|
||||
|
||||
/*
|
||||
Used by MapBlockPointerCache.
|
||||
|
||||
waitCaches() can be called to remove all caches before continuing
|
||||
*/
|
||||
CacheLock m_blockcachelock;
|
||||
|
||||
Map(std::ostream &dout);
|
||||
virtual ~Map();
|
||||
|
||||
@ -154,7 +278,7 @@ public:
|
||||
MapBlock * blockref = getBlockNoCreate(blockpos);
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
|
||||
return blockref->getNode(relpos);
|
||||
return blockref->getNodeNoCheck(relpos);
|
||||
}
|
||||
|
||||
// virtual from NodeContainer
|
||||
@ -163,7 +287,7 @@ public:
|
||||
v3s16 blockpos = getNodeBlockPos(p);
|
||||
MapBlock * blockref = getBlockNoCreate(blockpos);
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
blockref->setNode(relpos, n);
|
||||
blockref->setNodeNoCheck(relpos, n);
|
||||
}
|
||||
|
||||
/*MapNode getNodeGenerate(v3s16 p)
|
||||
@ -247,15 +371,15 @@ struct HMParams
|
||||
{
|
||||
HMParams()
|
||||
{
|
||||
heightmap_blocksize = 64;
|
||||
height_randmax = "constant 70.0";
|
||||
height_randfactor = "constant 0.6";
|
||||
height_base = "linear 0 80 0";
|
||||
blocksize = 64;
|
||||
randmax = "constant 70.0";
|
||||
randfactor = "constant 0.6";
|
||||
base = "linear 0 80 0";
|
||||
}
|
||||
s16 heightmap_blocksize;
|
||||
std::string height_randmax;
|
||||
std::string height_randfactor;
|
||||
std::string height_base;
|
||||
s16 blocksize;
|
||||
std::string randmax;
|
||||
std::string randfactor;
|
||||
std::string base;
|
||||
};
|
||||
|
||||
// Map parameters
|
||||
|
@ -38,7 +38,9 @@ enum
|
||||
{
|
||||
NODECONTAINER_ID_MAPBLOCK,
|
||||
NODECONTAINER_ID_MAPSECTOR,
|
||||
NODECONTAINER_ID_MAP
|
||||
NODECONTAINER_ID_MAP,
|
||||
NODECONTAINER_ID_MAPBLOCKCACHE,
|
||||
NODECONTAINER_ID_VOXELMANIPULATOR,
|
||||
};
|
||||
|
||||
class NodeContainer
|
||||
@ -245,6 +247,35 @@ public:
|
||||
setNode(p.X, p.Y, p.Z, n);
|
||||
}
|
||||
|
||||
/*
|
||||
Non-checking variants of the above
|
||||
*/
|
||||
|
||||
MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
|
||||
{
|
||||
if(data == NULL)
|
||||
throw InvalidPositionException();
|
||||
return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
|
||||
}
|
||||
|
||||
MapNode getNodeNoCheck(v3s16 p)
|
||||
{
|
||||
return getNodeNoCheck(p.X, p.Y, p.Z);
|
||||
}
|
||||
|
||||
void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
|
||||
{
|
||||
if(data == NULL)
|
||||
throw InvalidPositionException();
|
||||
data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
|
||||
setChangedFlag();
|
||||
}
|
||||
|
||||
void setNodeNoCheck(v3s16 p, MapNode & n)
|
||||
{
|
||||
setNodeNoCheck(p.X, p.Y, p.Z, n);
|
||||
}
|
||||
|
||||
/*
|
||||
These functions consult the parent container if the position
|
||||
is not valid on this MapBlock.
|
||||
|
@ -17,10 +17,25 @@
|
||||
|
||||
#define MATERIALS_COUNT 256
|
||||
|
||||
// This is completely ignored. It doesn't create faces with anything.
|
||||
/*
|
||||
Ignored node.
|
||||
|
||||
param is used for custom information in special containers,
|
||||
like VoxelManipulator.
|
||||
|
||||
Anything that stores MapNodes doesn't have to preserve parameters
|
||||
associated with this material.
|
||||
|
||||
Doesn't create faces with anything and is considered being
|
||||
out-of-map in the game map.
|
||||
*/
|
||||
#define MATERIAL_IGNORE 255
|
||||
// This is the common material through which the player can walk
|
||||
// and which is transparent to light
|
||||
#define MATERIAL_IGNORE_DEFAULT_PARAM 0
|
||||
|
||||
/*
|
||||
The common material through which the player can walk and which
|
||||
is transparent to light
|
||||
*/
|
||||
#define MATERIAL_AIR 254
|
||||
|
||||
/*
|
||||
@ -64,6 +79,8 @@ enum Material
|
||||
|
||||
MATERIAL_MESE,
|
||||
|
||||
MATERIAL_MUD,
|
||||
|
||||
// This is set to the number of the actual values in this enum
|
||||
USEFUL_MATERIAL_COUNT
|
||||
};
|
||||
@ -126,6 +143,21 @@ inline u8 face_materials(u8 m1, u8 m2)
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true for materials that form the base ground that
|
||||
follows the main heightmap
|
||||
*/
|
||||
inline bool is_ground_material(u8 m)
|
||||
{
|
||||
return(
|
||||
m == MATERIAL_STONE ||
|
||||
m == MATERIAL_GRASS ||
|
||||
m == MATERIAL_GRASS_FOOTSTEPS ||
|
||||
m == MATERIAL_MESE ||
|
||||
m == MATERIAL_MUD
|
||||
);
|
||||
}
|
||||
|
||||
struct MapNode
|
||||
{
|
||||
//TODO: block type to differ from material
|
||||
@ -133,9 +165,6 @@ struct MapNode
|
||||
// block type
|
||||
u8 d;
|
||||
|
||||
// Removed because light is now stored in param for air
|
||||
// f32 light;
|
||||
|
||||
/*
|
||||
Misc parameter. Initialized to 0.
|
||||
- For light_propagates() blocks, this is light intensity,
|
||||
@ -155,6 +184,11 @@ struct MapNode
|
||||
param = a_param;
|
||||
}
|
||||
|
||||
bool operator==(const MapNode &other)
|
||||
{
|
||||
return (d == other.d && param == other.param);
|
||||
}
|
||||
|
||||
bool light_propagates()
|
||||
{
|
||||
return light_propagates_material(d);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#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
|
||||
|
||||
|
420
src/server.cpp
420
src/server.cpp
@ -178,7 +178,10 @@ void * EmergeThread::Thread()
|
||||
modified_blocks.insert(block->getPos(), block);
|
||||
}
|
||||
|
||||
//TimeTaker timer("** updateLighting", g_device);
|
||||
/*dstream<<"lighting "<<lighting_invalidated_blocks.size()
|
||||
<<" blocks"<<std::endl;
|
||||
TimeTaker timer("** updateLighting", g_device);*/
|
||||
|
||||
// Update lighting without locking the environment mutex,
|
||||
// add modified blocks to changed blocks
|
||||
map.updateLighting(lighting_invalidated_blocks, modified_blocks);
|
||||
@ -222,11 +225,11 @@ void * EmergeThread::Thread()
|
||||
client->SetBlocksNotSent(modified_blocks);
|
||||
}
|
||||
|
||||
if(q->peer_ids.find(client->peer_id) != NULL)
|
||||
/*if(q->peer_ids.find(client->peer_id) != NULL)
|
||||
{
|
||||
// Decrement emerge queue count of client
|
||||
client->BlockEmerged();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
@ -246,282 +249,6 @@ void * EmergeThread::Thread()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void RemoteClient::SendBlocks(Server *server, float dtime)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
/*
|
||||
Find what blocks to send to the client next, and send them.
|
||||
|
||||
Throttling is based on limiting the amount of blocks "flying"
|
||||
at a given time.
|
||||
*/
|
||||
|
||||
// Can't send anything without knowing version
|
||||
if(serialization_version == SER_FMT_VER_INVALID)
|
||||
{
|
||||
dstream<<"RemoteClient::SendBlocks(): Not sending, no version."
|
||||
<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
|
||||
if(m_blocks_sending.size() >= MAX_SIMULTANEOUS_BLOCK_SENDS)
|
||||
{
|
||||
//dstream<<"Not sending any blocks, Queue full."<<std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Player *player = server->m_env.getPlayer(peer_id);
|
||||
|
||||
v3f playerpos = player->getPosition();
|
||||
v3f playerspeed = player->getSpeed();
|
||||
|
||||
v3s16 center_nodepos = floatToInt(playerpos);
|
||||
|
||||
v3s16 center = getNodeBlockPos(center_nodepos);
|
||||
|
||||
/*
|
||||
Get the starting value of the block finder radius.
|
||||
*/
|
||||
s16 last_nearest_unsent_d;
|
||||
s16 d_start;
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
|
||||
if(m_last_center != center)
|
||||
{
|
||||
m_nearest_unsent_d = 0;
|
||||
m_last_center = center;
|
||||
}
|
||||
|
||||
static float reset_counter = 0;
|
||||
reset_counter += dtime;
|
||||
if(reset_counter > 5.0)
|
||||
{
|
||||
reset_counter = 0;
|
||||
m_nearest_unsent_d = 0;
|
||||
}
|
||||
|
||||
last_nearest_unsent_d = m_nearest_unsent_d;
|
||||
|
||||
d_start = m_nearest_unsent_d;
|
||||
}
|
||||
|
||||
u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS;
|
||||
|
||||
{
|
||||
SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
|
||||
m_time_from_building.m_value += dtime;
|
||||
/*
|
||||
Check the time from last addNode/removeNode.
|
||||
Decrease send rate if player is building stuff.
|
||||
*/
|
||||
if(m_time_from_building.m_value
|
||||
< FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
|
||||
{
|
||||
maximum_simultaneous_block_sends
|
||||
= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
|
||||
}
|
||||
}
|
||||
|
||||
// Serialization version used
|
||||
//u8 ser_version = serialization_version;
|
||||
|
||||
//bool has_incomplete_blocks = false;
|
||||
|
||||
/*
|
||||
TODO: Get this from somewhere
|
||||
*/
|
||||
//s16 d_max = 7;
|
||||
s16 d_max = 8;
|
||||
|
||||
//TODO: Get this from somewhere (probably a bigger value)
|
||||
s16 d_max_gen = 5;
|
||||
|
||||
//dstream<<"Starting from "<<d_start<<std::endl;
|
||||
|
||||
for(s16 d = d_start; d <= d_max; d++)
|
||||
{
|
||||
//dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
|
||||
|
||||
//if(has_incomplete_blocks == false)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
/*
|
||||
If m_nearest_unsent_d was changed by the EmergeThread
|
||||
(it can change it to 0 through SetBlockNotSent),
|
||||
update our d to it.
|
||||
Else update m_nearest_unsent_d
|
||||
*/
|
||||
if(m_nearest_unsent_d != last_nearest_unsent_d)
|
||||
{
|
||||
d = m_nearest_unsent_d;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nearest_unsent_d = d;
|
||||
}
|
||||
last_nearest_unsent_d = m_nearest_unsent_d;
|
||||
}
|
||||
|
||||
/*
|
||||
Get the border/face dot coordinates of a "d-radiused"
|
||||
box
|
||||
*/
|
||||
core::list<v3s16> list;
|
||||
getFacePositions(list, d);
|
||||
|
||||
core::list<v3s16>::Iterator li;
|
||||
for(li=list.begin(); li!=list.end(); li++)
|
||||
{
|
||||
v3s16 p = *li + center;
|
||||
|
||||
/*
|
||||
Send throttling
|
||||
- Don't allow too many simultaneous transfers
|
||||
|
||||
Also, don't send blocks that are already flying.
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
|
||||
if(m_blocks_sending.size()
|
||||
>= maximum_simultaneous_block_sends)
|
||||
{
|
||||
/*dstream<<"Not sending more blocks. Queue full. "
|
||||
<<m_blocks_sending.size()
|
||||
<<std::endl;*/
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_blocks_sending.find(p) != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Do not go over-limit
|
||||
*/
|
||||
if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
|
||||
|| p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
|
||||
continue;
|
||||
|
||||
bool generate = d <= d_max_gen;
|
||||
|
||||
// Limit the generating area vertically to half
|
||||
if(abs(p.Y - center.Y) > d_max_gen / 2)
|
||||
generate = false;
|
||||
|
||||
/*
|
||||
Don't send already sent blocks
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sent_mutex);
|
||||
|
||||
if(m_blocks_sent.find(p) != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if map has this block
|
||||
*/
|
||||
MapBlock *block = NULL;
|
||||
try
|
||||
{
|
||||
block = server->m_env.getMap().getBlockNoCreate(p);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
|
||||
bool surely_not_found_on_disk = false;
|
||||
if(block != NULL)
|
||||
{
|
||||
/*if(block->isIncomplete())
|
||||
{
|
||||
has_incomplete_blocks = true;
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if(block->isDummy())
|
||||
{
|
||||
surely_not_found_on_disk = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If block has been marked to not exist on disk (dummy)
|
||||
and generating new ones is not wanted, skip block. TODO
|
||||
*/
|
||||
if(generate == false && surely_not_found_on_disk == true)
|
||||
{
|
||||
// get next one.
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Add inexistent block to emerge queue.
|
||||
*/
|
||||
if(block == NULL || surely_not_found_on_disk)
|
||||
{
|
||||
// Block not found.
|
||||
SharedPtr<JMutexAutoLock> lock
|
||||
(m_num_blocks_in_emerge_queue.getLock());
|
||||
|
||||
//TODO: Get value from somewhere
|
||||
//TODO: Balance between clients
|
||||
//if(server->m_emerge_queue.size() < 1)
|
||||
|
||||
// Allow only one block in emerge queue
|
||||
if(m_num_blocks_in_emerge_queue.m_value == 0)
|
||||
{
|
||||
// Add it to the emerge queue and trigger the thread
|
||||
|
||||
u8 flags = 0;
|
||||
if(generate == false)
|
||||
flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
|
||||
|
||||
{
|
||||
m_num_blocks_in_emerge_queue.m_value++;
|
||||
}
|
||||
|
||||
server->m_emerge_queue.addBlock(peer_id, p, flags);
|
||||
server->m_emergethread.trigger();
|
||||
}
|
||||
|
||||
// get next one.
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Send block
|
||||
*/
|
||||
|
||||
/*dstream<<"RemoteClient::SendBlocks(): d="<<d<<", p="
|
||||
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<" sending queue size: "<<m_blocks_sending.size()<<std::endl;*/
|
||||
|
||||
server->SendBlockNoLock(peer_id, block, serialization_version);
|
||||
|
||||
/*
|
||||
Add to history
|
||||
*/
|
||||
SentBlock(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add anything here. The loop breaks by returning.
|
||||
}
|
||||
#endif // backup of SendBlocks
|
||||
|
||||
void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
core::array<PrioritySortedBlockTransfer> &dest)
|
||||
{
|
||||
@ -531,7 +258,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
|
||||
if(m_blocks_sending.size() >= MAX_SIMULTANEOUS_BLOCK_SENDS)
|
||||
if(m_blocks_sending.size() >= g_settings.getU16
|
||||
("max_simultaneous_block_sends_per_client"))
|
||||
{
|
||||
//dstream<<"Not sending any blocks, Queue full."<<std::endl;
|
||||
return;
|
||||
@ -574,15 +302,17 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
d_start = m_nearest_unsent_d;
|
||||
}
|
||||
|
||||
u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS;
|
||||
u16 maximum_simultaneous_block_sends = g_settings.getU16
|
||||
("max_simultaneous_block_sends_per_client");
|
||||
|
||||
/*
|
||||
Check the time from last addNode/removeNode.
|
||||
|
||||
Decrease send rate if player is building stuff.
|
||||
*/
|
||||
{
|
||||
SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
|
||||
m_time_from_building.m_value += dtime;
|
||||
/*
|
||||
Check the time from last addNode/removeNode.
|
||||
Decrease send rate if player is building stuff.
|
||||
*/
|
||||
if(m_time_from_building.m_value
|
||||
< FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
|
||||
{
|
||||
@ -646,9 +376,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
/*
|
||||
Send throttling
|
||||
- Don't allow too many simultaneous transfers
|
||||
- EXCEPT when the blocks are very close
|
||||
|
||||
Also, don't send blocks that are already flying.
|
||||
*/
|
||||
if(d >= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
|
||||
{
|
||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
||||
|
||||
@ -722,7 +454,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
|
||||
/*
|
||||
If block has been marked to not exist on disk (dummy)
|
||||
and generating new ones is not wanted, skip block. TODO
|
||||
and generating new ones is not wanted, skip block.
|
||||
*/
|
||||
if(generate == false && surely_not_found_on_disk == true)
|
||||
{
|
||||
@ -735,16 +467,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
*/
|
||||
if(block == NULL || surely_not_found_on_disk)
|
||||
{
|
||||
// Block not found.
|
||||
SharedPtr<JMutexAutoLock> lock
|
||||
(m_num_blocks_in_emerge_queue.getLock());
|
||||
/*SharedPtr<JMutexAutoLock> lock
|
||||
(m_num_blocks_in_emerge_queue.getLock());*/
|
||||
|
||||
//TODO: Get value from somewhere
|
||||
//TODO: Balance between clients
|
||||
//if(server->m_emerge_queue.size() < 1)
|
||||
|
||||
// Allow only one block in emerge queue
|
||||
if(m_num_blocks_in_emerge_queue.m_value == 0)
|
||||
if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
|
||||
{
|
||||
// Add it to the emerge queue and trigger the thread
|
||||
|
||||
@ -752,10 +480,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||
if(generate == false)
|
||||
flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
|
||||
|
||||
{
|
||||
m_num_blocks_in_emerge_queue.m_value++;
|
||||
}
|
||||
|
||||
server->m_emerge_queue.addBlock(peer_id, p, flags);
|
||||
server->m_emergethread.trigger();
|
||||
}
|
||||
@ -880,7 +604,7 @@ void RemoteClient::SendObjectData(
|
||||
v3s16 center = getNodeBlockPos(center_nodepos);
|
||||
|
||||
//s16 d_max = ACTIVE_OBJECT_D_BLOCKS;
|
||||
s16 d_max = server->m_active_object_range;
|
||||
s16 d_max = g_settings.getS16("active_object_range");
|
||||
|
||||
// Number of blocks whose objects were written to bos
|
||||
u16 blockcount = 0;
|
||||
@ -956,9 +680,9 @@ void RemoteClient::SendObjectData(
|
||||
// Fetch the block only if it is on disk.
|
||||
|
||||
// Grab and increment counter
|
||||
SharedPtr<JMutexAutoLock> lock
|
||||
/*SharedPtr<JMutexAutoLock> lock
|
||||
(m_num_blocks_in_emerge_queue.getLock());
|
||||
m_num_blocks_in_emerge_queue.m_value++;
|
||||
m_num_blocks_in_emerge_queue.m_value++;*/
|
||||
|
||||
// Add to queue as an anonymous fetch from disk
|
||||
u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL;
|
||||
@ -1072,12 +796,12 @@ void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::BlockEmerged()
|
||||
/*void RemoteClient::BlockEmerged()
|
||||
{
|
||||
SharedPtr<JMutexAutoLock> lock(m_num_blocks_in_emerge_queue.getLock());
|
||||
assert(m_num_blocks_in_emerge_queue.m_value > 0);
|
||||
m_num_blocks_in_emerge_queue.m_value--;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
|
||||
{
|
||||
@ -1145,19 +869,13 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
||||
|
||||
Server::Server(
|
||||
std::string mapsavedir,
|
||||
bool creative_mode,
|
||||
HMParams hm_params,
|
||||
MapParams map_params,
|
||||
float objectdata_interval,
|
||||
u16 active_object_range
|
||||
MapParams map_params
|
||||
):
|
||||
m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server),
|
||||
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
|
||||
m_thread(this),
|
||||
m_emergethread(this),
|
||||
m_creative_mode(creative_mode),
|
||||
m_objectdata_interval(objectdata_interval),
|
||||
m_active_object_range(active_object_range)
|
||||
m_emergethread(this)
|
||||
{
|
||||
m_env_mutex.Init();
|
||||
m_con_mutex.Init();
|
||||
@ -1196,7 +914,7 @@ void Server::start(unsigned short port)
|
||||
m_thread.stop();
|
||||
|
||||
// Initialize connection
|
||||
m_con.setTimeoutMs(50);
|
||||
m_con.setTimeoutMs(30);
|
||||
m_con.Serve(port);
|
||||
|
||||
// Start thread
|
||||
@ -1287,7 +1005,7 @@ void Server::AsyncRunStep()
|
||||
|
||||
// Run time- and client- related stuff
|
||||
// NOTE: If you intend to add something here, check that it
|
||||
// doesn't fit in RemoteClient::SendBlocks for example.
|
||||
// doesn't fit in RemoteClient::GetNextBlocks for example.
|
||||
/*{
|
||||
// Clients are behind connection lock
|
||||
JMutexAutoLock lock(m_con_mutex);
|
||||
@ -1309,7 +1027,7 @@ void Server::AsyncRunStep()
|
||||
{
|
||||
static float counter = 0.0;
|
||||
counter += dtime;
|
||||
if(counter >= m_objectdata_interval)
|
||||
if(counter >= g_settings.getFloat("objectdata_interval"))
|
||||
{
|
||||
JMutexAutoLock lock1(m_env_mutex);
|
||||
JMutexAutoLock lock2(m_con_mutex);
|
||||
@ -1319,8 +1037,21 @@ void Server::AsyncRunStep()
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger emergethread (it gets somehow gets to a
|
||||
// non-triggered but bysy state sometimes)
|
||||
{
|
||||
static float counter = 0.0;
|
||||
counter += dtime;
|
||||
if(counter >= 2.0)
|
||||
{
|
||||
counter = 0.0;
|
||||
|
||||
m_emergethread.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
// Save map
|
||||
{
|
||||
static float counter = 0.0;
|
||||
counter += dtime;
|
||||
if(counter >= SERVER_MAP_SAVE_INTERVAL)
|
||||
@ -1619,7 +1350,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Left click
|
||||
if(button == 0)
|
||||
{
|
||||
if(m_creative_mode == false)
|
||||
if(g_settings.getBool("creative_mode") == false)
|
||||
{
|
||||
|
||||
// Skip if inventory has no free space
|
||||
@ -1684,8 +1415,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Otherwise remove it
|
||||
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
@ -1707,7 +1436,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Send as reliable
|
||||
m_con.SendToAll(0, reply, true);
|
||||
|
||||
if(m_creative_mode == false)
|
||||
if(g_settings.getBool("creative_mode") == false)
|
||||
{
|
||||
// Add to inventory and send inventory
|
||||
InventoryItem *item = new MaterialItem(material, 1);
|
||||
@ -1715,6 +1444,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
SendInventory(player->peer_id);
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the node
|
||||
(this takes some time so it is done after the quick stuff)
|
||||
*/
|
||||
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
||||
|
||||
} // button == 0
|
||||
/*
|
||||
Right button places blocks and stuff
|
||||
@ -1744,9 +1479,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
MapNode n2 = m_env.getMap().getNode(p_over);
|
||||
if(n2.d != MATERIAL_AIR)
|
||||
return;
|
||||
|
||||
core::map<v3s16, MapBlock*> modified_blocks;
|
||||
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
@ -1758,7 +1490,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Reset build time counter
|
||||
getClient(peer->id)->m_time_from_building.set(0.0);
|
||||
|
||||
if(m_creative_mode == false)
|
||||
if(g_settings.getBool("creative_mode") == false)
|
||||
{
|
||||
// Remove from inventory and send inventory
|
||||
if(mitem->getCount() == 1)
|
||||
@ -1779,6 +1511,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
n.serialize(&reply[8], peer_ser_ver);
|
||||
// Send as reliable
|
||||
m_con.SendToAll(0, reply, true);
|
||||
|
||||
/*
|
||||
Add node.
|
||||
|
||||
This takes some time so it is done after the quick stuff
|
||||
*/
|
||||
core::map<v3s16, MapBlock*> modified_blocks;
|
||||
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
|
||||
}
|
||||
/*
|
||||
Handle block object items
|
||||
@ -1828,7 +1568,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
|
||||
//dout_server<<"Placed object"<<std::endl;
|
||||
|
||||
if(m_creative_mode == false)
|
||||
if(g_settings.getBool("creative_mode") == false)
|
||||
{
|
||||
// Remove from inventory and send inventory
|
||||
player->inventory.deleteItem(item_i);
|
||||
@ -2168,7 +1908,7 @@ void Server::peerAdded(con::Peer *peer)
|
||||
Add stuff to inventory
|
||||
*/
|
||||
|
||||
if(m_creative_mode)
|
||||
if(g_settings.getBool("creative_mode"))
|
||||
{
|
||||
// Give all materials
|
||||
assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
|
||||
@ -2327,35 +2067,6 @@ void Server::SendInventory(u16 peer_id)
|
||||
m_con.Send(peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void Server::SendBlocks(float dtime)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
//dstream<<"Server::SendBlocks(): BEGIN"<<std::endl;
|
||||
|
||||
JMutexAutoLock envlock(m_env_mutex);
|
||||
JMutexAutoLock conlock(m_con_mutex);
|
||||
|
||||
for(core::map<u16, RemoteClient*>::Iterator
|
||||
i = m_clients.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
RemoteClient *client = i.getNode()->getValue();
|
||||
assert(client->peer_id == i.getNode()->getKey());
|
||||
|
||||
if(client->serialization_version == SER_FMT_VER_INVALID)
|
||||
continue;
|
||||
|
||||
//dstream<<"Server::SendBlocks(): sending blocks for client "<<client->peer_id<<std::endl;
|
||||
|
||||
//u16 peer_id = client->peer_id;
|
||||
client->SendBlocks(this, dtime);
|
||||
}
|
||||
|
||||
//dstream<<"Server::SendBlocks(): END"<<std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Server::SendBlocks(float dtime)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
@ -2390,8 +2101,9 @@ void Server::SendBlocks(float dtime)
|
||||
|
||||
for(u32 i=0; i<queue.size(); i++)
|
||||
{
|
||||
//TODO: Calculate value dynamically
|
||||
if(total_sending >= MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL)
|
||||
//TODO: Calculate limit dynamically
|
||||
if(total_sending >= g_settings.getS32
|
||||
("max_simultaneous_block_sends_server_total"))
|
||||
break;
|
||||
|
||||
PrioritySortedBlockTransfer q = queue[i];
|
||||
|
44
src/server.h
44
src/server.h
@ -103,6 +103,23 @@ public:
|
||||
return m_queue.size();
|
||||
}
|
||||
|
||||
u32 peerItemCount(u16 peer_id)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
u32 count = 0;
|
||||
|
||||
core::list<QueuedBlockEmerge*>::Iterator i;
|
||||
for(i=m_queue.begin(); i!=m_queue.end(); i++)
|
||||
{
|
||||
QueuedBlockEmerge *q = *i;
|
||||
if(q->peer_ids.find(peer_id) != NULL)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
core::list<QueuedBlockEmerge*> m_queue;
|
||||
JMutex m_mutex;
|
||||
@ -237,8 +254,8 @@ public:
|
||||
u8 pending_serialization_version;
|
||||
|
||||
RemoteClient():
|
||||
m_time_from_building(0.0),
|
||||
m_num_blocks_in_emerge_queue(0)
|
||||
m_time_from_building(0.0)
|
||||
//m_num_blocks_in_emerge_queue(0)
|
||||
{
|
||||
peer_id = 0;
|
||||
serialization_version = SER_FMT_VER_INVALID;
|
||||
@ -276,7 +293,7 @@ public:
|
||||
void SetBlockNotSent(v3s16 p);
|
||||
void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
|
||||
|
||||
void BlockEmerged();
|
||||
//void BlockEmerged();
|
||||
|
||||
/*bool IsSendingBlock(v3s16 p)
|
||||
{
|
||||
@ -300,8 +317,8 @@ public:
|
||||
JMutexAutoLock l2(m_blocks_sent_mutex);
|
||||
JMutexAutoLock l3(m_blocks_sending_mutex);
|
||||
o<<"RemoteClient "<<peer_id<<": "
|
||||
<<"m_num_blocks_in_emerge_queue="
|
||||
<<m_num_blocks_in_emerge_queue.get()
|
||||
/*<<"m_num_blocks_in_emerge_queue="
|
||||
<<m_num_blocks_in_emerge_queue.get()*/
|
||||
<<", m_blocks_sent.size()="<<m_blocks_sent.size()
|
||||
<<", m_blocks_sending.size()="<<m_blocks_sending.size()
|
||||
<<", m_nearest_unsent_d="<<m_nearest_unsent_d
|
||||
@ -321,10 +338,11 @@ private:
|
||||
*/
|
||||
|
||||
//TODO: core::map<v3s16, MapBlock*> m_active_blocks
|
||||
//NOTE: Not here, it should be server-wide!
|
||||
|
||||
// Number of blocks in the emerge queue that have this client as
|
||||
// a receiver. Used for throttling network usage.
|
||||
MutexedVariable<s16> m_num_blocks_in_emerge_queue;
|
||||
//MutexedVariable<s16> m_num_blocks_in_emerge_queue;
|
||||
|
||||
/*
|
||||
Blocks that have been sent to client.
|
||||
@ -368,16 +386,16 @@ public:
|
||||
*/
|
||||
Server(
|
||||
std::string mapsavedir,
|
||||
bool creative_mode,
|
||||
HMParams hm_params,
|
||||
MapParams map_params,
|
||||
float objectdata_inverval,
|
||||
u16 active_object_range
|
||||
MapParams map_params
|
||||
);
|
||||
~Server();
|
||||
void start(unsigned short port);
|
||||
void stop();
|
||||
// This is mainly a way to pass the time to the server.
|
||||
// Actual processing is done in an another thread.
|
||||
void step(float dtime);
|
||||
// This is run by ServerThread and does the actual processing
|
||||
void AsyncRunStep();
|
||||
void Receive();
|
||||
void ProcessData(u8 *data, u32 datasize, u16 peer_id);
|
||||
@ -387,7 +405,6 @@ public:
|
||||
|
||||
// Environment and Connection must be locked when called
|
||||
void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
|
||||
//void SendBlock(u16 peer_id, MapBlock *block, u8 ver);
|
||||
//TODO: Sending of many blocks in a single packet
|
||||
|
||||
// Environment and Connection must be locked when called
|
||||
@ -431,11 +448,6 @@ private:
|
||||
|
||||
BlockEmergeQueue m_emerge_queue;
|
||||
|
||||
// Settings
|
||||
bool m_creative_mode;
|
||||
float m_objectdata_interval;
|
||||
u16 m_active_object_range;
|
||||
|
||||
friend class EmergeThread;
|
||||
friend class RemoteClient;
|
||||
};
|
||||
|
@ -164,7 +164,9 @@ void UDPSocket::Bind(unsigned short port)
|
||||
|
||||
if(bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
|
||||
{
|
||||
#ifndef DISABLE_ERRNO
|
||||
dstream<<(int)m_handle<<": Bind failed: "<<strerror(errno)<<std::endl;
|
||||
#endif
|
||||
throw SocketException("Failed to bind socket");
|
||||
}
|
||||
}
|
||||
@ -291,7 +293,9 @@ bool UDPSocket::WaitData(int timeout_ms)
|
||||
}
|
||||
else if(result < 0){
|
||||
// Error
|
||||
#ifndef DISABLE_ERRNO
|
||||
dstream<<(int)m_handle<<": Select failed: "<<strerror(errno)<<std::endl;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
dstream<<(int)m_handle<<": WSAGetLastError()="<<WSAGetLastError()<<std::endl;
|
||||
#endif
|
||||
|
42
src/test.cpp
42
src/test.cpp
@ -1,6 +1,5 @@
|
||||
#include "test.h"
|
||||
#include "common_irrlicht.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "map.h"
|
||||
#include "player.h"
|
||||
@ -10,6 +9,7 @@
|
||||
#include "connection.h"
|
||||
#include "utility.h"
|
||||
#include "serialization.h"
|
||||
#include "voxel.h"
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -125,6 +125,45 @@ struct TestMapNode
|
||||
}
|
||||
};
|
||||
|
||||
struct TestVoxelManipulator
|
||||
{
|
||||
void Run()
|
||||
{
|
||||
VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1));
|
||||
assert(a.index(0,0,0) == 1*3*3 + 1*3 + 1);
|
||||
assert(a.index(-1,-1,-1) == 0);
|
||||
|
||||
VoxelManipulator v;
|
||||
|
||||
v.print(dstream);
|
||||
|
||||
dstream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl;
|
||||
|
||||
//v[v3s16(-1,0,-1)] = MapNode(2);
|
||||
v[v3s16(-1,0,-1)].d = 2;
|
||||
|
||||
v.print(dstream);
|
||||
|
||||
assert(v[v3s16(-1,0,-1)].d == 2);
|
||||
|
||||
dstream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
|
||||
|
||||
assert(v[v3s16(0,0,-1)].d == MATERIAL_IGNORE);
|
||||
|
||||
v.print(dstream);
|
||||
|
||||
dstream<<"*** Adding area ***"<<std::endl;
|
||||
|
||||
v.addArea(a);
|
||||
|
||||
v.print(dstream);
|
||||
|
||||
assert(v[v3s16(-1,0,-1)].d == 2);
|
||||
assert(v[v3s16(0,1,1)].d == MATERIAL_IGNORE);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct TestMapBlock
|
||||
{
|
||||
class TC : public NodeContainer
|
||||
@ -906,6 +945,7 @@ void run_tests()
|
||||
TEST(TestUtilities);
|
||||
TEST(TestCompress);
|
||||
TEST(TestMapNode);
|
||||
TEST(TestVoxelManipulator);
|
||||
TEST(TestMapBlock);
|
||||
TEST(TestMapSector);
|
||||
TEST(TestHeightmap);
|
||||
|
155
src/utility.h
155
src/utility.h
@ -8,8 +8,11 @@
|
||||
#include "common_irrlicht.h"
|
||||
#include "debug.h"
|
||||
#include "strfnd.h"
|
||||
#include "exceptions.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
extern const v3s16 g_26dirs[26];
|
||||
|
||||
@ -613,5 +616,157 @@ inline s32 stoi(std::string s, s32 min, s32 max)
|
||||
return i;
|
||||
}
|
||||
|
||||
inline s32 stoi(std::string s)
|
||||
{
|
||||
return atoi(s.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
Config stuff
|
||||
*/
|
||||
|
||||
class Settings
|
||||
{
|
||||
public:
|
||||
|
||||
// Returns false on EOF
|
||||
bool parseConfigObject(std::istream &is)
|
||||
{
|
||||
if(is.eof())
|
||||
return false;
|
||||
|
||||
// NOTE: This function will be expanded to allow multi-line settings
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
//dstream<<"got line: \""<<line<<"\""<<std::endl;
|
||||
|
||||
std::string trimmedline = trim(line);
|
||||
|
||||
// Ignore comments
|
||||
if(trimmedline[0] == '#')
|
||||
return true;
|
||||
|
||||
//dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
|
||||
|
||||
Strfnd sf(trim(line));
|
||||
|
||||
std::string name = sf.next("=");
|
||||
name = trim(name);
|
||||
|
||||
if(name == "")
|
||||
return true;
|
||||
|
||||
std::string value = sf.next("\n");
|
||||
value = trim(value);
|
||||
|
||||
dstream<<"Config name=\""<<name<<"\" value=\""
|
||||
<<value<<"\""<<std::endl;
|
||||
|
||||
m_settings[name] = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true on success
|
||||
bool readConfigFile(const char *filename)
|
||||
{
|
||||
std::ifstream is(filename);
|
||||
if(is.good() == false)
|
||||
{
|
||||
dstream<<"Error opening configuration file: "
|
||||
<<filename<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
dstream<<"Parsing configuration file: "
|
||||
<<filename<<std::endl;
|
||||
|
||||
while(parseConfigObject(is));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void set(std::string name, std::string value)
|
||||
{
|
||||
m_settings[name] = value;
|
||||
}
|
||||
|
||||
std::string get(std::string name)
|
||||
{
|
||||
core::map<std::string, std::string>::Node *n;
|
||||
n = m_settings.find(name);
|
||||
if(n == NULL)
|
||||
throw SettingNotFoundException("Setting not found");
|
||||
|
||||
return n->getValue();
|
||||
}
|
||||
|
||||
bool getBool(std::string name)
|
||||
{
|
||||
return is_yes(get(name));
|
||||
}
|
||||
|
||||
// Asks if empty
|
||||
bool getBoolAsk(std::string name, std::string question, bool def)
|
||||
{
|
||||
std::string s = get(name);
|
||||
if(s != "")
|
||||
return is_yes(s);
|
||||
|
||||
char templine[10];
|
||||
std::cout<<question<<" [y/N]: ";
|
||||
std::cin.getline(templine, 10);
|
||||
s = templine;
|
||||
|
||||
if(s == "")
|
||||
return def;
|
||||
|
||||
return is_yes(s);
|
||||
}
|
||||
|
||||
float getFloat(std::string name)
|
||||
{
|
||||
float f;
|
||||
std::istringstream vis(get(name));
|
||||
vis>>f;
|
||||
return f;
|
||||
}
|
||||
|
||||
u16 getU16(std::string name)
|
||||
{
|
||||
return stoi(get(name), 0, 65535);
|
||||
}
|
||||
|
||||
u16 getU16Ask(std::string name, std::string question, u16 def)
|
||||
{
|
||||
std::string s = get(name);
|
||||
if(s != "")
|
||||
return stoi(s, 0, 65535);
|
||||
|
||||
char templine[10];
|
||||
std::cout<<question<<" ["<<def<<"]: ";
|
||||
std::cin.getline(templine, 10);
|
||||
s = templine;
|
||||
|
||||
if(s == "")
|
||||
return def;
|
||||
|
||||
return stoi(s, 0, 65535);
|
||||
}
|
||||
|
||||
s16 getS16(std::string name)
|
||||
{
|
||||
return stoi(get(name), -32768, 32767);
|
||||
}
|
||||
|
||||
s32 getS32(std::string name)
|
||||
{
|
||||
return stoi(get(name));
|
||||
}
|
||||
|
||||
private:
|
||||
core::map<std::string, std::string> m_settings;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user