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
|
# 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
|
# and be sure that CXX is set to a valid compiler
|
||||||
TARGET = test
|
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))
|
SOURCES = $(addprefix src/, $(SOURCE_FILES))
|
||||||
OBJECTS = $(SOURCES:.cpp=.o)
|
OBJECTS = $(SOURCES:.cpp=.o)
|
||||||
FASTTARGET = fasttest
|
FASTTARGET = fasttest
|
||||||
@ -13,7 +13,7 @@ JTHREADPATH = ../jthread/jthread-1.2.1
|
|||||||
CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src
|
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 -fomit-frame-pointer -pipe
|
||||||
CXXFLAGS = -O2 -ffast-math -Wall -g
|
CXXFLAGS = -O2 -ffast-math -Wall -g -pipe
|
||||||
#CXXFLAGS = -O1 -ffast-math -Wall -g
|
#CXXFLAGS = -O1 -ffast-math -Wall -g
|
||||||
#CXXFLAGS = -Wall -g -O0
|
#CXXFLAGS = -Wall -g -O0
|
||||||
|
|
||||||
@ -21,8 +21,8 @@ CXXFLAGS = -O2 -ffast-math -Wall -g
|
|||||||
#CXXFLAGS = -O3 -ffast-math -Wall -g
|
#CXXFLAGS = -O3 -ffast-math -Wall -g
|
||||||
#CXXFLAGS = -O2 -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
|
#Default target
|
||||||
|
|
||||||
@ -53,7 +53,9 @@ all_linux all_win32: $(DESTPATH)
|
|||||||
fast_linux: $(FASTDESTPATH)
|
fast_linux: $(FASTDESTPATH)
|
||||||
|
|
||||||
$(FASTDESTPATH): $(SOURCES)
|
$(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)
|
$(DESTPATH): $(OBJECTS)
|
||||||
$(CXX) -o $@ $(OBJECTS) $(LDFLAGS)
|
$(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.png $PACKAGEPATH/data/
|
||||||
cp -r data/sign_back.png $PACKAGEPATH/data/
|
cp -r data/sign_back.png $PACKAGEPATH/data/
|
||||||
cp -r data/rat.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
|
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
|
# Player and object positions are sent at intervals specified by this
|
||||||
objectdata_inverval = 0.2
|
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();
|
bool was = m_client->AsyncProcessData();
|
||||||
|
|
||||||
if(was == false)
|
if(was == false)
|
||||||
sleep_ms(50);
|
sleep_ms(10);
|
||||||
}
|
}
|
||||||
#if CATCH_UNHANDLED_EXCEPTIONS
|
#if CATCH_UNHANDLED_EXCEPTIONS
|
||||||
}
|
}
|
||||||
@ -159,13 +159,17 @@ void Client::step(float dtime)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Delete unused sectors
|
Delete unused sectors
|
||||||
|
|
||||||
|
NOTE: This jams the game for a while because deleting sectors
|
||||||
|
clear caches
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static float counter = -0.001;
|
static float counter = -0.001;
|
||||||
counter -= dtime;
|
counter -= dtime;
|
||||||
if(counter <= 0.0)
|
if(counter <= 0.0)
|
||||||
{
|
{
|
||||||
counter = 10.0;
|
// 3 minute interval
|
||||||
|
counter = 180.0;
|
||||||
|
|
||||||
JMutexAutoLock lock(m_env_mutex);
|
JMutexAutoLock lock(m_env_mutex);
|
||||||
|
|
||||||
@ -381,6 +385,8 @@ float Client::asyncStep()
|
|||||||
/*float dtime;
|
/*float dtime;
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock1(m_step_dtime_mutex);
|
JMutexAutoLock lock1(m_step_dtime_mutex);
|
||||||
|
if(m_step_dtime < 0.001)
|
||||||
|
return 0.0;
|
||||||
dtime = m_step_dtime;
|
dtime = m_step_dtime;
|
||||||
m_step_dtime = 0.0;
|
m_step_dtime = 0.0;
|
||||||
}
|
}
|
||||||
@ -1207,6 +1213,18 @@ bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater)
|
|||||||
|
|
||||||
bool Client::AsyncProcessData()
|
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);
|
LazyMeshUpdater mesh_updater(&m_env);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@ -1214,7 +1232,7 @@ bool Client::AsyncProcessData()
|
|||||||
if(r == false)
|
if(r == false)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
|
void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
|
||||||
|
@ -28,19 +28,20 @@
|
|||||||
// The absolute working limit is (2^15 - viewing_range).
|
// The absolute working limit is (2^15 - viewing_range).
|
||||||
#define MAP_GENERATION_LIMIT (31000)
|
#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 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
|
// Viewing range stuff
|
||||||
|
|
||||||
#define FPS_DEFAULT_WANTED 30
|
//#define HEIGHTMAP_RANGE_NODES 300
|
||||||
#define FPS_DEFAULT_MAX 60
|
|
||||||
|
|
||||||
#define HEIGHTMAP_RANGE_NODES 300
|
|
||||||
|
|
||||||
//#define FREETIME_RATIO 0.2
|
//#define FREETIME_RATIO 0.2
|
||||||
#define FREETIME_RATIO 0.15
|
#define FREETIME_RATIO 0.15
|
||||||
@ -56,7 +57,7 @@
|
|||||||
//#define ACTIVE_OBJECT_D_BLOCKS 2
|
//#define ACTIVE_OBJECT_D_BLOCKS 2
|
||||||
|
|
||||||
// Wether to catch all std::exceptions
|
// Wether to catch all std::exceptions
|
||||||
#define CATCH_UNJANDLED_EXCEPTIONS 1
|
#define CATCH_UNHANDLED_EXCEPTIONS 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collecting active blocks is stopped after object data
|
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:
|
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 ==============================
|
=============================== NOTES ==============================
|
||||||
|
|
||||||
NOTE: VBO cannot be turned on for fast-changing stuff because there
|
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
|
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.
|
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.
|
When day changes to night, these two values can be interpolated.
|
||||||
|
|
||||||
TODO: Fix address to be ipv6 compatible
|
TODO: Fix address to be ipv6 compatible
|
||||||
|
|
||||||
TODO: ESC Pause mode in which the cursor is not kept at the center of window.
|
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
|
- This also enables server to check if client has received the
|
||||||
most recent block sent, for example.
|
most recent block sent, for example.
|
||||||
|
|
||||||
SUGG: Add a time value to the param of footstepped grass and check it
|
TODO: Add a sane bandwidth throttling system to Connection
|
||||||
against a global timer when a block is accessed, to make old
|
|
||||||
steps fade away.
|
|
||||||
|
|
||||||
FIXME: There still are *some* tiny glitches in lighting as seen from
|
FIXME: There still are *some* tiny glitches in lighting as seen from
|
||||||
the client side. The server calculates them right but sometimes
|
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?
|
the sender sends the block as it was before emerging?
|
||||||
TODO: How about adding a "revision" field to MapBlocks?
|
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
|
memory
|
||||||
|
- ...What does this mean in the first place?
|
||||||
|
|
||||||
TODO: Somehow prioritize the sending of blocks and combine the block
|
TODO: Somehow prioritize the sending of blocks and combine the block
|
||||||
send queue lengths
|
send queue lengths
|
||||||
@ -130,9 +133,6 @@ SUGG: Make client send GOTBLOCKS before updating meshes
|
|||||||
|
|
||||||
TODO: Server to load starting inventory from disk
|
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 only be hidden when the client quits.
|
||||||
TODO: - Players to be saved on disk, with inventory
|
TODO: - Players to be saved on disk, with inventory
|
||||||
TODO: Players to be saved as text in map/players/<name>
|
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.
|
- A "near blocks" buffer, in which some nearby blocks are stored.
|
||||||
- For all blocks in the buffer, objects are stepped(). This
|
- For all blocks in the buffer, objects are stepped(). This
|
||||||
means they are active.
|
means they are active.
|
||||||
- TODO All blocks going in and out of the buffer are recorded.
|
- TODO: A global active buffer is needed for the server
|
||||||
- TODO For outgoing blocks, a timestamp is written.
|
- TODO: All blocks going in and out of the buffer are recorded.
|
||||||
- TODO For incoming blocks, the time difference is calculated and
|
- TODO: For outgoing blocks, a timestamp is written.
|
||||||
|
- TODO: For incoming blocks, the time difference is calculated and
|
||||||
objects are stepped according to it.
|
objects are stepped according to it.
|
||||||
TODO: A timestamp to blocks
|
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: Add config parameters for server's sending and generating distance
|
||||||
|
|
||||||
TODO: Copy the text of the last picked sign to inventory in creative
|
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
|
- This will allow saving ages of rats on disk but not sending
|
||||||
them to clients
|
them to clients
|
||||||
|
|
||||||
TODO: Fix the long-lived Server Block Emerge Jam bug
|
TODO: Get rid of GotSplitPacketException
|
||||||
- Is it related to the client deleting blocks?
|
|
||||||
|
Before release:
|
||||||
|
|
||||||
|
TODO: Check what goes wrong with caching map to disk (Kray)
|
||||||
|
|
||||||
Doing now:
|
Doing now:
|
||||||
======================================================================
|
======================================================================
|
||||||
|
|
||||||
|
TODO: Implement lighting using VoxelManipulator
|
||||||
|
|
||||||
======================================================================
|
======================================================================
|
||||||
|
|
||||||
@ -202,7 +212,7 @@ Doing now:
|
|||||||
the starting place to a static direction.
|
the starting place to a static direction.
|
||||||
|
|
||||||
This allows one to move around with the player and see what
|
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
|
#define FIELD_OF_VIEW_TEST 0
|
||||||
|
|
||||||
@ -265,7 +275,8 @@ const char *g_material_filenames[MATERIALS_COUNT] =
|
|||||||
"../data/tree.png",
|
"../data/tree.png",
|
||||||
"../data/leaves.png",
|
"../data/leaves.png",
|
||||||
"../data/grass_footsteps.png",
|
"../data/grass_footsteps.png",
|
||||||
"../data/mese.png"
|
"../data/mese.png",
|
||||||
|
"../data/mud.png"
|
||||||
};
|
};
|
||||||
|
|
||||||
video::SMaterial g_materials[MATERIALS_COUNT];
|
video::SMaterial g_materials[MATERIALS_COUNT];
|
||||||
@ -296,28 +307,39 @@ bool g_viewing_range_all = false;
|
|||||||
These are loaded from the config file.
|
These are loaded from the config file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::string g_dedicated_server;
|
Settings g_settings;
|
||||||
|
|
||||||
// Client stuff
|
// Sets default settings
|
||||||
float g_wanted_fps = FPS_DEFAULT_WANTED;
|
void set_default_settings()
|
||||||
float g_fps_max = FPS_DEFAULT_MAX;
|
{
|
||||||
s16 g_viewing_range_nodes_max = 300;
|
g_settings.set("dedicated_server", "");
|
||||||
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;
|
|
||||||
|
|
||||||
// Server stuff
|
// Client stuff
|
||||||
bool g_creative_mode = false;
|
g_settings.set("wanted_fps", "30");
|
||||||
HMParams g_hm_params;
|
g_settings.set("fps_max", "60");
|
||||||
MapParams g_map_params;
|
g_settings.set("viewing_range_nodes_max", "300");
|
||||||
float g_objectdata_interval = 0.2;
|
g_settings.set("viewing_range_nodes_min", "20");
|
||||||
u16 g_active_object_range = 2;
|
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
|
Random stuff
|
||||||
@ -354,144 +376,6 @@ std::ostream *derr_server_ptr = &dstream;
|
|||||||
std::ostream *dout_client_ptr = &dstream;
|
std::ostream *dout_client_ptr = &dstream;
|
||||||
std::ostream *derr_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
|
Timestamp stuff
|
||||||
@ -876,8 +760,10 @@ void updateViewingRange(f32 frametime, Client *client)
|
|||||||
if(g_viewing_range_all == true)
|
if(g_viewing_range_all == true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
float wanted_fps = g_settings.getFloat("wanted_fps");
|
||||||
|
|
||||||
// Initialize to the target value
|
// 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;
|
frametime_avg = frametime_avg * 0.9 + frametime * 0.1;
|
||||||
|
|
||||||
static f32 counter = 0;
|
static f32 counter = 0;
|
||||||
@ -892,7 +778,7 @@ void updateViewingRange(f32 frametime, Client *client)
|
|||||||
//float freetime_ratio = 0.4;
|
//float freetime_ratio = 0.4;
|
||||||
float freetime_ratio = FREETIME_RATIO;
|
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);
|
float fraction = sqrt(frametime_avg / frametime_wanted);
|
||||||
|
|
||||||
@ -925,11 +811,14 @@ void updateViewingRange(f32 frametime, Client *client)
|
|||||||
|
|
||||||
JMutexAutoLock lock(g_range_mutex);
|
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;
|
s16 n = (float)g_viewing_range_nodes / fraction;
|
||||||
if(n < g_viewing_range_nodes_min)
|
if(n < viewing_range_nodes_min)
|
||||||
n = g_viewing_range_nodes_min;
|
n = viewing_range_nodes_min;
|
||||||
if(n > g_viewing_range_nodes_max)
|
if(n > viewing_range_nodes_max)
|
||||||
n = g_viewing_range_nodes_max;
|
n = viewing_range_nodes_max;
|
||||||
|
|
||||||
bool can_change = true;
|
bool can_change = true;
|
||||||
|
|
||||||
@ -1050,10 +939,11 @@ int main(int argc, char *argv[])
|
|||||||
disable_stderr = true;
|
disable_stderr = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Initialize debug streams
|
||||||
debugstreams_init(disable_stderr, DEBUGFILE);
|
debugstreams_init(disable_stderr, DEBUGFILE);
|
||||||
|
// Initialize debug stacks
|
||||||
debug_stacks_init();
|
debug_stacks_init();
|
||||||
|
|
||||||
|
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -1063,6 +953,10 @@ int main(int argc, char *argv[])
|
|||||||
Basic initialization
|
Basic initialization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Initialize default settings
|
||||||
|
set_default_settings();
|
||||||
|
|
||||||
|
// Print startup message
|
||||||
dstream<<DTIME<<"minetest-c55"
|
dstream<<DTIME<<"minetest-c55"
|
||||||
" with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
|
" with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
|
||||||
<<", ENABLE_TESTS="<<ENABLE_TESTS
|
<<", ENABLE_TESTS="<<ENABLE_TESTS
|
||||||
@ -1096,7 +990,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if(argc >= 2)
|
if(argc >= 2)
|
||||||
{
|
{
|
||||||
readConfigFile(argv[1]);
|
g_settings.readConfigFile(argv[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1108,7 +1002,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
for(u32 i=0; i<2; i++)
|
for(u32 i=0; i<2; i++)
|
||||||
{
|
{
|
||||||
bool r = readConfigFile(filenames[i]);
|
bool r = g_settings.readConfigFile(filenames[i]);
|
||||||
if(r)
|
if(r)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1120,6 +1014,17 @@ int main(int argc, char *argv[])
|
|||||||
g_range_mutex.Init();
|
g_range_mutex.Init();
|
||||||
assert(g_range_mutex.IsInitialized());
|
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
|
Ask some stuff
|
||||||
*/
|
*/
|
||||||
@ -1127,40 +1032,13 @@ int main(int argc, char *argv[])
|
|||||||
std::cout<<std::endl<<std::endl;
|
std::cout<<std::endl<<std::endl;
|
||||||
char templine[100];
|
char templine[100];
|
||||||
|
|
||||||
std::cout<<"Dedicated server? [y = yes]: ";
|
// Dedicated?
|
||||||
if(g_dedicated_server != "")
|
bool dedicated = g_settings.getBoolAsk
|
||||||
{
|
("dedicated_server", "Dedicated server?", false);
|
||||||
std::cout<<g_dedicated_server<<std::endl;
|
std::cout<<"dedicated = "<<dedicated<<std::endl;
|
||||||
snprintf(templine, 100, "%s", g_dedicated_server.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cin.getline(templine, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dedicated = false;
|
// Port?
|
||||||
if(templine[0] == 'y')
|
u16 port = g_settings.getU16Ask("port", "Port", 30000);
|
||||||
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);
|
|
||||||
std::cout<<"-> "<<port<<std::endl;
|
std::cout<<"-> "<<port<<std::endl;
|
||||||
|
|
||||||
if(dedicated)
|
if(dedicated)
|
||||||
@ -1173,17 +1051,15 @@ int main(int argc, char *argv[])
|
|||||||
std::cout<<"========================"<<std::endl;
|
std::cout<<"========================"<<std::endl;
|
||||||
std::cout<<std::endl;
|
std::cout<<std::endl;
|
||||||
|
|
||||||
Server server("../map", g_creative_mode, g_hm_params,
|
Server server("../map", hm_params, map_params);
|
||||||
g_map_params, g_objectdata_interval,
|
|
||||||
g_active_object_range);
|
|
||||||
server.start(port);
|
server.start(port);
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// This is kind of a hack but can be done like this
|
// This is kind of a hack but can be done like this
|
||||||
// because server.step() is very light
|
// because server.step() is very light
|
||||||
sleep_ms(100);
|
sleep_ms(30);
|
||||||
server.step(0.1);
|
server.step(0.030);
|
||||||
|
|
||||||
static int counter = 0;
|
static int counter = 0;
|
||||||
counter--;
|
counter--;
|
||||||
@ -1214,10 +1090,10 @@ int main(int argc, char *argv[])
|
|||||||
char connect_name[100] = "";
|
char connect_name[100] = "";
|
||||||
|
|
||||||
std::cout<<"Address to connect to [empty = host a game]: ";
|
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;
|
std::cout<<g_settings.get("address")<<std::endl;
|
||||||
snprintf(connect_name, 100, "%s", g_address.c_str());
|
snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1235,9 +1111,9 @@ int main(int argc, char *argv[])
|
|||||||
std::cout<<"-> "<<connect_name<<std::endl;
|
std::cout<<"-> "<<connect_name<<std::endl;
|
||||||
|
|
||||||
char playername[PLAYERNAME_SIZE] = "";
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -1254,10 +1130,10 @@ int main(int argc, char *argv[])
|
|||||||
u16 screenH;
|
u16 screenH;
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
|
|
||||||
if(g_screenW != "" && g_screenH != "")
|
if(g_settings.get("screenW") != "" && g_settings.get("screenH") != "")
|
||||||
{
|
{
|
||||||
screenW = atoi(g_screenW.c_str());
|
screenW = atoi(g_settings.get("screenW").c_str());
|
||||||
screenH = atoi(g_screenH.c_str());
|
screenH = atoi(g_settings.get("screenH").c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1343,7 +1219,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
device->setResizable(true);
|
device->setResizable(true);
|
||||||
|
|
||||||
if(g_random_input)
|
if(g_settings.getBool("random_input"))
|
||||||
g_input = new RandomInputHandler();
|
g_input = new RandomInputHandler();
|
||||||
else
|
else
|
||||||
g_input = new RealInputHandler(device, &receiver);
|
g_input = new RealInputHandler(device, &receiver);
|
||||||
@ -1443,9 +1319,7 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
SharedPtr<Server> server;
|
SharedPtr<Server> server;
|
||||||
if(hosting){
|
if(hosting){
|
||||||
server = new Server("../map", g_creative_mode, g_hm_params,
|
server = new Server("../map", hm_params, map_params);
|
||||||
g_map_params, g_objectdata_interval,
|
|
||||||
g_active_object_range);
|
|
||||||
server->start(port);
|
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
|
// TODO: Get rid of the g_materials parameter or it's globalness
|
||||||
Client client(device, g_materials,
|
Client client(device, g_materials,
|
||||||
g_client_delete_unused_sectors_timeout,
|
g_settings.getFloat("client_delete_unused_sectors_timeout"),
|
||||||
playername);
|
playername);
|
||||||
|
|
||||||
Address connect_address(0,0,0,0, port);
|
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;
|
u32 frametime_min = 1000./fps_max;
|
||||||
|
|
||||||
if(busytime_u32 < frametime_min)
|
if(busytime_u32 < frametime_min)
|
||||||
|
@ -16,6 +16,9 @@ extern s16 g_viewing_range_nodes;
|
|||||||
//extern s16 g_actual_viewing_range_nodes;
|
//extern s16 g_actual_viewing_range_nodes;
|
||||||
extern bool g_viewing_range_all;
|
extern bool g_viewing_range_all;
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
extern Settings g_settings;
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
// Debug streams
|
// Debug streams
|
||||||
|
405
src/map.cpp
405
src/map.cpp
@ -9,6 +9,7 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
#include "voxel.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -18,6 +19,47 @@
|
|||||||
#define sleep_ms(x) usleep(x*1000)
|
#define sleep_ms(x) usleep(x*1000)
|
||||||
#endif
|
#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):
|
Map::Map(std::ostream &dout):
|
||||||
m_dout(dout),
|
m_dout(dout),
|
||||||
m_camera_position(0,0,0),
|
m_camera_position(0,0,0),
|
||||||
@ -158,33 +200,11 @@ bool Map::isNodeUnderground(v3s16 p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LKJnb
|
#if 0
|
||||||
//TODO: Remove: Not used.
|
void Map::interpolate(v3s16 block,
|
||||||
/*
|
|
||||||
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,
|
|
||||||
core::map<v3s16, MapBlock*> & modified_blocks)
|
core::map<v3s16, MapBlock*> & modified_blocks)
|
||||||
{
|
{
|
||||||
v3s16 dirs[6] = {
|
const v3s16 dirs[6] = {
|
||||||
v3s16(0,0,1), // back
|
v3s16(0,0,1), // back
|
||||||
v3s16(0,1,0), // top
|
v3s16(0,1,0), // top
|
||||||
v3s16(1,0,0), // right
|
v3s16(1,0,0), // right
|
||||||
@ -193,6 +213,15 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
|||||||
v3s16(-1,0,0), // left
|
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
|
Initialize block cache
|
||||||
*/
|
*/
|
||||||
@ -201,23 +230,22 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
|||||||
// Cache this a bit, too
|
// Cache this a bit, too
|
||||||
bool block_checked_in_modified = false;
|
bool block_checked_in_modified = false;
|
||||||
|
|
||||||
// Loop through 6 neighbors
|
for(; j.atEnd() == false; j++)
|
||||||
for(u16 i=0; i<6; i++){
|
//for(; j != from_nodes.end(); j++)
|
||||||
// Get the position of the neighbor node
|
{
|
||||||
v3s16 n2pos = pos + dirs[i];
|
v3s16 pos = j.getNode()->getKey();
|
||||||
|
//v3s16 pos = *j;
|
||||||
// Get the block where the node is located
|
//dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
|
||||||
v3s16 blockpos = getNodeBlockPos(n2pos);
|
v3s16 blockpos = getNodeBlockPos(pos);
|
||||||
|
|
||||||
// Only fetch a new block if the block position has changed
|
// Only fetch a new block if the block position has changed
|
||||||
try{
|
try{
|
||||||
if(block == NULL || blockpos != blockpos_last)
|
if(block == NULL || blockpos != blockpos_last){
|
||||||
{
|
|
||||||
block = getBlockNoCreate(blockpos);
|
block = getBlockNoCreate(blockpos);
|
||||||
blockpos_last = blockpos;
|
blockpos_last = blockpos;
|
||||||
|
|
||||||
block_checked_in_modified = false;
|
block_checked_in_modified = false;
|
||||||
//blockchangecount++;
|
blockchangecount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
catch(InvalidPositionException &e)
|
||||||
@ -228,32 +256,74 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
|||||||
if(block->isDummy())
|
if(block->isDummy())
|
||||||
continue;
|
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
|
// Calculate relative position in block
|
||||||
v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
|
v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
|
||||||
// Get node straight from the block
|
// Get node straight from the block
|
||||||
MapNode n2 = block->getNode(relpos);
|
MapNode n2 = block->getNode(relpos);
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
/*
|
/*
|
||||||
If the neighbor is dimmer than what was specified
|
If the neighbor is brighter than the current node,
|
||||||
as oldlight (the light of the previous 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)
|
||||||
{
|
{
|
||||||
/*
|
if(n2.light_propagates())
|
||||||
Set light to 0 and recurse.
|
{
|
||||||
*/
|
n2.setLight(newlight);
|
||||||
u8 current_light = n2.getLight();
|
|
||||||
n2.setLight(0);
|
|
||||||
block->setNode(relpos, n2);
|
block->setNode(relpos, n2);
|
||||||
unLightNeighbors(n2pos, current_light,
|
lighted_nodes.insert(n2pos, true);
|
||||||
light_sources, modified_blocks);
|
//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 the block is not found in modified_blocks, add.
|
||||||
if(modified_blocks.find(blockpos) == NULL)
|
if(modified_blocks.find(blockpos) == NULL)
|
||||||
@ -263,12 +333,20 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
|
|||||||
block_checked_in_modified = true;
|
block_checked_in_modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
catch(InvalidPositionException &e)
|
||||||
else{
|
{
|
||||||
//light_sources.push_back(n2pos);
|
continue;
|
||||||
light_sources.insert(n2pos, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*dstream<<"spreadLight(): Changed block "
|
||||||
|
<<blockchangecount<<" times"
|
||||||
|
<<" for "<<from_nodes.size()<<" nodes"
|
||||||
|
<<std::endl;*/
|
||||||
|
|
||||||
|
if(lighted_nodes.size() > 0)
|
||||||
|
spreadLight(lighted_nodes, modified_blocks);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1090,6 +1168,13 @@ void Map::timerUpdate(float dtime)
|
|||||||
|
|
||||||
void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
|
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;
|
core::list<v2s16>::Iterator j;
|
||||||
for(j=list.begin(); j!=list.end(); 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
|
// Create master heightmap
|
||||||
ValueGenerator *maxgen =
|
ValueGenerator *maxgen =
|
||||||
ValueGenerator::deSerialize(hmp.height_randmax);
|
ValueGenerator::deSerialize(hmp.randmax);
|
||||||
ValueGenerator *factorgen =
|
ValueGenerator *factorgen =
|
||||||
ValueGenerator::deSerialize(hmp.height_randfactor);
|
ValueGenerator::deSerialize(hmp.randfactor);
|
||||||
ValueGenerator *basegen =
|
ValueGenerator *basegen =
|
||||||
ValueGenerator::deSerialize(hmp.height_base);
|
ValueGenerator::deSerialize(hmp.base);
|
||||||
m_heightmap = new UnlimitedHeightmap
|
m_heightmap = new UnlimitedHeightmap
|
||||||
(hmp.heightmap_blocksize, maxgen, factorgen, basegen);
|
(hmp.blocksize, maxgen, factorgen, basegen);
|
||||||
|
|
||||||
// Set map parameters
|
// Set map parameters
|
||||||
m_params = mp;
|
m_params = mp;
|
||||||
@ -1409,6 +1494,9 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
|
|||||||
SECTOR_OBJECT_TREE_1);
|
SECTOR_OBJECT_TREE_1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
Plant some bushes if sector is pit-like
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
// Pitness usually goes at around -0.5...0.5
|
// Pitness usually goes at around -0.5...0.5
|
||||||
u32 bush_max = 0;
|
u32 bush_max = 0;
|
||||||
@ -1429,6 +1517,22 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
|
|||||||
SECTOR_OBJECT_BUSH_1);
|
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
|
Insert to container
|
||||||
@ -1533,9 +1637,16 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Randomize a bit. This makes dungeons.
|
// Randomize a bit. This makes dungeons.
|
||||||
bool low_block_is_empty = false;
|
/*bool low_block_is_empty = false;
|
||||||
if(rand() % 4 == 0)
|
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
|
// This is the basic material of what the visible flat ground
|
||||||
// will consist of
|
// will consist of
|
||||||
@ -1551,9 +1662,7 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
{
|
{
|
||||||
//dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
|
//dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
|
||||||
float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
|
float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
|
||||||
|
|
||||||
assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
|
assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
|
||||||
|
|
||||||
s16 surface_y = surface_y_f;
|
s16 surface_y = surface_y_f;
|
||||||
//avg_ground_y += surface_y;
|
//avg_ground_y += surface_y;
|
||||||
if(surface_y < lowest_ground_y)
|
if(surface_y < lowest_ground_y)
|
||||||
@ -1574,13 +1683,14 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
else
|
else
|
||||||
surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
|
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;
|
s16 real_y = block_y * MAP_BLOCKSIZE + y0;
|
||||||
MapNode n;
|
MapNode n;
|
||||||
/*
|
/*
|
||||||
Calculate lighting
|
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.
|
newly created block, they won't be taken into account.
|
||||||
*/
|
*/
|
||||||
if(real_y > surface_y)
|
if(real_y > surface_y)
|
||||||
@ -1589,12 +1699,17 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
Calculate material
|
Calculate material
|
||||||
*/
|
*/
|
||||||
// If node is very low
|
// If node is very low
|
||||||
if(real_y <= surface_y - 10){
|
if(real_y <= surface_y - 7){
|
||||||
// Create dungeons
|
// 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;
|
n.d = MATERIAL_AIR;
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
n.d = MATERIAL_STONE;
|
n.d = MATERIAL_STONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1603,7 +1718,14 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
n.d = MATERIAL_STONE;
|
n.d = MATERIAL_STONE;
|
||||||
// If node is at or under heightmap y
|
// If node is at or under heightmap y
|
||||||
else if(real_y <= surface_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;
|
n.d = material;
|
||||||
|
}
|
||||||
// If node is over heightmap y
|
// If node is over heightmap y
|
||||||
else{
|
else{
|
||||||
// If under water level, it's water
|
// 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;
|
bool is_underground = (block_y+1) * MAP_BLOCKSIZE < lowest_ground_y;
|
||||||
block->setIsUnderground(is_underground);
|
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
|
Add some minerals
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(is_underground && low_block_is_empty == false)
|
if(is_underground)
|
||||||
{
|
{
|
||||||
s16 underground_level = lowest_ground_y/MAP_BLOCKSIZE - block_y;
|
s16 underground_level = lowest_ground_y/MAP_BLOCKSIZE - block_y;
|
||||||
for(s16 i=0; i<underground_level*3; i++)
|
for(s16 i=0; i<underground_level*3; i++)
|
||||||
@ -1640,9 +1772,6 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
if(rand()%2 == 0)
|
if(rand()%2 == 0)
|
||||||
{
|
{
|
||||||
v3s16 cp(
|
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,
|
(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++)
|
for(u16 i=0; i<26; i++)
|
||||||
{
|
{
|
||||||
|
if(!is_ground_material(block->getNode(cp+g_26dirs[i]).d))
|
||||||
|
continue;
|
||||||
|
|
||||||
if(rand()%8 == 0)
|
if(rand()%8 == 0)
|
||||||
block->setNode(cp+g_26dirs[i], n);
|
block->setNode(cp+g_26dirs[i], n);
|
||||||
}
|
}
|
||||||
@ -1666,7 +1798,7 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
/*
|
/*
|
||||||
Create a few rats in empty blocks underground
|
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++)
|
//for(u16 i=0; i<2; i++)
|
||||||
{
|
{
|
||||||
@ -1674,42 +1806,54 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
RatObject *obj = new RatObject(NULL, -1, intToFloat(pos));
|
RatObject *obj = new RatObject(NULL, -1, intToFloat(pos));
|
||||||
block->addObject(obj);
|
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.
|
Add block to sector.
|
||||||
*/
|
*/
|
||||||
sector->insertBlock(block);
|
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;
|
core::map<s16, MapBlock*> changed_blocks_sector;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1722,6 +1866,7 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
i.atEnd() == false; i++)
|
i.atEnd() == false; i++)
|
||||||
{
|
{
|
||||||
v3s16 p = i.getNode()->getKey();
|
v3s16 p = i.getNode()->getKey();
|
||||||
|
v2s16 p2d(p.X,p.Z);
|
||||||
u8 d = i.getNode()->getValue();
|
u8 d = i.getNode()->getValue();
|
||||||
|
|
||||||
//v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
|
//v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
|
||||||
@ -1795,6 +1940,66 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
objects_to_remove.push_back(p);
|
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
|
else
|
||||||
{
|
{
|
||||||
dstream<<"ServerMap::emergeBlock(): "
|
dstream<<"ServerMap::emergeBlock(): "
|
||||||
@ -1807,7 +2012,7 @@ MapBlock * ServerMap::emergeBlock(
|
|||||||
{
|
{
|
||||||
dstream<<"WARNING: "<<__FUNCTION_NAME
|
dstream<<"WARNING: "<<__FUNCTION_NAME
|
||||||
<<": while inserting object "<<(int)d
|
<<": while inserting object "<<(int)d
|
||||||
<<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
<<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
|
||||||
<<" InvalidPositionException.what()="
|
<<" InvalidPositionException.what()="
|
||||||
<<e.what()<<std::endl;
|
<<e.what()<<std::endl;
|
||||||
// This is not too fatal and seems to happen sometimes.
|
// 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 "mapsector.h"
|
||||||
#include "constants.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:
|
public:
|
||||||
InvalidFilenameException(const char *s):
|
MapBlockPointerCache(Map *map);
|
||||||
BaseException(s)
|
~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
|
#define MAPTYPE_BASE 0
|
||||||
@ -61,6 +178,13 @@ public:
|
|||||||
|
|
||||||
v3s16 drawoffset; // for drawbox()
|
v3s16 drawoffset; // for drawbox()
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used by MapBlockPointerCache.
|
||||||
|
|
||||||
|
waitCaches() can be called to remove all caches before continuing
|
||||||
|
*/
|
||||||
|
CacheLock m_blockcachelock;
|
||||||
|
|
||||||
Map(std::ostream &dout);
|
Map(std::ostream &dout);
|
||||||
virtual ~Map();
|
virtual ~Map();
|
||||||
|
|
||||||
@ -154,7 +278,7 @@ public:
|
|||||||
MapBlock * blockref = getBlockNoCreate(blockpos);
|
MapBlock * blockref = getBlockNoCreate(blockpos);
|
||||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||||
|
|
||||||
return blockref->getNode(relpos);
|
return blockref->getNodeNoCheck(relpos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual from NodeContainer
|
// virtual from NodeContainer
|
||||||
@ -163,7 +287,7 @@ public:
|
|||||||
v3s16 blockpos = getNodeBlockPos(p);
|
v3s16 blockpos = getNodeBlockPos(p);
|
||||||
MapBlock * blockref = getBlockNoCreate(blockpos);
|
MapBlock * blockref = getBlockNoCreate(blockpos);
|
||||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||||
blockref->setNode(relpos, n);
|
blockref->setNodeNoCheck(relpos, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*MapNode getNodeGenerate(v3s16 p)
|
/*MapNode getNodeGenerate(v3s16 p)
|
||||||
@ -247,15 +371,15 @@ struct HMParams
|
|||||||
{
|
{
|
||||||
HMParams()
|
HMParams()
|
||||||
{
|
{
|
||||||
heightmap_blocksize = 64;
|
blocksize = 64;
|
||||||
height_randmax = "constant 70.0";
|
randmax = "constant 70.0";
|
||||||
height_randfactor = "constant 0.6";
|
randfactor = "constant 0.6";
|
||||||
height_base = "linear 0 80 0";
|
base = "linear 0 80 0";
|
||||||
}
|
}
|
||||||
s16 heightmap_blocksize;
|
s16 blocksize;
|
||||||
std::string height_randmax;
|
std::string randmax;
|
||||||
std::string height_randfactor;
|
std::string randfactor;
|
||||||
std::string height_base;
|
std::string base;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Map parameters
|
// Map parameters
|
||||||
|
@ -38,7 +38,9 @@ enum
|
|||||||
{
|
{
|
||||||
NODECONTAINER_ID_MAPBLOCK,
|
NODECONTAINER_ID_MAPBLOCK,
|
||||||
NODECONTAINER_ID_MAPSECTOR,
|
NODECONTAINER_ID_MAPSECTOR,
|
||||||
NODECONTAINER_ID_MAP
|
NODECONTAINER_ID_MAP,
|
||||||
|
NODECONTAINER_ID_MAPBLOCKCACHE,
|
||||||
|
NODECONTAINER_ID_VOXELMANIPULATOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NodeContainer
|
class NodeContainer
|
||||||
@ -245,6 +247,35 @@ public:
|
|||||||
setNode(p.X, p.Y, p.Z, n);
|
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
|
These functions consult the parent container if the position
|
||||||
is not valid on this MapBlock.
|
is not valid on this MapBlock.
|
||||||
|
@ -17,10 +17,25 @@
|
|||||||
|
|
||||||
#define MATERIALS_COUNT 256
|
#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
|
#define MATERIAL_IGNORE 255
|
||||||
// This is the common material through which the player can walk
|
#define MATERIAL_IGNORE_DEFAULT_PARAM 0
|
||||||
// and which is transparent to light
|
|
||||||
|
/*
|
||||||
|
The common material through which the player can walk and which
|
||||||
|
is transparent to light
|
||||||
|
*/
|
||||||
#define MATERIAL_AIR 254
|
#define MATERIAL_AIR 254
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -64,6 +79,8 @@ enum Material
|
|||||||
|
|
||||||
MATERIAL_MESE,
|
MATERIAL_MESE,
|
||||||
|
|
||||||
|
MATERIAL_MUD,
|
||||||
|
|
||||||
// This is set to the number of the actual values in this enum
|
// This is set to the number of the actual values in this enum
|
||||||
USEFUL_MATERIAL_COUNT
|
USEFUL_MATERIAL_COUNT
|
||||||
};
|
};
|
||||||
@ -126,6 +143,21 @@ inline u8 face_materials(u8 m1, u8 m2)
|
|||||||
return 2;
|
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
|
struct MapNode
|
||||||
{
|
{
|
||||||
//TODO: block type to differ from material
|
//TODO: block type to differ from material
|
||||||
@ -133,9 +165,6 @@ struct MapNode
|
|||||||
// block type
|
// block type
|
||||||
u8 d;
|
u8 d;
|
||||||
|
|
||||||
// Removed because light is now stored in param for air
|
|
||||||
// f32 light;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Misc parameter. Initialized to 0.
|
Misc parameter. Initialized to 0.
|
||||||
- For light_propagates() blocks, this is light intensity,
|
- For light_propagates() blocks, this is light intensity,
|
||||||
@ -155,6 +184,11 @@ struct MapNode
|
|||||||
param = a_param;
|
param = a_param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const MapNode &other)
|
||||||
|
{
|
||||||
|
return (d == other.d && param == other.param);
|
||||||
|
}
|
||||||
|
|
||||||
bool light_propagates()
|
bool light_propagates()
|
||||||
{
|
{
|
||||||
return light_propagates_material(d);
|
return light_propagates_material(d);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define SECTOR_OBJECT_TEST 0
|
#define SECTOR_OBJECT_TEST 0
|
||||||
#define SECTOR_OBJECT_TREE_1 1
|
#define SECTOR_OBJECT_TREE_1 1
|
||||||
#define SECTOR_OBJECT_BUSH_1 2
|
#define SECTOR_OBJECT_BUSH_1 2
|
||||||
|
#define SECTOR_OBJECT_RAVINE 3
|
||||||
|
|
||||||
#define MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT 4
|
#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);
|
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,
|
// Update lighting without locking the environment mutex,
|
||||||
// add modified blocks to changed blocks
|
// add modified blocks to changed blocks
|
||||||
map.updateLighting(lighting_invalidated_blocks, modified_blocks);
|
map.updateLighting(lighting_invalidated_blocks, modified_blocks);
|
||||||
@ -222,11 +225,11 @@ void * EmergeThread::Thread()
|
|||||||
client->SetBlocksNotSent(modified_blocks);
|
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
|
// Decrement emerge queue count of client
|
||||||
client->BlockEmerged();
|
client->BlockEmerged();
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -246,282 +249,6 @@ void * EmergeThread::Thread()
|
|||||||
return NULL;
|
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,
|
void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
||||||
core::array<PrioritySortedBlockTransfer> &dest)
|
core::array<PrioritySortedBlockTransfer> &dest)
|
||||||
{
|
{
|
||||||
@ -531,7 +258,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
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;
|
//dstream<<"Not sending any blocks, Queue full."<<std::endl;
|
||||||
return;
|
return;
|
||||||
@ -574,15 +302,17 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||||||
d_start = m_nearest_unsent_d;
|
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());
|
SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
|
||||||
m_time_from_building.m_value += dtime;
|
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
|
if(m_time_from_building.m_value
|
||||||
< FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
|
< FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
|
||||||
{
|
{
|
||||||
@ -646,9 +376,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||||||
/*
|
/*
|
||||||
Send throttling
|
Send throttling
|
||||||
- Don't allow too many simultaneous transfers
|
- Don't allow too many simultaneous transfers
|
||||||
|
- EXCEPT when the blocks are very close
|
||||||
|
|
||||||
Also, don't send blocks that are already flying.
|
Also, don't send blocks that are already flying.
|
||||||
*/
|
*/
|
||||||
|
if(d >= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock(m_blocks_sending_mutex);
|
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)
|
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)
|
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)
|
if(block == NULL || surely_not_found_on_disk)
|
||||||
{
|
{
|
||||||
// Block not found.
|
/*SharedPtr<JMutexAutoLock> lock
|
||||||
SharedPtr<JMutexAutoLock> lock
|
(m_num_blocks_in_emerge_queue.getLock());*/
|
||||||
(m_num_blocks_in_emerge_queue.getLock());
|
|
||||||
|
|
||||||
//TODO: Get value from somewhere
|
//TODO: Get value from somewhere
|
||||||
//TODO: Balance between clients
|
|
||||||
//if(server->m_emerge_queue.size() < 1)
|
|
||||||
|
|
||||||
// Allow only one block in emerge queue
|
// 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
|
// Add it to the emerge queue and trigger the thread
|
||||||
|
|
||||||
@ -752,10 +480,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
|
|||||||
if(generate == false)
|
if(generate == false)
|
||||||
flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
|
flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
|
||||||
|
|
||||||
{
|
|
||||||
m_num_blocks_in_emerge_queue.m_value++;
|
|
||||||
}
|
|
||||||
|
|
||||||
server->m_emerge_queue.addBlock(peer_id, p, flags);
|
server->m_emerge_queue.addBlock(peer_id, p, flags);
|
||||||
server->m_emergethread.trigger();
|
server->m_emergethread.trigger();
|
||||||
}
|
}
|
||||||
@ -880,7 +604,7 @@ void RemoteClient::SendObjectData(
|
|||||||
v3s16 center = getNodeBlockPos(center_nodepos);
|
v3s16 center = getNodeBlockPos(center_nodepos);
|
||||||
|
|
||||||
//s16 d_max = ACTIVE_OBJECT_D_BLOCKS;
|
//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
|
// Number of blocks whose objects were written to bos
|
||||||
u16 blockcount = 0;
|
u16 blockcount = 0;
|
||||||
@ -956,9 +680,9 @@ void RemoteClient::SendObjectData(
|
|||||||
// Fetch the block only if it is on disk.
|
// Fetch the block only if it is on disk.
|
||||||
|
|
||||||
// Grab and increment counter
|
// Grab and increment counter
|
||||||
SharedPtr<JMutexAutoLock> lock
|
/*SharedPtr<JMutexAutoLock> lock
|
||||||
(m_num_blocks_in_emerge_queue.getLock());
|
(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
|
// Add to queue as an anonymous fetch from disk
|
||||||
u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL;
|
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());
|
SharedPtr<JMutexAutoLock> lock(m_num_blocks_in_emerge_queue.getLock());
|
||||||
assert(m_num_blocks_in_emerge_queue.m_value > 0);
|
assert(m_num_blocks_in_emerge_queue.m_value > 0);
|
||||||
m_num_blocks_in_emerge_queue.m_value--;
|
m_num_blocks_in_emerge_queue.m_value--;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
|
/*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
|
||||||
{
|
{
|
||||||
@ -1145,19 +869,13 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
|||||||
|
|
||||||
Server::Server(
|
Server::Server(
|
||||||
std::string mapsavedir,
|
std::string mapsavedir,
|
||||||
bool creative_mode,
|
|
||||||
HMParams hm_params,
|
HMParams hm_params,
|
||||||
MapParams map_params,
|
MapParams map_params
|
||||||
float objectdata_interval,
|
|
||||||
u16 active_object_range
|
|
||||||
):
|
):
|
||||||
m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server),
|
m_env(new ServerMap(mapsavedir, hm_params, map_params), 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)
|
||||||
m_creative_mode(creative_mode),
|
|
||||||
m_objectdata_interval(objectdata_interval),
|
|
||||||
m_active_object_range(active_object_range)
|
|
||||||
{
|
{
|
||||||
m_env_mutex.Init();
|
m_env_mutex.Init();
|
||||||
m_con_mutex.Init();
|
m_con_mutex.Init();
|
||||||
@ -1196,7 +914,7 @@ void Server::start(unsigned short port)
|
|||||||
m_thread.stop();
|
m_thread.stop();
|
||||||
|
|
||||||
// Initialize connection
|
// Initialize connection
|
||||||
m_con.setTimeoutMs(50);
|
m_con.setTimeoutMs(30);
|
||||||
m_con.Serve(port);
|
m_con.Serve(port);
|
||||||
|
|
||||||
// Start thread
|
// Start thread
|
||||||
@ -1287,7 +1005,7 @@ void Server::AsyncRunStep()
|
|||||||
|
|
||||||
// Run time- and client- related stuff
|
// Run time- and client- related stuff
|
||||||
// NOTE: If you intend to add something here, check that it
|
// 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
|
// Clients are behind connection lock
|
||||||
JMutexAutoLock lock(m_con_mutex);
|
JMutexAutoLock lock(m_con_mutex);
|
||||||
@ -1309,7 +1027,7 @@ void Server::AsyncRunStep()
|
|||||||
{
|
{
|
||||||
static float counter = 0.0;
|
static float counter = 0.0;
|
||||||
counter += dtime;
|
counter += dtime;
|
||||||
if(counter >= m_objectdata_interval)
|
if(counter >= g_settings.getFloat("objectdata_interval"))
|
||||||
{
|
{
|
||||||
JMutexAutoLock lock1(m_env_mutex);
|
JMutexAutoLock lock1(m_env_mutex);
|
||||||
JMutexAutoLock lock2(m_con_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
|
// Save map
|
||||||
|
{
|
||||||
static float counter = 0.0;
|
static float counter = 0.0;
|
||||||
counter += dtime;
|
counter += dtime;
|
||||||
if(counter >= SERVER_MAP_SAVE_INTERVAL)
|
if(counter >= SERVER_MAP_SAVE_INTERVAL)
|
||||||
@ -1619,7 +1350,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
// Left click
|
// Left click
|
||||||
if(button == 0)
|
if(button == 0)
|
||||||
{
|
{
|
||||||
if(m_creative_mode == false)
|
if(g_settings.getBool("creative_mode") == false)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Skip if inventory has no free space
|
// Skip if inventory has no free space
|
||||||
@ -1684,8 +1415,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Otherwise remove it
|
|
||||||
m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
|
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
catch(InvalidPositionException &e)
|
||||||
{
|
{
|
||||||
@ -1707,7 +1436,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
// Send as reliable
|
// Send as reliable
|
||||||
m_con.SendToAll(0, reply, true);
|
m_con.SendToAll(0, reply, true);
|
||||||
|
|
||||||
if(m_creative_mode == false)
|
if(g_settings.getBool("creative_mode") == false)
|
||||||
{
|
{
|
||||||
// Add to inventory and send inventory
|
// Add to inventory and send inventory
|
||||||
InventoryItem *item = new MaterialItem(material, 1);
|
InventoryItem *item = new MaterialItem(material, 1);
|
||||||
@ -1715,6 +1444,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
SendInventory(player->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
|
} // button == 0
|
||||||
/*
|
/*
|
||||||
Right button places blocks and stuff
|
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);
|
MapNode n2 = m_env.getMap().getNode(p_over);
|
||||||
if(n2.d != MATERIAL_AIR)
|
if(n2.d != MATERIAL_AIR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
core::map<v3s16, MapBlock*> modified_blocks;
|
|
||||||
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
|
|
||||||
}
|
}
|
||||||
catch(InvalidPositionException &e)
|
catch(InvalidPositionException &e)
|
||||||
{
|
{
|
||||||
@ -1758,7 +1490,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
// Reset build time counter
|
// Reset build time counter
|
||||||
getClient(peer->id)->m_time_from_building.set(0.0);
|
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
|
// Remove from inventory and send inventory
|
||||||
if(mitem->getCount() == 1)
|
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);
|
n.serialize(&reply[8], peer_ser_ver);
|
||||||
// Send as reliable
|
// Send as reliable
|
||||||
m_con.SendToAll(0, reply, true);
|
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
|
Handle block object items
|
||||||
@ -1828,7 +1568,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
|
|
||||||
//dout_server<<"Placed object"<<std::endl;
|
//dout_server<<"Placed object"<<std::endl;
|
||||||
|
|
||||||
if(m_creative_mode == false)
|
if(g_settings.getBool("creative_mode") == false)
|
||||||
{
|
{
|
||||||
// Remove from inventory and send inventory
|
// Remove from inventory and send inventory
|
||||||
player->inventory.deleteItem(item_i);
|
player->inventory.deleteItem(item_i);
|
||||||
@ -2168,7 +1908,7 @@ void Server::peerAdded(con::Peer *peer)
|
|||||||
Add stuff to inventory
|
Add stuff to inventory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(m_creative_mode)
|
if(g_settings.getBool("creative_mode"))
|
||||||
{
|
{
|
||||||
// Give all materials
|
// Give all materials
|
||||||
assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
|
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);
|
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)
|
void Server::SendBlocks(float dtime)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
@ -2390,8 +2101,9 @@ void Server::SendBlocks(float dtime)
|
|||||||
|
|
||||||
for(u32 i=0; i<queue.size(); i++)
|
for(u32 i=0; i<queue.size(); i++)
|
||||||
{
|
{
|
||||||
//TODO: Calculate value dynamically
|
//TODO: Calculate limit dynamically
|
||||||
if(total_sending >= MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL)
|
if(total_sending >= g_settings.getS32
|
||||||
|
("max_simultaneous_block_sends_server_total"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
PrioritySortedBlockTransfer q = queue[i];
|
PrioritySortedBlockTransfer q = queue[i];
|
||||||
|
44
src/server.h
44
src/server.h
@ -103,6 +103,23 @@ public:
|
|||||||
return m_queue.size();
|
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:
|
private:
|
||||||
core::list<QueuedBlockEmerge*> m_queue;
|
core::list<QueuedBlockEmerge*> m_queue;
|
||||||
JMutex m_mutex;
|
JMutex m_mutex;
|
||||||
@ -237,8 +254,8 @@ public:
|
|||||||
u8 pending_serialization_version;
|
u8 pending_serialization_version;
|
||||||
|
|
||||||
RemoteClient():
|
RemoteClient():
|
||||||
m_time_from_building(0.0),
|
m_time_from_building(0.0)
|
||||||
m_num_blocks_in_emerge_queue(0)
|
//m_num_blocks_in_emerge_queue(0)
|
||||||
{
|
{
|
||||||
peer_id = 0;
|
peer_id = 0;
|
||||||
serialization_version = SER_FMT_VER_INVALID;
|
serialization_version = SER_FMT_VER_INVALID;
|
||||||
@ -276,7 +293,7 @@ public:
|
|||||||
void SetBlockNotSent(v3s16 p);
|
void SetBlockNotSent(v3s16 p);
|
||||||
void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
|
void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
|
||||||
|
|
||||||
void BlockEmerged();
|
//void BlockEmerged();
|
||||||
|
|
||||||
/*bool IsSendingBlock(v3s16 p)
|
/*bool IsSendingBlock(v3s16 p)
|
||||||
{
|
{
|
||||||
@ -300,8 +317,8 @@ public:
|
|||||||
JMutexAutoLock l2(m_blocks_sent_mutex);
|
JMutexAutoLock l2(m_blocks_sent_mutex);
|
||||||
JMutexAutoLock l3(m_blocks_sending_mutex);
|
JMutexAutoLock l3(m_blocks_sending_mutex);
|
||||||
o<<"RemoteClient "<<peer_id<<": "
|
o<<"RemoteClient "<<peer_id<<": "
|
||||||
<<"m_num_blocks_in_emerge_queue="
|
/*<<"m_num_blocks_in_emerge_queue="
|
||||||
<<m_num_blocks_in_emerge_queue.get()
|
<<m_num_blocks_in_emerge_queue.get()*/
|
||||||
<<", m_blocks_sent.size()="<<m_blocks_sent.size()
|
<<", m_blocks_sent.size()="<<m_blocks_sent.size()
|
||||||
<<", m_blocks_sending.size()="<<m_blocks_sending.size()
|
<<", m_blocks_sending.size()="<<m_blocks_sending.size()
|
||||||
<<", m_nearest_unsent_d="<<m_nearest_unsent_d
|
<<", m_nearest_unsent_d="<<m_nearest_unsent_d
|
||||||
@ -321,10 +338,11 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//TODO: core::map<v3s16, MapBlock*> m_active_blocks
|
//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
|
// Number of blocks in the emerge queue that have this client as
|
||||||
// a receiver. Used for throttling network usage.
|
// 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.
|
Blocks that have been sent to client.
|
||||||
@ -368,16 +386,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
Server(
|
Server(
|
||||||
std::string mapsavedir,
|
std::string mapsavedir,
|
||||||
bool creative_mode,
|
|
||||||
HMParams hm_params,
|
HMParams hm_params,
|
||||||
MapParams map_params,
|
MapParams map_params
|
||||||
float objectdata_inverval,
|
|
||||||
u16 active_object_range
|
|
||||||
);
|
);
|
||||||
~Server();
|
~Server();
|
||||||
void start(unsigned short port);
|
void start(unsigned short port);
|
||||||
void stop();
|
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);
|
void step(float dtime);
|
||||||
|
// This is run by ServerThread and does the actual processing
|
||||||
void AsyncRunStep();
|
void AsyncRunStep();
|
||||||
void Receive();
|
void Receive();
|
||||||
void ProcessData(u8 *data, u32 datasize, u16 peer_id);
|
void ProcessData(u8 *data, u32 datasize, u16 peer_id);
|
||||||
@ -387,7 +405,6 @@ public:
|
|||||||
|
|
||||||
// Environment and Connection must be locked when called
|
// Environment and Connection must be locked when called
|
||||||
void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
|
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
|
//TODO: Sending of many blocks in a single packet
|
||||||
|
|
||||||
// Environment and Connection must be locked when called
|
// Environment and Connection must be locked when called
|
||||||
@ -431,11 +448,6 @@ private:
|
|||||||
|
|
||||||
BlockEmergeQueue m_emerge_queue;
|
BlockEmergeQueue m_emerge_queue;
|
||||||
|
|
||||||
// Settings
|
|
||||||
bool m_creative_mode;
|
|
||||||
float m_objectdata_interval;
|
|
||||||
u16 m_active_object_range;
|
|
||||||
|
|
||||||
friend class EmergeThread;
|
friend class EmergeThread;
|
||||||
friend class RemoteClient;
|
friend class RemoteClient;
|
||||||
};
|
};
|
||||||
|
@ -164,7 +164,9 @@ void UDPSocket::Bind(unsigned short port)
|
|||||||
|
|
||||||
if(bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
|
if(bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
|
||||||
{
|
{
|
||||||
|
#ifndef DISABLE_ERRNO
|
||||||
dstream<<(int)m_handle<<": Bind failed: "<<strerror(errno)<<std::endl;
|
dstream<<(int)m_handle<<": Bind failed: "<<strerror(errno)<<std::endl;
|
||||||
|
#endif
|
||||||
throw SocketException("Failed to bind socket");
|
throw SocketException("Failed to bind socket");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,7 +293,9 @@ bool UDPSocket::WaitData(int timeout_ms)
|
|||||||
}
|
}
|
||||||
else if(result < 0){
|
else if(result < 0){
|
||||||
// Error
|
// Error
|
||||||
|
#ifndef DISABLE_ERRNO
|
||||||
dstream<<(int)m_handle<<": Select failed: "<<strerror(errno)<<std::endl;
|
dstream<<(int)m_handle<<": Select failed: "<<strerror(errno)<<std::endl;
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
dstream<<(int)m_handle<<": WSAGetLastError()="<<WSAGetLastError()<<std::endl;
|
dstream<<(int)m_handle<<": WSAGetLastError()="<<WSAGetLastError()<<std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
42
src/test.cpp
42
src/test.cpp
@ -1,6 +1,5 @@
|
|||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include "common_irrlicht.h"
|
#include "common_irrlicht.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
@ -10,6 +9,7 @@
|
|||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "serialization.h"
|
#include "serialization.h"
|
||||||
|
#include "voxel.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#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
|
struct TestMapBlock
|
||||||
{
|
{
|
||||||
class TC : public NodeContainer
|
class TC : public NodeContainer
|
||||||
@ -906,6 +945,7 @@ void run_tests()
|
|||||||
TEST(TestUtilities);
|
TEST(TestUtilities);
|
||||||
TEST(TestCompress);
|
TEST(TestCompress);
|
||||||
TEST(TestMapNode);
|
TEST(TestMapNode);
|
||||||
|
TEST(TestVoxelManipulator);
|
||||||
TEST(TestMapBlock);
|
TEST(TestMapBlock);
|
||||||
TEST(TestMapSector);
|
TEST(TestMapSector);
|
||||||
TEST(TestHeightmap);
|
TEST(TestHeightmap);
|
||||||
|
155
src/utility.h
155
src/utility.h
@ -8,8 +8,11 @@
|
|||||||
#include "common_irrlicht.h"
|
#include "common_irrlicht.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "strfnd.h"
|
#include "strfnd.h"
|
||||||
|
#include "exceptions.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
extern const v3s16 g_26dirs[26];
|
extern const v3s16 g_26dirs[26];
|
||||||
|
|
||||||
@ -613,5 +616,157 @@ inline s32 stoi(std::string s, s32 min, s32 max)
|
|||||||
return i;
|
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
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user