TARGET = test\r
SOURCE_FILES = guiPauseMenu.cpp mapnode.cpp tile.cpp 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\r
SOURCES = $(addprefix src/, $(SOURCE_FILES))\r
-OBJECTS = $(SOURCES:.cpp=.o)\r
-FASTTARGET = fasttest\r
+BUILD_DIR = build\r
+OBJECTS = $(addprefix $(BUILD_DIR)/, $(SOURCE_FILES:.cpp=.o))\r
+#OBJECTS = $(SOURCES:.cpp=.o)\r
+\r
+FAST_TARGET = fasttest\r
+\r
+SERVER_TARGET = server\r
+SERVER_SOURCE_FILES = mapnode.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp servermain.cpp test.cpp\r
+SERVER_SOURCES = $(addprefix src/, $(SERVER_SOURCE_FILES))\r
+SERVER_BUILD_DIR = serverbuild\r
+SERVER_OBJECTS = $(addprefix $(SERVER_BUILD_DIR)/, $(SERVER_SOURCE_FILES:.cpp=.o))\r
+#SERVER_OBJECTS = $(SERVER_SOURCES:.cpp=.o)\r
\r
IRRLICHTPATH = ../irrlicht/irrlicht-1.7.1\r
JTHREADPATH = ../jthread/jthread-1.2.1\r
\r
-CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src\r
-\r
#CXXFLAGS = -O2 -ffast-math -Wall -fomit-frame-pointer -pipe\r
CXXFLAGS = -O2 -ffast-math -Wall -g -pipe\r
#CXXFLAGS = -O1 -ffast-math -Wall -g\r
#CXXFLAGS = -Wall -g -O0\r
\r
-#CXXFLAGS = -O3 -ffast-math -Wall\r
-#CXXFLAGS = -O3 -ffast-math -Wall -g\r
-#CXXFLAGS = -O2 -ffast-math -Wall -g\r
-\r
-FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686\r
-#FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686 -fwhole-program\r
+#FAST_CXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686\r
\r
#Default target\r
\r
# Target specific settings\r
\r
all_linux fast_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L$(IRRLICHTPATH)/lib/Linux -L$(JTHREADPATH)/src/.libs -lIrrlicht -lGL -lXxf86vm -lXext -lX11 -ljthread -lz\r
+all_linux fast_linux: CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src\r
+fast_linux server_linux: CXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686\r
+server_linux: LDFLAGS = -L$(JTHREADPATH)/src/.libs -ljthread -lz -lpthread\r
+server_linux: CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src -DSERVER\r
all_linux fast_linux clean_linux: SYSTEM=Linux\r
\r
+# These are out of date\r
all_win32: LDFLAGS = -L$(IRRLICHTPATH)/lib/Win32-gcc -L$(JTHREADPATH)/Debug -lIrrlicht -lopengl32 -lm -ljthread\r
all_win32 clean_win32: SYSTEM=Win32-gcc\r
all_win32 clean_win32: SUF=.exe\r
# Name of the binary - only valid for targets which set SYSTEM\r
\r
DESTPATH = bin/$(TARGET)$(SUF)\r
-FASTDESTPATH = bin/$(FASTTARGET)$(SUF)\r
+FAST_DESTPATH = bin/$(FAST_TARGET)$(SUF)\r
+SERVER_DESTPATH = bin/$(SERVER_TARGET)$(SUF)\r
\r
# Build commands\r
\r
-all_linux all_win32: $(DESTPATH)\r
-\r
-fast_linux: $(FASTDESTPATH)\r
+all_linux all_win32: make_build_dir $(DESTPATH)\r
+fast_linux: make_build_dir $(FAST_DESTPATH)\r
+server_linux: make_server_build_dir $(SERVER_DESTPATH)\r
\r
-$(FASTDESTPATH): $(SOURCES)\r
- $(CXX) -o $(FASTDESTPATH) $(SOURCES) $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE\r
- @# Errno doesn't work ("error: ‘__errno_location’ was not declared in this scope")\r
- @#cat $(SOURCES) | $(CXX) -o $(FASTDESTPATH) -x c++ - -Isrc/ $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE -DDISABLE_ERRNO\r
+make_build_dir:\r
+ mkdir -p $(BUILD_DIR)\r
+make_server_build_dir:\r
+ mkdir -p $(SERVER_BUILD_DIR)\r
\r
$(DESTPATH): $(OBJECTS)\r
$(CXX) -o $@ $(OBJECTS) $(LDFLAGS)\r
\r
-.cpp.o:\r
+$(FAST_DESTPATH): $(SOURCES)\r
+ $(CXX) -o $@ $(OBJECTS) $(LDFLAGS) -DUNITTEST_DISABLE\r
+\r
+$(SERVER_DESTPATH): $(SERVER_OBJECTS)\r
+ $(CXX) -o $@ $(SERVER_OBJECTS) $(LDFLAGS) -DSERVER -DUNITTEST_DISABLE\r
+\r
+$(BUILD_DIR)/%.o: src/%.cpp\r
$(CXX) -c -o $@ $< $(CPPFLAGS) $(CXXFLAGS)\r
\r
-clean: clean_linux clean_win32 clean_fast_linux\r
+$(SERVER_BUILD_DIR)/%.o: src/%.cpp\r
+ $(CXX) -c -o $@ $< $(CPPFLAGS) $(CXXFLAGS)\r
+\r
+clean: clean_linux clean_win32 clean_fast_linux clean_server_linux\r
\r
clean_linux clean_win32:\r
@$(RM) $(OBJECTS) $(DESTPATH)\r
\r
clean_fast_linux:\r
- @$(RM) $(FASTDESTPATH)\r
+ @$(RM) $(OBJECTS) $(FAST_DESTPATH)\r
+\r
+clean_server_linux:\r
+ @$(RM) $(SERVER_OBJECTS) $(SERVER_DESTPATH)\r
\r
-.PHONY: all all_win32 clean clean_linux clean_win32\r
+.PHONY: all all_win32 clean clean_linux clean_win32 clean_fast_linux clean_server_linux\r
return NULL;
}
-Client::Client(IrrlichtDevice *device,
- const char *playername):
+Client::Client(
+ IrrlichtDevice *device,
+ const char *playername,
+ JMutex &range_mutex,
+ s16 &viewing_range_nodes,
+ bool &viewing_range_all):
m_thread(this),
m_env(new ClientMap(this,
+ range_mutex,
+ viewing_range_nodes,
+ viewing_range_all,
device->getSceneManager()->getRootSceneNode(),
device->getSceneManager(), 666),
dout_client),
#ifndef CLIENT_HEADER
#define CLIENT_HEADER
+#ifndef SERVER
+
#include "connection.h"
#include "environment.h"
#include "common_irrlicht.h"
/*
NOTE: Every public method should be thread-safe
*/
- Client(IrrlichtDevice *device, const char *playername);
+ Client(
+ IrrlichtDevice *device,
+ const char *playername,
+ JMutex &range_mutex,
+ s16 &viewing_range_nodes,
+ bool &viewing_range_all
+ );
+
~Client();
/*
The name of the local player should already be set when
//u32 m_daynight_ratio;
};
-#endif
+#endif // !SERVER
+
+#endif // !CLIENT_HEADER
{
n.d = CONTENT_GRASS_FOOTSTEPS;
m_map->setNode(bottompos, n);
-
+#ifndef SERVER
// Update mesh on client
if(m_map->mapType() == MAPTYPE_CLIENT)
{
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
b->updateMesh(m_daynight_ratio);
}
+#endif
}
}
catch(InvalidPositionException &e)
{
DSTACK(__FUNCTION_NAME);
//Check that only one local player exists and peer_ids are unique
+#ifndef SERVER
assert(player->isLocal() == false || getLocalPlayer() == NULL);
+#endif
assert(getPlayer(player->peer_id) == NULL);
m_players.push_back(player);
}
}
}
+#ifndef SERVER
LocalPlayer * Environment::getLocalPlayer()
{
for(core::list<Player*>::Iterator i = m_players.begin();
}
return NULL;
}
+#endif
Player * Environment::getPlayer(u16 peer_id)
{
}
}
+#ifndef SERVER
void Environment::updateMeshes(v3s16 blockpos)
{
m_map->updateMeshes(blockpos, m_daynight_ratio);
{
m_map->expireMeshes(only_daynight_diffed);
}
+#endif
void Environment::setDayNightRatio(u32 r)
{
*/
void addPlayer(Player *player);
void removePlayer(u16 peer_id);
+#ifndef SERVER
LocalPlayer * getLocalPlayer();
+#endif
Player * getPlayer(u16 peer_id);
core::list<Player*> getPlayers();
void printPlayers(std::ostream &o);
+#ifndef SERVER
void updateMeshes(v3s16 blockpos);
void expireMeshes(bool only_daynight_diffed);
+#endif
void setDayNightRatio(u32 r);
u32 getDayNightRatio();
{
return new MaterialItem(m_content, m_count);
}
+#ifndef SERVER
video::ITexture * getImage()
{
/*if(m_content == CONTENT_TORCH)
return g_texturecache.get(g_content_inventory_textures[m_content]);
}
+#endif
std::string getText()
{
std::ostringstream os;
Create client\r
*/\r
\r
- Client client(device, playername);\r
+ Client client(device, playername,\r
+ g_range_mutex,\r
+ g_viewing_range_nodes,\r
+ g_viewing_range_all);\r
\r
Address connect_address(0,0,0,0, port);\r
try{\r
#include <jmutex.h>
-extern JMutex g_range_mutex;
-extern s16 g_viewing_range_nodes;
-//extern s16 g_actual_viewing_range_nodes;
-extern bool g_viewing_range_all;
-
// Settings
extern Settings g_settings;
#define dout_server (*dout_server_ptr)
#define derr_server (*derr_server_ptr)
-// TODO: Move somewhere else? materials.h?
-// This header is only for MATERIALS_COUNT
-//#include "mapnode.h"
-//extern video::SMaterial g_materials[MATERIALS_COUNT];
-
-#include "utility.h"
-extern TextureCache g_texturecache;
+#ifndef SERVER
+ #include "utility.h"
+ extern TextureCache g_texturecache;
+#endif
extern IrrlichtDevice *g_device;
}
}
+#ifndef SERVER
void Map::expireMeshes(bool only_daynight_diffed)
{
TimeTaker timer("expireMeshes()", g_device);
catch(InvalidPositionException &e){}
}
+#endif
+
bool Map::dayNightDiffed(v3s16 blockpos)
{
try{
out<<"ServerMap: ";
}
+#ifndef SERVER
+
/*
ClientMap
*/
ClientMap::ClientMap(
Client *client,
+ JMutex &range_mutex,
+ s16 &viewing_range_nodes,
+ bool &viewing_range_all,
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id
Map(dout_client),
scene::ISceneNode(parent, mgr, id),
m_client(client),
- mesh(NULL)
+ mesh(NULL),
+ m_range_mutex(range_mutex),
+ m_viewing_range_nodes(viewing_range_nodes),
+ m_viewing_range_all(viewing_range_all)
{
mesh_mutex.Init();
s16 viewing_range_nodes;
bool viewing_range_all;
{
- JMutexAutoLock lock(g_range_mutex);
- viewing_range_nodes = g_viewing_range_nodes;
- viewing_range_all = g_viewing_range_all;
+ JMutexAutoLock lock(m_range_mutex);
+ viewing_range_nodes = m_viewing_range_nodes;
+ viewing_range_all = m_viewing_range_all;
}
m_camera_mutex.Lock();
out<<"ClientMap: ";
}
+#endif // !SERVER
/*
MapVoxelManipulator
void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks);
+#ifndef SERVER
+ void expireMeshes(bool only_daynight_diffed);
+
/*
Updates the faces of the given block and blocks on the
leading edge.
*/
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
-
- void expireMeshes(bool only_daynight_diffed);
+#endif
/*
Takes the blocks at the trailing edges into account
bool m_map_saving_enabled;
};
+#ifndef SERVER
+
class Client;
class ClientMap : public Map, public scene::ISceneNode
public:
ClientMap(
Client *client,
+ JMutex &range_mutex,
+ s16 &viewing_range_nodes,
+ bool &viewing_range_all,
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id
// This is the master heightmap mesh
scene::SMesh *mesh;
JMutex mesh_mutex;
+
+ JMutex &m_range_mutex;
+ s16 &m_viewing_range_nodes;
+ bool &m_viewing_range_all;
};
+#endif
+
class MapVoxelManipulator : public VoxelManipulator
{
public:
m_pos(pos),
changed(true),
is_underground(false),
- m_mesh_expired(false),
m_day_night_differs(false),
m_objects(this)
{
if(dummy == false)
reallocate();
+#ifndef SERVER
+ m_mesh_expired = false;
mesh_mutex.Init();
-
mesh = NULL;
- /*for(s32 i=0; i<DAYNIGHT_CACHE_COUNT; i++)
- {
- mesh[i] = NULL;
- }*/
+#endif
}
MapBlock::~MapBlock()
{
+#ifndef SERVER
{
JMutexAutoLock lock(mesh_mutex);
mesh->drop();
mesh = NULL;
}
- /*for(s32 i=0; i<DAYNIGHT_CACHE_COUNT; i++)
- {
- if(mesh[i] != NULL)
- {
- mesh[i]->drop();
- mesh[i] = NULL;
- }
- }*/
}
+#endif
if(data)
delete[] data;
}
}
+/*
+ Parameters must consist of air and !air.
+ Order doesn't matter.
+
+ If either of the nodes doesn't exist, light is 0.
+
+ parameters:
+ daynight_ratio: 0...1000
+ n: getNodeParent(p)
+ n2: getNodeParent(p + face_dir)
+ face_dir: axis oriented unit vector from p to p2
+*/
+u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
+ v3s16 face_dir)
+{
+ try{
+ u8 light;
+ u8 l1 = n.getLightBlend(daynight_ratio);
+ u8 l2 = n2.getLightBlend(daynight_ratio);
+ if(l1 > l2)
+ light = l1;
+ else
+ light = l2;
+
+ // Make some nice difference to different sides
+
+ /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
+ light = diminish_light(diminish_light(light));
+ else if(face_dir.X == -1 || face_dir.Z == -1)
+ light = diminish_light(light);*/
+
+ if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
+ light = diminish_light(diminish_light(light));
+ else if(face_dir.Z == 1 || face_dir.Z == -1)
+ light = diminish_light(light);
+
+ return light;
+ }
+ catch(InvalidPositionException &e)
+ {
+ return 0;
+ }
+}
+
+#ifndef SERVER
+
void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
v3s16 dir, v3f scale, v3f posRelative_f,
core::array<FastFace> &dest)
//return f;
}
-/*
- Parameters must consist of air and !air.
- Order doesn't matter.
-
- If either of the nodes doesn't exist, light is 0.
-
- parameters:
- daynight_ratio: 0...1000
- n: getNodeParent(p)
- n2: getNodeParent(p + face_dir)
- face_dir: axis oriented unit vector from p to p2
-*/
-u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
- v3s16 face_dir)
-{
- try{
- u8 light;
- u8 l1 = n.getLightBlend(daynight_ratio);
- u8 l2 = n2.getLightBlend(daynight_ratio);
- if(l1 > l2)
- light = l1;
- else
- light = l2;
-
- // Make some nice difference to different sides
-
- /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
- light = diminish_light(diminish_light(light));
- else if(face_dir.X == -1 || face_dir.Z == -1)
- light = diminish_light(light);*/
-
- if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
- light = diminish_light(diminish_light(light));
- else if(face_dir.Z == 1 || face_dir.Z == -1)
- light = diminish_light(light);
-
- return light;
- }
- catch(InvalidPositionException &e)
- {
- return 0;
- }
-}
-
/*
Gets node tile from any place relative to block.
Returns TILE_NODE if doesn't exist or should not be drawn.
}
}*/
+#endif // !SERVER
+
/*
Propagates sunlight down through the block.
Doesn't modify nodes that are not affected by sunlight.
class MapBlock : public NodeContainer
{
public:
-
- //scene::SMesh *mesh[DAYNIGHT_CACHE_COUNT];
- scene::SMesh *mesh;
- JMutex mesh_mutex;
-
MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
~MapBlock();
{
changed = true;
}
-
+#ifndef SERVER
void setMeshExpired(bool expired)
{
m_mesh_expired = expired;
{
return m_mesh_expired;
}
-
+#endif
v3s16 getPos()
{
return m_pos;
setNode(x0+x, y0+y, z0+z, node);
}
- static void makeFastFace(TileSpec tile, u8 light, v3f p,
- v3s16 dir, v3f scale, v3f posRelative_f,
- core::array<FastFace> &dest);
-
u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
v3s16 face_dir);
face_dir);
}
+#ifndef SERVER
+ static void makeFastFace(TileSpec tile, u8 light, v3f p,
+ v3s16 dir, v3f scale, v3f posRelative_f,
+ core::array<FastFace> &dest);
+
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir);
u8 getNodeContent(v3s16 p, MapNode mn);
/*void updateMesh(s32 daynight_i);
// Updates all DAYNIGHT_CACHE_COUNT meshes
void updateMeshes(s32 first_i=0);*/
+#endif // !SERVER
bool propagateSunlight(core::map<v3s16, bool> & light_sources);
{
return m_objects.getCount();
}
-
+
+#ifndef SERVER
/*
Methods for setting temporary modifications to nodes for
drawing
{
m_temp_mods.clear();
}
+#endif
/*
Day-night lighting difference
void deSerialize(std::istream &is, u8 version);
+ /*
+ Public member variables
+ */
+
+#ifndef SERVER
+ //scene::SMesh *mesh[DAYNIGHT_CACHE_COUNT];
+ scene::SMesh *mesh;
+ JMutex mesh_mutex;
+#endif
+
private:
/*
/*
Used for some initial lighting stuff.
At least /has been/ used. 8)
+ It's probably useless now.
*/
bool is_underground;
-
- bool m_mesh_expired;
// Whether day and night lighting differs
bool m_day_night_differs;
MapBlockObjectList m_objects;
+#ifndef SERVER
+ bool m_mesh_expired;
+
// Temporary modifications to nodes
// These are only used when drawing
core::map<v3s16, NodeMod> m_temp_mods;
+#endif
};
inline bool blockpos_over_limit(v3s16 p)
// A return value of true requests deletion of the object by the caller.
// NOTE: Only server calls this.
virtual bool serverStep(float dtime) { return false; };
+
+#ifdef SERVER
+ void clientStep(float dtime) {};
+ void addToScene(void *smgr) {};
+ void removeFromScene() {};
+#else
// This should do slight animations only or so
virtual void clientStep(float dtime) {};
// Should return silently if there is nothing to remove
// NOTE: This has to be called before calling destructor
virtual void removeFromScene() {};
+#endif
virtual std::string infoText() { return ""; }
virtual bool serverStep(float dtime) { return false; };
virtual void clientStep(float dtime) {};
- virtual void addToScene(scene::ISceneManager *smgr) = 0;
- virtual void removeFromScene() = 0;
+ /*virtual void addToScene(scene::ISceneManager *smgr) = 0;
+ virtual void removeFromScene() = 0;*/
/*
Special methods
return false;
}
-
+#ifndef SERVER
virtual void clientStep(float dtime)
{
m_pos += m_speed * dtime;
m_node = NULL;
}
}
+#endif
virtual std::string getInventoryString()
{
{
return false;
}
+#ifndef SERVER
virtual void addToScene(scene::ISceneManager *smgr)
{
if(m_node != NULL)
m_node = NULL;
}
}
+#endif
virtual std::string infoText()
{
/*
Special methods
*/
-
void updateSceneNode()
{
+#ifndef SERVER
if(m_node != NULL)
{
m_node->setPosition(getAbsolutePos());
m_node->setRotation(v3f(0, m_yaw, 0));
}
+#endif
}
void setText(std::string text)
return sector;
}
+#ifndef SERVER
/*
ClientMapSector
*/
m_corners[2] = c2;
m_corners[3] = c3;
}
+#endif // !SERVER
//END
core::map<v3s16, u8> *m_objects;
};
+#ifndef SERVER
class ClientMapSector : public MapSector
{
public:
// The ground height of the corners is stored in here
s16 m_corners[4];
};
+#endif
#endif
RemotePlayer
*/
+#ifndef SERVER
+
RemotePlayer::RemotePlayer(
scene::ISceneNode* parent,
IrrlichtDevice *device,
m_text(NULL)
{
m_box = core::aabbox3d<f32>(-BS/2,0,-BS/2,BS/2,BS*2,BS/2);
-
+
if(parent != NULL && device != NULL)
{
// ISceneNode stores a member called SceneManager
}
}
+#endif
+
+#ifndef SERVER
/*
LocalPlayer
*/
// Accelerate to target speed with maximum increment
accelerate(speed, inc);
}
-
+#endif
v3f m_position;
};
+class ServerRemotePlayer : public Player
+{
+public:
+ ServerRemotePlayer()
+ {
+ }
+ virtual ~ServerRemotePlayer()
+ {
+ }
+
+ bool isLocal() const
+ {
+ return false;
+ }
+
+private:
+};
+
+#ifndef SERVER
+
class RemotePlayer : public Player, public scene::ISceneNode
{
public:
core::aabbox3d<f32> m_box;
};
+#endif
+
+#ifndef SERVER
struct PlayerControl
{
PlayerControl()
private:
};
+#endif // !SERVER
#endif
// The player shouldn't already exist
assert(player == NULL);
- player = new RemotePlayer();
+ player = new ServerRemotePlayer();
player->peer_id = peer->id;
/*
--- /dev/null
+/*
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+=============================== NOTES ==============================
+
+TODO: Move the default settings into some separate file
+
+*/
+
+#ifndef SERVER
+ #ifdef _WIN32
+ #else
+ #error "For a server build, SERVER must be defined globally"
+ #endif
+#endif
+
+#ifdef UNITTEST_DISABLE
+ #ifdef _WIN32
+ #pragma message ("Disabling unit tests")
+ #else
+ #warning "Disabling unit tests"
+ #endif
+ // Disable unit tests
+ #define ENABLE_TESTS 0
+#else
+ // Enable unit tests
+ #define ENABLE_TESTS 1
+#endif
+
+#ifdef _MSC_VER
+#pragma comment(lib, "jthread.lib")
+#pragma comment(lib, "zlibwapi.lib")
+#endif
+
+#ifdef _WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+ #define sleep_ms(x) Sleep(x)
+#else
+ #include <unistd.h>
+ #define sleep_ms(x) usleep(x*1000)
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <time.h>
+#include <jmutexautolock.h>
+#include <locale.h>
+#include "common_irrlicht.h"
+#include "debug.h"
+#include "map.h"
+#include "player.h"
+#include "main.h"
+#include "test.h"
+#include "environment.h"
+#include "server.h"
+#include "serialization.h"
+#include "constants.h"
+#include "strfnd.h"
+#include "porting.h"
+
+// Dummy variable
+IrrlichtDevice *g_device = NULL;
+
+/*
+ Settings.
+ These are loaded from the config file.
+*/
+
+Settings g_settings;
+
+// Sets default settings
+void set_default_settings()
+{
+ // Client stuff
+ g_settings.setDefault("wanted_fps", "30");
+ g_settings.setDefault("fps_max", "60");
+ g_settings.setDefault("viewing_range_nodes_max", "300");
+ g_settings.setDefault("viewing_range_nodes_min", "35");
+ g_settings.setDefault("screenW", "");
+ g_settings.setDefault("screenH", "");
+ g_settings.setDefault("host_game", "");
+ g_settings.setDefault("port", "");
+ g_settings.setDefault("address", "");
+ g_settings.setDefault("name", "");
+ g_settings.setDefault("random_input", "false");
+ g_settings.setDefault("client_delete_unused_sectors_timeout", "1200");
+ g_settings.setDefault("enable_fog", "true");
+
+ // Server stuff
+ g_settings.setDefault("creative_mode", "false");
+ g_settings.setDefault("heightmap_blocksize", "32");
+ g_settings.setDefault("height_randmax", "constant 50.0");
+ g_settings.setDefault("height_randfactor", "constant 0.6");
+ g_settings.setDefault("height_base", "linear 0 0 0");
+ g_settings.setDefault("plants_amount", "1.0");
+ g_settings.setDefault("ravines_amount", "1.0");
+ g_settings.setDefault("objectdata_interval", "0.2");
+ g_settings.setDefault("active_object_range", "2");
+ g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
+ g_settings.setDefault("max_simultaneous_block_sends_server_total", "4");
+ g_settings.setDefault("disable_water_climb", "true");
+ g_settings.setDefault("endless_water", "true");
+ g_settings.setDefault("max_block_send_distance", "5");
+ g_settings.setDefault("max_block_generate_distance", "4");
+}
+
+/*
+ Debug streams
+*/
+
+// Connection
+std::ostream *dout_con_ptr = &dummyout;
+std::ostream *derr_con_ptr = &dstream_no_stderr;
+
+// Server
+std::ostream *dout_server_ptr = &dstream;
+std::ostream *derr_server_ptr = &dstream;
+
+// Client
+std::ostream *dout_client_ptr = &dstream;
+std::ostream *derr_client_ptr = &dstream;
+
+
+/*
+ Timestamp stuff
+*/
+
+JMutex g_timestamp_mutex;
+
+std::string getTimestamp()
+{
+ if(g_timestamp_mutex.IsInitialized()==false)
+ return "";
+ JMutexAutoLock lock(g_timestamp_mutex);
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&t);
+ char cs[20];
+ strftime(cs, 20, "%H:%M:%S", tm);
+ return cs;
+}
+
+int main(int argc, char *argv[])
+{
+ /*
+ Low-level initialization
+ */
+
+ bool disable_stderr = false;
+#ifdef _WIN32
+ disable_stderr = true;
+#endif
+
+ // Initialize debug streams
+ debugstreams_init(disable_stderr, DEBUGFILE);
+ // Initialize debug stacks
+ debug_stacks_init();
+
+ DSTACK(__FUNCTION_NAME);
+
+ try
+ {
+
+ /*
+ Parse command line
+ */
+
+ // List all allowed options
+ core::map<std::string, ValueSpec> allowed_options;
+ allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));
+ allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,
+ "Load configuration from specified file"));
+ allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));
+ allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));
+ allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));
+
+ Settings cmd_args;
+
+ bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);
+
+ if(ret == false || cmd_args.getFlag("help"))
+ {
+ dstream<<"Allowed options:"<<std::endl;
+ for(core::map<std::string, ValueSpec>::Iterator
+ i = allowed_options.getIterator();
+ i.atEnd() == false; i++)
+ {
+ dstream<<" --"<<i.getNode()->getKey();
+ if(i.getNode()->getValue().type == VALUETYPE_FLAG)
+ {
+ }
+ else
+ {
+ dstream<<" <value>";
+ }
+ dstream<<std::endl;
+
+ if(i.getNode()->getValue().help != NULL)
+ {
+ dstream<<" "<<i.getNode()->getValue().help
+ <<std::endl;
+ }
+ }
+
+ return cmd_args.getFlag("help") ? 0 : 1;
+ }
+
+
+ /*
+ Basic initialization
+ */
+
+ // Initialize default settings
+ set_default_settings();
+
+ // Print startup message
+ dstream<<DTIME<<"minetest-c55 server"
+ " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
+ <<", ENABLE_TESTS="<<ENABLE_TESTS
+ <<std::endl;
+
+ // Set locale. This is for forcing '.' as the decimal point.
+ std::locale::global(std::locale("C"));
+ // This enables printing all characters in bitmap font
+ setlocale(LC_CTYPE, "en_US");
+
+ // Initialize sockets
+ sockets_init();
+ atexit(sockets_cleanup);
+
+ // Initialize timestamp mutex
+ g_timestamp_mutex.Init();
+
+ /*
+ Initialization
+ */
+
+ /*
+ Read config file
+ */
+
+ // Path of configuration file in use
+ std::string configpath = "";
+
+ if(cmd_args.exists("config"))
+ {
+ bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());
+ if(r == false)
+ {
+ dstream<<"Could not read configuration from \""
+ <<cmd_args.get("config")<<"\""<<std::endl;
+ return 1;
+ }
+ configpath = cmd_args.get("config");
+ }
+ else
+ {
+ const char *filenames[2] =
+ {
+ "../minetest.conf",
+ "../../minetest.conf"
+ };
+
+ for(u32 i=0; i<2; i++)
+ {
+ bool r = g_settings.readConfigFile(filenames[i]);
+ if(r)
+ {
+ configpath = filenames[i];
+ break;
+ }
+ }
+ }
+
+ // Initialize random seed
+ srand(time(0));
+
+ /*
+ Run unit tests
+ */
+ if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
+ || cmd_args.getFlag("enable-unittests") == true)
+ {
+ run_tests();
+ }
+
+ // Read map parameters from settings
+
+ HMParams hm_params;
+ hm_params.blocksize = g_settings.getU16("heightmap_blocksize");
+ hm_params.randmax = g_settings.get("height_randmax");
+ hm_params.randfactor = g_settings.get("height_randfactor");
+ hm_params.base = g_settings.get("height_base");
+
+ MapParams map_params;
+ map_params.plants_amount = g_settings.getFloat("plants_amount");
+ map_params.ravines_amount = g_settings.getFloat("ravines_amount");
+
+ /*
+ Check parameters
+ */
+
+ std::cout<<std::endl<<std::endl;
+
+ std::cout
+ <<" .__ __ __ "<<std::endl
+ <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
+ <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
+ <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
+ <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
+ <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl
+ <<std::endl
+ <<"Now with more waterish water!"
+ <<std::endl;
+
+ std::cout<<std::endl;
+
+ // Port?
+ u16 port = 30000;
+ if(cmd_args.exists("port"))
+ {
+ port = cmd_args.getU16("port");
+ }
+ else if(g_settings.exists("port"))
+ {
+ port = g_settings.getU16("port");
+ }
+ else
+ {
+ dstream<<"Please specify port (in config or on command line)"
+ <<std::endl;
+ }
+
+ DSTACK("Dedicated server branch");
+
+ std::cout<<std::endl;
+ std::cout<<"========================"<<std::endl;
+ std::cout<<"Running dedicated server"<<std::endl;
+ std::cout<<"========================"<<std::endl;
+ std::cout<<std::endl;
+
+ Server server("../map", hm_params, map_params);
+ server.start(port);
+
+ for(;;)
+ {
+ // This is kind of a hack but can be done like this
+ // because server.step() is very light
+ sleep_ms(30);
+ server.step(0.030);
+
+ static int counter = 0;
+ counter--;
+ if(counter <= 0)
+ {
+ counter = 10;
+
+ core::list<PlayerInfo> list = server.getPlayerInfo();
+ core::list<PlayerInfo>::Iterator i;
+ static u32 sum_old = 0;
+ u32 sum = PIChecksum(list);
+ if(sum != sum_old)
+ {
+ std::cout<<DTIME<<"Player info:"<<std::endl;
+ for(i=list.begin(); i!=list.end(); i++)
+ {
+ i->PrintLine(&std::cout);
+ }
+ }
+ sum_old = sum;
+ }
+ }
+
+ /*
+ Update configuration file
+ */
+ if(configpath != "")
+ {
+ g_settings.updateConfigFile(configpath.c_str());
+ }
+
+ } //try
+ catch(con::PeerNotFoundException &e)
+ {
+ dstream<<DTIME<<"Connection timed out."<<std::endl;
+ }
+#if CATCH_UNHANDLED_EXCEPTIONS
+ /*
+ This is what has to be done in every thread to get suitable debug info
+ */
+ catch(std::exception &e)
+ {
+ dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "
+ <<e.what()<<std::endl;
+ assert(0);
+ }
+#endif
+
+ debugstreams_deinit();
+
+ return 0;
+}
+
+//END