diff --git a/data/grass.png b/data/grass.png
index 88336c013..8fe9078ca 100644
Binary files a/data/grass.png and b/data/grass.png differ
diff --git a/data/grass_side.png b/data/grass_side.png
index ee12491e8..7bacbfb5e 100644
Binary files a/data/grass_side.png and b/data/grass_side.png differ
diff --git a/minetest.vcproj b/minetest.vcproj
index 71dc5763a..68c6fced7 100644
--- a/minetest.vcproj
+++ b/minetest.vcproj
@@ -271,6 +271,10 @@
RelativePath=".\src\materials.cpp"
>
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7913f4964..d027c7cd9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -38,18 +38,12 @@ configure_file(
"${PROJECT_BINARY_DIR}/cmake_config.h"
)
-set(minetest_SRCS
- guiMainMenu.cpp
+set(common_SRCS
+ mineral.cpp
porting.cpp
- guiMessageMenu.cpp
materials.cpp
- guiTextInputMenu.cpp
- guiInventoryMenu.cpp
- irrlichtwrapper.cpp
- guiPauseMenu.cpp
defaultsettings.cpp
mapnode.cpp
- tile.cpp
voxel.cpp
mapblockobject.cpp
inventory.cpp
@@ -59,7 +53,6 @@ set(minetest_SRCS
filesys.cpp
connection.cpp
environment.cpp
- client.cpp
server.cpp
socket.cpp
mapblock.cpp
@@ -68,34 +61,24 @@ set(minetest_SRCS
map.cpp
player.cpp
utility.cpp
- main.cpp
test.cpp
)
+set(minetest_SRCS
+ ${common_SRCS}
+ guiMainMenu.cpp
+ guiMessageMenu.cpp
+ guiTextInputMenu.cpp
+ guiInventoryMenu.cpp
+ guiPauseMenu.cpp
+ irrlichtwrapper.cpp
+ client.cpp
+ main.cpp
+)
+
set(minetestserver_SRCS
- porting.cpp
- materials.cpp
- defaultsettings.cpp
- 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
+ ${common_SRCS}
servermain.cpp
- test.cpp
)
include_directories(
diff --git a/src/environment.cpp b/src/environment.cpp
index 51ed05422..9d64ff58a 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "environment.h"
+#include "filesys.h"
Environment::Environment(Map *map, std::ostream &dout):
m_dout(dout)
@@ -192,6 +193,7 @@ void Environment::addPlayer(Player *player)
DSTACK(__FUNCTION_NAME);
/*
Check that only one local player exists and peer_ids are unique.
+ Also check that names are unique.
Exception: there can be multiple players with peer_id=0
*/
#ifndef SERVER
@@ -201,8 +203,12 @@ void Environment::addPlayer(Player *player)
*/
assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
#endif
+ // If peer id is non-zero, it has to be unique.
if(player->peer_id != 0)
assert(getPlayer(player->peer_id) == NULL);
+ // Name has to be unique.
+ assert(getPlayer(player->getName()) == NULL);
+ // Add.
m_players.push_back(player);
}
@@ -300,6 +306,181 @@ void Environment::printPlayers(std::ostream &o)
}
}
+void Environment::serializePlayers(const std::string &savedir)
+{
+ std::string players_path = savedir + "/players";
+ fs::CreateDir(players_path);
+
+ core::map saved_players;
+
+ std::vector player_files = fs::GetDirListing(players_path);
+ for(u32 i=0; iserialize(os);
+ saved_players.insert(player, true);
+ }
+ }
+
+ for(core::list::Iterator i = m_players.begin();
+ i != m_players.end(); i++)
+ {
+ Player *player = *i;
+ if(saved_players.find(player) != NULL)
+ {
+ dstream<<"Player "<getName()
+ <<" was already saved."<getName();
+ // Don't save unnamed player
+ if(playername == "")
+ {
+ dstream<<"Not saving unnamed player."<getName()<<" to "
+ <serialize(os);
+ saved_players.insert(player, true);
+ }
+ }
+}
+
+void Environment::deSerializePlayers(const std::string &savedir)
+{
+ std::string players_path = savedir + "/players";
+
+ core::map saved_players;
+
+ std::vector player_files = fs::GetDirListing(players_path);
+ for(u32 i=0; ideSerialize(is);
+ }
+
+ if(newplayer)
+ addPlayer(player);
+ }
+}
+
#ifndef SERVER
void Environment::updateMeshes(v3s16 blockpos)
{
diff --git a/src/environment.h b/src/environment.h
index fa7253170..dfc60673b 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -63,6 +63,10 @@ public:
core::list getPlayers();
core::list getPlayers(bool ignore_disconnected);
void printPlayers(std::ostream &o);
+
+ void serializePlayers(const std::string &savedir);
+ // This loads players as ServerRemotePlayers
+ void deSerializePlayers(const std::string &savedir);
#ifndef SERVER
void updateMeshes(v3s16 blockpos);
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 713adefdf..cbe66edb0 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -217,7 +217,7 @@ void InventoryList::serialize(std::ostream &os)
os<<"\n";
}
- os<<"end\n";
+ os<<"EndInventoryList\n";
}
void InventoryList::deSerialize(std::istream &is)
@@ -238,7 +238,7 @@ void InventoryList::deSerialize(std::istream &is)
std::string name;
std::getline(iss, name, ' ');
- if(name == "end")
+ if(name == "EndInventoryList")
{
break;
}
@@ -497,7 +497,7 @@ void Inventory::serialize(std::ostream &os)
list->serialize(os);
}
- os<<"end\n";
+ os<<"EndInventory\n";
}
void Inventory::deSerialize(std::istream &is)
@@ -514,7 +514,7 @@ void Inventory::deSerialize(std::istream &is)
std::string name;
std::getline(iss, name, ' ');
- if(name == "end")
+ if(name == "EndInventory")
{
break;
}
diff --git a/src/inventory.h b/src/inventory.h
index 797a67509..e7c7adaee 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -122,10 +122,12 @@ public:
#ifndef SERVER
video::ITexture * getImage()
{
- if(m_content >= USEFUL_CONTENT_COUNT)
+ /*if(m_content >= USEFUL_CONTENT_COUNT)
return NULL;
- return g_irrlicht->getTexture(g_content_inventory_texture_paths[m_content]);
+ return g_irrlicht->getTexture(g_content_inventory_texture_paths[m_content]);*/
+
+ return g_irrlicht->getTexture(content_features(m_content).inventory_texture);
}
#endif
std::string getText()
@@ -250,19 +252,19 @@ public:
#ifndef SERVER
video::ITexture * getImage()
{
- std::string basename;
+ std::string name;
if(m_subname == "Stick")
- basename = porting::getDataPath("stick.png");
+ name = "stick.png";
else if(m_subname == "lump_of_coal")
- basename = porting::getDataPath("lump_of_coal.png");
+ name = "lump_of_coal.png";
else if(m_subname == "lump_of_iron")
- basename = porting::getDataPath("lump_of_iron.png");
+ name = "lump_of_iron.png";
else
- basename = porting::getDataPath("cloud.png[[mod:crack3");
+ name = "cloud.png";
// Get such a texture
- return g_irrlicht->getTexture(basename);
+ return g_irrlicht->getTexture(name);
}
#endif
std::string getText()
@@ -330,28 +332,35 @@ public:
{
std::string basename;
if(m_toolname == "WPick")
- basename = porting::getDataPath("tool_wpick.png").c_str();
+ basename = "tool_wpick.png";
else if(m_toolname == "STPick")
- basename = porting::getDataPath("tool_stpick.png").c_str();
+ basename = "tool_stpick.png";
else if(m_toolname == "MesePick")
- basename = porting::getDataPath("tool_mesepick.png").c_str();
- // Default to cloud texture
+ basename = "tool_mesepick.png";
else
- basename = porting::getDataPath("cloud.png").c_str();
- //basename = tile_texture_path_get(TILE_CLOUD);
+ basename = "cloud.png";
/*
- Calculate some progress value with sane amount of
+ Calculate a progress value with sane amount of
maximum states
*/
u32 maxprogress = 30;
u32 toolprogress = (65535-m_wear)/(65535/maxprogress);
- // Make texture name for the new texture with a progress bar
+ float value_f = (float)toolprogress / (float)maxprogress;
+ std::ostringstream os;
+ os<<"[progressbar"<getTextureId(basename));
+ spec.addTid(g_irrlicht->getTextureId(os.str()));
+ return g_irrlicht->getTexture(spec);
+
+ /*// Make texture name for the new texture with a progress bar
float value_f = (float)toolprogress / (float)maxprogress;
std::ostringstream os;
os<getTexture(os.str());
+ return g_irrlicht->getTexture(os.str());*/
/*// Make texture name for the new texture with a progress bar
std::ostringstream os;
diff --git a/src/irrlichtwrapper.cpp b/src/irrlichtwrapper.cpp
index 4e1ebdd74..e5cab98c6 100644
--- a/src/irrlichtwrapper.cpp
+++ b/src/irrlichtwrapper.cpp
@@ -17,13 +17,15 @@ void IrrlichtWrapper::Run()
*/
if(m_get_texture_queue.size() > 0)
{
- GetRequest
+ GetRequest
request = m_get_texture_queue.pop();
- dstream<<"got texture request with key="
- <
+ GetResult
result;
result.key = request.key;
result.callers = request.callers;
@@ -33,9 +35,29 @@ void IrrlichtWrapper::Run()
}
}
-video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec)
+textureid_t IrrlichtWrapper::getTextureId(const std::string &name)
{
- if(spec == "")
+ u32 id = m_namecache.getId(name);
+ return id;
+}
+
+std::string IrrlichtWrapper::getTextureName(textureid_t id)
+{
+ std::string name("");
+ m_namecache.getValue(id, name);
+ // In case it was found, return the name; otherwise return an empty name.
+ return name;
+}
+
+video::ITexture* IrrlichtWrapper::getTexture(const std::string &name)
+{
+ TextureSpec spec(getTextureId(name));
+ return getTexture(spec);
+}
+
+video::ITexture* IrrlichtWrapper::getTexture(const TextureSpec &spec)
+{
+ if(spec.empty())
return NULL;
video::ITexture *t = m_texturecache.get(spec);
@@ -44,26 +66,26 @@ video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec)
if(get_current_thread_id() == m_main_thread)
{
- dstream<<"Getting texture directly: spec="
- < result_queue;
+ ResultQueue result_queue;
// Throw a request in
m_get_texture_queue.add(spec, 0, 0, &result_queue);
- dstream<<"Waiting for texture from main thread: "
- <
+ GetResult
result = result_queue.pop_front(1000);
// Check that at least something worked OK
@@ -83,144 +105,177 @@ video::ITexture* IrrlichtWrapper::getTexture(const std::string &spec)
return t;
}
-/*
- Non-thread-safe functions
-*/
+// Draw a progress bar on the image
+void make_progressbar(float value, video::IImage *image);
/*
- Texture modifier functions
+ Texture fetcher/maker function, called always from the main thread
*/
-// blitted_name = eg. "mineral_coal.png"
-video::ITexture * make_blitname(const std::string &blitted_name,
- video::ITexture *original,
- const char *newname, video::IVideoDriver* driver)
+video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
{
- if(original == NULL)
+ // This would result in NULL image
+ if(spec.empty())
return NULL;
- // Size of the base image
- core::dimension2d dim(16, 16);
- // Position to copy the blitted to in the base image
- core::position2d pos_base(0, 0);
- // Position to copy the blitted from in the blitted image
- core::position2d pos_other(0, 0);
+ // Don't generate existing stuff
+ video::ITexture *t = m_texturecache.get(spec);
+ if(t != NULL)
+ {
+ dstream<<"WARNING: Existing stuff requested from "
+ "getTextureDirect()"<getVideoDriver();
- video::IImage *baseimage = driver->createImage(original, pos_base, dim);
- assert(baseimage);
+ /*
+ An image will be built from files and then converted into a texture.
+ */
+ video::IImage *baseimg = NULL;
- video::IImage *blittedimage = driver->createImageFromFile(porting::getDataPath(blitted_name.c_str()).c_str());
- assert(blittedimage);
+ /*
+ Irrlicht requires a name for every texture, with which it
+ will be stored internally in irrlicht.
+ */
+ std::string texture_name;
+
+ for(u32 i=0; icreateImageFromFile(path.c_str());
+
+ if(image == NULL)
+ {
+ dstream<<"WARNING: Could not load image \""<createImage(video::ECF_A8R8G8B8, image);
+ core::dimension2d dim = image->getDimension();
+ baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
+ image->copyTo(baseimg);
+ image->drop();
+ //baseimg = image;
+ }
+ // Else blit on base.
+ else
+ {
+ dstream<<"Blitting "< dim = image->getDimension();
+ //core::dimension2d dim(16,16);
+ // Position to copy the blitted to in the base image
+ core::position2d pos_to(0,0);
+ // Position to copy the blitted from in the blitted image
+ core::position2d pos_from(0,0);
+ // Blit
+ image->copyToWithAlpha(baseimg, pos_to,
+ core::rect(pos_from, dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ // Drop image
+ image->drop();
+ }
+ }
+ else
+ {
+ // A special texture modification
+ dstream<<"getTextureDirect(): generating \""< dim(16, 16);
+ // Size of the crack image
+ //core::dimension2d dim_crack(16, 16 * CRACK_ANIMATION_LENGTH);
+ // Position to copy the crack to in the base image
+ core::position2d pos_base(0, 0);
+ // Position to copy the crack from in the crack image
+ core::position2d pos_other(0, 16 * progression);
+
+ video::IImage *crackimage = driver->createImageFromFile(
+ porting::getDataPath("crack.png").c_str());
+ crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
+ core::rect(pos_other, dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ crackimage->drop();
+ }
+ else if(name.substr(0,12) == "[progressbar")
+ {
+ float value = stof(name.substr(12));
+ make_progressbar(value, baseimg);
+ }
+ else
+ {
+ dstream<<"WARNING: getTextureDirect(): Invalid "
+ " texture: \""<copyToWithAlpha(baseimage, v2s32(0,0),
- core::rect(pos_other, dim),
- video::SColor(255,255,255,255),
- NULL);
-
- blittedimage->drop();
+ /*// DEBUG: Paint some pixels
+ video::SColor c(255,255,0,0);
+ baseimg->setPixel(1,1, c);
+ baseimg->setPixel(1,14, c);
+ baseimg->setPixel(14,1, c);
+ baseimg->setPixel(14,14, c);*/
// Create texture from resulting image
+ t = driver->addTexture(texture_name.c_str(), baseimg);
+ baseimg->drop();
- video::ITexture *newtexture = driver->addTexture(newname, baseimage);
+ dstream<<"getTextureDirect(): created texture \""<drop();
+ return t;
- return newtexture;
}
-video::ITexture * make_crack(u16 progression, video::ITexture *original,
- const char *newname, video::IVideoDriver* driver)
+void make_progressbar(float value, video::IImage *image)
{
- if(original == NULL)
- return NULL;
+ if(image == NULL)
+ return;
- // Size of the base image
- core::dimension2d dim(16, 16);
- // Size of the crack image
- //core::dimension2d dim_crack(16, 16 * CRACK_ANIMATION_LENGTH);
- // Position to copy the crack to in the base image
- core::position2d pos_base(0, 0);
- // Position to copy the crack from in the crack image
- core::position2d pos_other(0, 16 * progression);
-
- video::IImage *baseimage = driver->createImage(original, pos_base, dim);
- assert(baseimage);
-
- video::IImage *crackimage = driver->createImageFromFile(porting::getDataPath("crack.png").c_str());
- assert(crackimage);
-
- // Then copy the right part of crackimage to baseimage
-
- crackimage->copyToWithAlpha(baseimage, v2s32(0,0),
- core::rect(pos_other, dim),
- video::SColor(255,255,255,255),
- NULL);
-
- crackimage->drop();
-
- // Create texture from resulting image
-
- video::ITexture *newtexture = driver->addTexture(newname, baseimage);
-
- baseimage->drop();
-
- return newtexture;
-}
-
-#if 0
-video::ITexture * make_sidegrass(video::ITexture *original,
- const char *newname, video::IVideoDriver* driver)
-{
- if(original == NULL)
- return NULL;
-
- // Size of the base image
- core::dimension2d dim(16, 16);
- // Position to copy the grass to in the base image
- core::position2d pos_base(0, 0);
- // Position to copy the grass from in the grass image
- core::position2d pos_other(0, 0);
-
- video::IImage *baseimage = driver->createImage(original, pos_base, dim);
- assert(baseimage);
-
- video::IImage *grassimage = driver->createImageFromFile(porting::getDataPath("grass_side.png").c_str());
- assert(grassimage);
-
- // Then copy the right part of grassimage to baseimage
-
- grassimage->copyToWithAlpha(baseimage, v2s32(0,0),
- core::rect(pos_other, dim),
- video::SColor(255,255,255,255),
- NULL);
-
- grassimage->drop();
-
- // Create texture from resulting image
-
- video::ITexture *newtexture = driver->addTexture(newname, baseimage);
-
- baseimage->drop();
-
- return newtexture;
-}
-#endif
-
-video::ITexture * make_progressbar(float value, video::ITexture *original,
- const char *newname, video::IVideoDriver* driver)
-{
- if(original == NULL)
- return NULL;
-
- core::position2d pos_base(0, 0);
- core::dimension2d dim = original->getOriginalSize();
-
- video::IImage *baseimage = driver->createImage(original, pos_base, dim);
- assert(baseimage);
-
- core::dimension2d size = baseimage->getDimension();
+ core::dimension2d size = image->getDimension();
u32 barheight = 1;
u32 barpad_x = 1;
@@ -242,177 +297,9 @@ video::ITexture * make_progressbar(float value, video::ITexture *original,
u32 x = x0 + barpos.X;
for(u32 y=barpos.Y; ysetPixel(x,y, *c);
+ image->setPixel(x,y, *c);
}
}
-
- video::ITexture *newtexture = driver->addTexture(newname, baseimage);
-
- baseimage->drop();
-
- return newtexture;
-}
-
-/*
- Texture fetcher/maker function, called always from the main thread
-*/
-
-video::ITexture* IrrlichtWrapper::getTextureDirect(const std::string &spec)
-{
- if(spec == "")
- return NULL;
-
- video::IVideoDriver* driver = m_device->getVideoDriver();
-
- /*
- Input (spec) is something like this:
- "/usr/share/minetest/stone.png[[mod:mineral0[[mod:crack3"
- */
-
- video::ITexture* t = NULL;
- std::string modmagic = "[[mod:";
- Strfnd f(spec);
- std::string path = f.next(modmagic);
- t = driver->getTexture(path.c_str());
- std::string texture_name = path;
- while(f.atend() == false)
- {
- std::string mod = f.next(modmagic);
- texture_name += modmagic + mod;
- dstream<<"Making texture \""<= spec.size())
- {
- strcache[length] = '\0';
- // Now our string is in strcache, ending in \0
-
- if(readmode == READMODE_PATH)
- {
- // Get initial texture (strcache is path)
- assert(t == NULL);
- t = driver->getTexture(strcache);
- readmode = READMODE_MOD;
- path = strcache;
- strcache = (char*)malloc(specsize);
- assert(strcache);
- }
- else
- {
- dstream<<"Parsing mod \""<= spec.size())
- break;
- }
-
- /*if(spec.mod == NULL)
- {
- dstream<<"IrrlichtWrapper::getTextureDirect: Loading texture "
- <getTexture(spec.path.c_str());
- }
-
- dstream<<"IrrlichtWrapper::getTextureDirect: Loading and modifying "
- "texture "<getTexture(spec.path.c_str());
- video::ITexture *result = spec.mod->make(base, spec.name.c_str(), driver);
-
- delete spec.mod;*/
-
- if(strcache)
- free(strcache);
- if(path)
- free(path);
-
- return t;
-#endif
}
diff --git a/src/irrlichtwrapper.h b/src/irrlichtwrapper.h
index 2506af012..a695bd1e4 100644
--- a/src/irrlichtwrapper.h
+++ b/src/irrlichtwrapper.h
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include "debug.h"
#include "utility.h"
+#include "texture.h"
#include
#include
@@ -36,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
threads, because texture pointers have to be handled in
background threads.
*/
-
+#if 0
class TextureCache
{
public:
@@ -73,12 +74,55 @@ private:
core::map m_textures;
JMutex m_mutex;
};
+#endif
+
+/*
+ A thread-safe texture pointer cache
+*/
+class TextureCache
+{
+public:
+ TextureCache()
+ {
+ m_mutex.Init();
+ assert(m_mutex.IsInitialized());
+ }
+
+ void set(const TextureSpec &spec, video::ITexture *texture)
+ {
+ if(texture == NULL)
+ return;
+
+ JMutexAutoLock lock(m_mutex);
+
+ m_textures[spec] = texture;
+ }
+
+ video::ITexture* get(const TextureSpec &spec)
+ {
+ JMutexAutoLock lock(m_mutex);
+
+ core::map::Node *n;
+ n = m_textures.find(spec);
+
+ if(n != NULL)
+ return n->getValue();
+
+ return NULL;
+ }
+
+private:
+ core::map m_textures;
+ JMutex m_mutex;
+};
/*
A thread-safe wrapper for irrlicht, to be accessed from
background worker threads.
Queues tasks to be done in the main thread.
+
+ Also caches texture specification strings to ids and textures.
*/
class IrrlichtWrapper
@@ -103,30 +147,55 @@ public:
return m_device->getTimer()->getRealTime();
}
- /*
- Path can contain stuff like
- "/usr/share/minetest/stone.png[[mod:mineral0[[mod:crack3"
+ /*
+ Format of a texture name:
+ "stone.png" (filename in image data directory)
+ "[crack1" (a name starting with "[" is a special feature)
+ "[progress1.0" (a name starting with "[" is a special feature)
*/
- video::ITexture* getTexture(const std::string &spec);
+ /*
+ Loads texture defined by "name" and assigns a texture id to it.
+ If texture has to be generated, generates it.
+ If the texture has already been loaded, returns existing id.
+ */
+ textureid_t getTextureId(const std::string &name);
+ // The reverse of the above
+ std::string getTextureName(textureid_t id);
+ // Gets a texture based on a filename
+ video::ITexture* getTexture(const std::string &name);
+ // Gets a texture based on a TextureSpec (a textureid_t is fine too)
+ video::ITexture* getTexture(const TextureSpec &spec);
private:
/*
Non-thread-safe variants of stuff, for internal use
*/
- video::ITexture* getTextureDirect(const std::string &spec);
+
+ // DEPRECATED NO-OP
+ //video::ITexture* getTextureDirect(const std::string &spec);
+
+ // Constructs a texture according to spec
+ video::ITexture* getTextureDirect(const TextureSpec &spec);
/*
Members
*/
+ // The id of the thread that can (and has to) use irrlicht directly
threadid_t m_main_thread;
-
+
+ // The irrlicht device
JMutex m_device_mutex;
IrrlichtDevice *m_device;
-
- TextureCache m_texturecache;
- RequestQueue m_get_texture_queue;
+ // Queued texture fetches (to be processed by the main thread)
+ RequestQueue m_get_texture_queue;
+
+ // Cache of textures by spec
+ TextureCache m_texturecache;
+
+ // A mapping from texture id to string spec
+ MutexedIdGenerator m_namecache;
};
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 388ab8089..0dc822474 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -104,8 +104,11 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into
Gaming ideas:
-------------
-- Aim for something like controlling a single dwarf in Dwarf Fortress.
+- Aim for something like controlling a single dwarf in Dwarf Fortress
+- The player could go faster by a crafting a boat, or riding an animal
+
+- Random NPC traders. what else?
Documentation:
--------------
@@ -165,6 +168,20 @@ TODO: Make fetching sector's blocks more efficient when rendering
TODO: Flowing water animation
+FIXME: The new texture stuff is slow on wine
+ - A basic grassy ground block takes 20-40ms
+ - A bit more complicated block can take 270ms
+ - On linux, a similar one doesn't take long at all (14ms)
+ - It is NOT a bad std::string implementation of MSVC.
+ - Can take up to 200ms? Is it when loading textures or always?
+ - Updating excess amount of meshes when making footprints is too
+ slow. It has to be fixed.
+ -> implement Map::updateNodeMeshes()
+ The fix:
+ * Optimize TileSpec to only contain a reference number that
+ is fast to compare, which refers to a cached string, or
+ * Make TextureSpec for using instead of strings
+
Configuration:
--------------
@@ -281,18 +298,6 @@ TODO: Flowing water to actually contain flow direction information
TODO: Remove duplicate lighting implementation from Map (leave
VoxelManipulator, which is faster)
-FIXME: The new texture stuff is slow on wine
- - A basic grassy ground block takes 20-40ms
- - A bit more complicated block can take 270ms
- - On linux, a similar one doesn't take long at all (14ms)
- - Is it a bad std::string implementation of MSVC?
- - Can take up to 200ms? Is it when loading textures or always?
- - Updating excess amount of meshes when making footprints is too
- slow. It has to be fixed.
- -> implement Map::updateNodeMeshes()
- TODO: Optimize TileSpec to only contain a reference number that
- is fast to compare, which refers to a cached string
-
Doing now:
----------
@@ -360,6 +365,7 @@ Doing now:
#include "filesys.h"
#include "config.h"
#include "guiMainMenu.h"
+#include "mineral.h"
IrrlichtWrapper *g_irrlicht;
@@ -1445,7 +1451,6 @@ int main(int argc, char *argv[])
// C-style stuff initialization
initializeMaterialProperties();
- init_mapnode();
// Debug handler
BEGIN_DEBUG_EXCEPTION_HANDLER
@@ -1683,7 +1688,8 @@ int main(int argc, char *argv[])
*/
init_content_inventory_texture_paths();
- //init_tile_textures();
+ init_mapnode(g_irrlicht);
+ init_mineral(g_irrlicht);
/*
GUI stuff
@@ -2378,7 +2384,7 @@ int main(int argc, char *argv[])
bool nodefound = false;
v3s16 nodepos;
v3s16 neighbourpos;
- core::aabbox3d nodefacebox;
+ core::aabbox3d nodehilightbox;
f32 mindistance = BS * 1001;
v3s16 pos_i = floatToInt(player_position);
@@ -2470,7 +2476,7 @@ int main(int argc, char *argv[])
nodepos = np;
neighbourpos = np;
mindistance = distance;
- nodefacebox = box;
+ nodehilightbox = box;
}
}
}
@@ -2513,7 +2519,16 @@ int main(int argc, char *argv[])
nodepos = np;
neighbourpos = np + dirs[i];
mindistance = distance;
- nodefacebox = facebox;
+
+ //nodehilightbox = facebox;
+
+ const float d = 0.502;
+ core::aabbox3d nodebox
+ (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
+ v3f nodepos_f = intToFloat(nodepos);
+ nodebox.MinEdge += nodepos_f;
+ nodebox.MaxEdge += nodepos_f;
+ nodehilightbox = nodebox;
}
} // if distance < mindistance
} // for dirs
@@ -2531,15 +2546,7 @@ int main(int argc, char *argv[])
// Visualize selection
- const float d = 0.502;
- core::aabbox3d nodebox(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
- v3f nodepos_f = intToFloat(nodepos);
- //v3f nodepos_f(nodepos.X*BS, nodepos.Y*BS, nodepos.Z*BS);
- nodebox.MinEdge += nodepos_f;
- nodebox.MaxEdge += nodepos_f;
- hilightboxes.push_back(nodebox);
-
- //hilightboxes.push_back(nodefacebox);
+ hilightboxes.push_back(nodehilightbox);
// Handle digging
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index f06dbc811..b346b0980 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -263,6 +263,7 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
//u8 li = decode_light(light);
u8 li = light;
+ //u8 li = 255; //DEBUG
u8 alpha = tile.alpha;
/*u8 alpha = 255;
@@ -309,15 +310,16 @@ TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir)
struct NodeMod mod = n->getValue();
if(mod.type == NODEMOD_CHANGECONTENT)
{
- //spec = content_tile(mod.param, face_dir);
MapNode mn2(mod.param);
spec = mn2.getTile(face_dir);
}
if(mod.type == NODEMOD_CRACK)
{
std::ostringstream os;
- os<<"[[mod:crack"<getTextureId(os.str());
+ spec.spec.addTid(tid);
}
}
@@ -601,7 +603,8 @@ void MapBlock::updateMesh(u32 daynight_ratio)
*/
{
- TimeTaker timer2("updateMesh() collect");
+ // 4-23ms for MAP_BLOCKSIZE=16
+ //TimeTaker timer2("updateMesh() collect");
// Lock this, as m_temp_mods will be used directly
JMutexAutoLock lock(m_temp_mods_mutex);
@@ -667,22 +670,25 @@ void MapBlock::updateMesh(u32 daynight_ratio)
// avg 0ms (100ms spikes when loading textures the first time)
//TimeTaker timer2("updateMesh() mesh building");
+ video::SMaterial material;
+ material.Lighting = false;
+ material.BackfaceCulling = false;
+ material.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
+ material.setFlag(video::EMF_FOG_ENABLE, true);
+
for(u32 i=0; igetTexture(f.tile.name);
- video::SMaterial material;
- material.Lighting = false;
- material.BackfaceCulling = false;
- material.setFlag(video::EMF_BILINEAR_FILTER, false);
- material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
- material.setFlag(video::EMF_FOG_ENABLE, true);
+ video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
material.setTexture(0, texture);
if(f.tile.alpha != 255)
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ else
+ material.MaterialType = video::EMT_SOLID;
collector.append(material, f.vertices, 4, indices, 6);
}
@@ -691,13 +697,22 @@ void MapBlock::updateMesh(u32 daynight_ratio)
/*
Add special graphics:
- torches
-
- TODO: Optimize by using same meshbuffer for same textures
+ - flowing water
*/
// 0ms
//TimeTaker timer2("updateMesh() adding special stuff");
+ // Flowing water material
+ video::SMaterial material_w1;
+ material_w1.setFlag(video::EMF_LIGHTING, false);
+ material_w1.setFlag(video::EMF_BACK_FACE_CULLING, false);
+ material_w1.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material_w1.setFlag(video::EMF_FOG_ENABLE, true);
+ material_w1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ material_w1.setTexture(0,
+ g_irrlicht->getTexture("water.png"));
+
for(s16 z=0; zgetTexture(porting::getDataPath("torch_on_floor.png").c_str()));
+ g_irrlicht->getTexture("torch_on_floor.png"));
else if(dir == v3s16(0,1,0))
material.setTexture(0,
- g_irrlicht->getTexture(porting::getDataPath("torch_on_ceiling.png").c_str()));
+ g_irrlicht->getTexture("torch_on_ceiling.png"));
// For backwards compatibility
else if(dir == v3s16(0,0,0))
material.setTexture(0,
- g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str()));
+ g_irrlicht->getTexture("torch_on_floor.png"));
else
material.setTexture(0,
- g_irrlicht->getTexture(porting::getDataPath("torch.png").c_str()));
+ g_irrlicht->getTexture("torch.png"));
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
@@ -947,19 +962,9 @@ void MapBlock::updateMesh(u32 daynight_ratio)
vertices[j].Pos += intToFloat(p + getPosRelative());
}
- // Set material
- video::SMaterial material;
- material.setFlag(video::EMF_LIGHTING, false);
- material.setFlag(video::EMF_BACK_FACE_CULLING, false);
- material.setFlag(video::EMF_BILINEAR_FILTER, false);
- material.setFlag(video::EMF_FOG_ENABLE, true);
- material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- material.setTexture(0,
- g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
-
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
- collector.append(material, vertices, 4, indices, 6);
+ collector.append(material_w1, vertices, 4, indices, 6);
}
/*
@@ -984,19 +989,9 @@ void MapBlock::updateMesh(u32 daynight_ratio)
vertices[i].Pos += intToFloat(p + getPosRelative());
}
- // Set material
- video::SMaterial material;
- material.setFlag(video::EMF_LIGHTING, false);
- material.setFlag(video::EMF_BACK_FACE_CULLING, false);
- material.setFlag(video::EMF_BILINEAR_FILTER, false);
- material.setFlag(video::EMF_FOG_ENABLE, true);
- material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- material.setTexture(0,
- g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
-
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
- collector.append(material, vertices, 4, indices, 6);
+ collector.append(material_w1, vertices, 4, indices, 6);
}
}
}
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 7625fab68..d197454fe 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -31,80 +31,85 @@ ContentFeatures::~ContentFeatures()
struct ContentFeatures g_content_features[256];
-void init_mapnode()
+ContentFeatures & content_features(u8 i)
+{
+ return g_content_features[i];
+}
+
+void init_mapnode(IrrlichtWrapper *irrlicht)
{
u8 i;
ContentFeatures *f = NULL;
i = CONTENT_STONE;
f = &g_content_features[i];
- f->setAllTextures("stone.png");
+ f->setAllTextures(irrlicht->getTextureId("stone.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_GRASS;
f = &g_content_features[i];
- //f->setAllTextures("mud.png[[mod:sidegrass");
- f->setAllTextures("mud.png[[mod:blitname:grass_side.png");
- f->setTexture(0, "grass.png");
- f->setTexture(1, "mud.png");
- f->setInventoryImage("grass.png");
+ f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
+ irrlicht->getTextureId("grass_side.png")));
+ f->setTexture(0, irrlicht->getTextureId("grass.png"));
+ f->setTexture(1, irrlicht->getTextureId("mud.png"));
+ f->setInventoryTexture(irrlicht->getTextureId("grass.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_GRASS_FOOTSTEPS;
f = &g_content_features[i];
- //f->setAllTextures("mud.png[[mod:sidegrass");
- f->setAllTextures("mud.png[[mod:blitname:grass_side.png");
- f->setTexture(0, "grass_footsteps.png");
- f->setTexture(1, "mud.png");
- f->setInventoryImage("grass_footsteps.png");
+ f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
+ irrlicht->getTextureId("grass_side.png")));
+ f->setTexture(0, irrlicht->getTextureId("grass_footsteps.png"));
+ f->setTexture(1, irrlicht->getTextureId("mud.png"));
+ f->setInventoryTexture(irrlicht->getTextureId("grass_footsteps.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_MUD;
f = &g_content_features[i];
- f->setAllTextures("mud.png");
+ f->setAllTextures(irrlicht->getTextureId("mud.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_SAND;
f = &g_content_features[i];
- f->setAllTextures("mud.png");
+ f->setAllTextures(irrlicht->getTextureId("mud.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_TREE;
f = &g_content_features[i];
- f->setAllTextures("tree.png");
+ f->setAllTextures(irrlicht->getTextureId("tree.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_LEAVES;
f = &g_content_features[i];
- f->setAllTextures("leaves.png");
+ f->setAllTextures(irrlicht->getTextureId("leaves.png"));
f->param_type = CPT_MINERAL;
f->is_ground_content = true;
i = CONTENT_COALSTONE;
f = &g_content_features[i];
f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
- /*f->setAllTextures("coalstone.png");
+ /*f->setAllTextures(irrlicht->getTextureId("coalstone.png"));
f->is_ground_content = true;*/
i = CONTENT_WOOD;
f = &g_content_features[i];
- f->setAllTextures("wood.png");
+ f->setAllTextures(irrlicht->getTextureId("wood.png"));
f->is_ground_content = true;
i = CONTENT_MESE;
f = &g_content_features[i];
- f->setAllTextures("mese.png");
+ f->setAllTextures(irrlicht->getTextureId("mese.png"));
f->is_ground_content = true;
i = CONTENT_CLOUD;
f = &g_content_features[i];
- f->setAllTextures("cloud.png");
+ f->setAllTextures(irrlicht->getTextureId("cloud.png"));
f->is_ground_content = true;
i = CONTENT_AIR;
@@ -120,7 +125,7 @@ void init_mapnode()
i = CONTENT_WATER;
f = &g_content_features[i];
- f->setInventoryImage("water.png");
+ f->setInventoryTexture(irrlicht->getTextureId("water.png"));
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->solidness = 0; // Drawn separately, makes no faces
@@ -132,8 +137,8 @@ void init_mapnode()
i = CONTENT_WATERSOURCE;
f = &g_content_features[i];
- f->setTexture(0, "water.png", WATER_ALPHA);
- f->setInventoryImage("water.png");
+ f->setTexture(0, irrlicht->getTextureId("water.png"), WATER_ALPHA);
+ f->setInventoryTexture(irrlicht->getTextureId("water.png"));
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->solidness = 1;
@@ -145,7 +150,7 @@ void init_mapnode()
i = CONTENT_TORCH;
f = &g_content_features[i];
- f->setInventoryImage("torch_on_floor.png");
+ f->setInventoryTexture(irrlicht->getTextureId("torch_on_floor.png"));
f->param_type = CPT_LIGHT;
f->light_propagates = true;
f->solidness = 0; // drawn separately, makes no faces
@@ -184,12 +189,10 @@ TileSpec MapNode::getTile(v3s16 dir)
if(content_features(d).param_type == CPT_MINERAL)
{
u8 mineral = param & 0x1f;
- const char *ts = mineral_block_texture(mineral);
- if(ts[0] != 0)
- {
- spec.name += "[[mod:blitname:";
- spec.name += ts;
- }
+ // Add mineral block texture
+ textureid_t tid = mineral_block_texture(mineral);
+ if(tid != 0)
+ spec.spec.addTid(tid);
}
return spec;
@@ -206,14 +209,15 @@ u8 MapNode::getMineral()
}
// Pointers to c_str()s g_content_features[i].inventory_image_path
-const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT] = {0};
+//const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT] = {0};
void init_content_inventory_texture_paths()
{
- for(u16 i=0; i
+
+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.
+*/
+
+#include "mineral.h"
+
+const char *mineral_filenames[MINERAL_COUNT] =
+{
+ NULL,
+ "mineral_coal.png",
+ "mineral_iron.png"
+};
+
+textureid_t mineral_textures[MINERAL_COUNT] = {0};
+
+void init_mineral(IrrlichtWrapper *irrlicht)
+{
+ for(u32 i=0; igetTextureId(mineral_filenames[i]);
+ }
+}
+
+textureid_t mineral_block_texture(u8 mineral)
+{
+ if(mineral >= MINERAL_COUNT)
+ return 0;
+
+ return mineral_textures[mineral];
+}
+
+
diff --git a/src/mineral.h b/src/mineral.h
index e43e48ab8..aa0902e12 100644
--- a/src/mineral.h
+++ b/src/mineral.h
@@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MINERAL_HEADER
#include "inventory.h"
+#include "texture.h"
+#include "irrlichtwrapper.h"
/*
Minerals
@@ -29,22 +31,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
type param.
*/
+// Caches textures
+void init_mineral(IrrlichtWrapper *irrlicht);
+
#define MINERAL_NONE 0
#define MINERAL_COAL 1
#define MINERAL_IRON 2
-inline const char * mineral_block_texture(u8 mineral)
-{
- switch(mineral)
- {
- case MINERAL_COAL:
- return "mineral_coal.png";
- case MINERAL_IRON:
- return "mineral_iron.png";
- default:
- return "";
- }
-}
+#define MINERAL_COUNT 3
+
+textureid_t mineral_block_texture(u8 mineral);
inline CraftItem * getDiggedMineralItem(u8 mineral)
{
diff --git a/src/player.cpp b/src/player.cpp
index 8aabb030c..b260e5056 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "connection.h"
#include "constants.h"
+#include "utility.h"
Player::Player():
touching_ground(false),
@@ -34,15 +35,21 @@ Player::Player():
m_position(0,0,0)
{
updateName("");
- inventory.addList("main", PLAYER_INVENTORY_SIZE);
- inventory.addList("craft", 9);
- inventory.addList("craftresult", 1);
+ resetInventory();
}
Player::~Player()
{
}
+void Player::resetInventory()
+{
+ inventory.clear();
+ inventory.addList("main", PLAYER_INVENTORY_SIZE);
+ inventory.addList("craft", 9);
+ inventory.addList("craftresult", 1);
+}
+
// Y direction is ignored
void Player::accelerate(v3f target_speed, f32 max_increase)
{
@@ -80,6 +87,50 @@ void Player::accelerate(v3f target_speed, f32 max_increase)
#endif
}
+void Player::serialize(std::ostream &os)
+{
+ // Utilize a Settings object for storing values
+ Settings args;
+ args.setS32("version", 1);
+ args.set("name", m_name);
+ args.setFloat("pitch", m_pitch);
+ args.setFloat("yaw", m_yaw);
+ args.setV3F("position", m_position);
+
+ args.writeLines(os);
+
+ os<<"PlayerArgsEnd\n";
+
+ inventory.serialize(os);
+}
+
+void Player::deSerialize(std::istream &is)
+{
+ Settings args;
+
+ for(;;)
+ {
+ if(is.eof())
+ throw SerializationError
+ ("Player::deSerialize(): PlayerArgsEnd not found");
+ std::string line;
+ std::getline(is, line);
+ std::string trimmedline = trim(line);
+ if(trimmedline == "PlayerArgsEnd")
+ break;
+ args.parseConfigLine(line);
+ }
+
+ //args.getS32("version");
+ std::string name = args.get("name");
+ updateName(name.c_str());
+ m_pitch = args.getFloat("pitch");
+ m_yaw = args.getFloat("yaw");
+ m_position = args.getV3F("position");
+
+ inventory.deSerialize(is);
+}
+
/*
RemotePlayer
*/
diff --git a/src/player.h b/src/player.h
index 9330bdd54..5ab027e0a 100644
--- a/src/player.h
+++ b/src/player.h
@@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PLAYERNAME_SIZE 20
+#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
+
class Map;
class Player
@@ -37,6 +39,8 @@ public:
Player();
virtual ~Player();
+ void resetInventory();
+
//void move(f32 dtime, Map &map);
virtual void move(f32 dtime, Map &map) = 0;
@@ -100,6 +104,14 @@ public:
// NOTE: Use peer_id == 0 for disconnected
/*virtual bool isClientConnected() { return false; }
virtual void setClientConnected(bool) {}*/
+
+ /*
+ serialize() writes a bunch of text that can contain
+ any characters except a '\0', and such an ending that
+ deSerialize stops reading exactly at the right point.
+ */
+ void serialize(std::ostream &os);
+ void deSerialize(std::istream &is);
bool touching_ground;
bool in_water;
@@ -119,8 +131,6 @@ protected:
class ServerRemotePlayer : public Player
{
public:
- /*ServerRemotePlayer(bool client_connected):
- m_client_connected(client_connected)*/
ServerRemotePlayer()
{
}
@@ -137,18 +147,6 @@ public:
{
}
- /*virtual bool isClientConnected()
- {
- return m_client_connected;
- }
- virtual void setClientConnected(bool client_connected)
- {
- m_client_connected = client_connected;
- }
-
- // This
- bool m_client_connected;*/
-
private:
};
@@ -252,7 +250,7 @@ private:
v3f m_showpos;
};
-#endif
+#endif // !SERVER
#ifndef SERVER
struct PlayerControl
diff --git a/src/server.cpp b/src/server.cpp
index 541582b65..823a48b90 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -1000,7 +1000,8 @@ Server::Server(
m_time_of_day(9000),
m_time_counter(0),
m_time_of_day_send_timer(0),
- m_uptime(0)
+ m_uptime(0),
+ m_mapsavedir(mapsavedir)
{
//m_flowwater_timer = 0.0;
m_liquid_transform_timer = 0.0;
@@ -1013,10 +1014,16 @@ Server::Server(
m_con_mutex.Init();
m_step_dtime_mutex.Init();
m_step_dtime = 0.0;
+
+ // Load players
+ m_env.deSerializePlayers(m_mapsavedir);
}
Server::~Server()
{
+ // Save players
+ m_env.serializePlayers(m_mapsavedir);
+
// Stop threads
stop();
@@ -1222,82 +1229,6 @@ void Server::AsyncRunStep()
}
}
-#if 0
- /*
- Update water
- */
- if(g_settings.getBool("water_moves") == true)
- {
- float interval;
-
- if(g_settings.getBool("endless_water") == false)
- interval = 1.0;
- else
- interval = 0.25;
-
- float &counter = m_flowwater_timer;
- counter += dtime;
- if(counter >= 0.25 && m_flow_active_nodes.size() > 0)
- {
-
- counter = 0.0;
-
- core::map modified_blocks;
-
- {
-
- JMutexAutoLock envlock(m_env_mutex);
-
- MapVoxelManipulator v(&m_env.getMap());
- v.m_disable_water_climb =
- g_settings.getBool("disable_water_climb");
-
- if(g_settings.getBool("endless_water") == false)
- v.flowWater(m_flow_active_nodes, 0, false, 250);
- else
- v.flowWater(m_flow_active_nodes, 0, false, 50);
-
- v.blitBack(modified_blocks);
-
- ServerMap &map = ((ServerMap&)m_env.getMap());
-
- // Update lighting
- core::map lighting_modified_blocks;
- map.updateLighting(modified_blocks, lighting_modified_blocks);
-
- // Add blocks modified by lighting to modified_blocks
- for(core::map::Iterator
- i = lighting_modified_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
- modified_blocks.insert(block->getPos(), block);
- }
- } // envlock
-
- /*
- Set the modified blocks unsent for all the clients
- */
-
- JMutexAutoLock lock2(m_con_mutex);
-
- for(core::map::Iterator
- i = m_clients.getIterator();
- i.atEnd() == false; i++)
- {
- RemoteClient *client = i.getNode()->getValue();
-
- if(modified_blocks.size() > 0)
- {
- // Remove block from sent history
- client->SetBlocksNotSent(modified_blocks);
- }
- }
-
- } // interval counter
- }
-#endif
-
// Periodically print some info
{
float &counter = m_print_info_timer;
@@ -1476,6 +1407,9 @@ void Server::AsyncRunStep()
dout_server<<"Server: Unloaded "<serialize(test_os);
+ dstream<<"Player serialization test: \""<deSerialize(test_is);
+ }*/
+
// If failed, cancel
if(player == NULL)
{
@@ -2950,7 +2894,7 @@ void Server::SendInventory(u16 peer_id)
if(!found)
{
ItemSpec specs[9];
- specs[0] = ItemSpec(ITEM_CRAFT, "Coal");
+ specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
if(checkItemCombination(items, specs))
{
@@ -3147,6 +3091,50 @@ RemoteClient* Server::getClient(u16 peer_id)
return n->getValue();
}
+void setCreativeInventory(Player *player)
+{
+ player->resetInventory();
+
+ // Give some good picks
+ {
+ InventoryItem *item = new ToolItem("STPick", 0);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+ {
+ InventoryItem *item = new ToolItem("MesePick", 0);
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+
+ /*
+ Give materials
+ */
+ assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
+
+ // add torch first
+ InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
+ player->inventory.addItem("main", item);
+
+ // Then others
+ for(u16 i=0; iinventory.addItem("main", item);
+ }
+ // Sign
+ {
+ InventoryItem *item = new MapBlockObjectItem("Sign Example text");
+ void* r = player->inventory.addItem("main", item);
+ assert(r == NULL);
+ }
+}
+
Player *Server::emergePlayer(const char *name, const char *password,
u16 peer_id)
{
@@ -3162,8 +3150,16 @@ Player *Server::emergePlayer(const char *name, const char *password,
dstream<<"emergePlayer(): Player already connected"<peer_id = peer_id;
+
+ // Reset inventory to creative if in creative mode
+ if(g_settings.getBool("creative_mode"))
+ {
+ setCreativeInventory(player);
+ }
+
return player;
}
@@ -3271,51 +3267,15 @@ Player *Server::emergePlayer(const char *name, const char *password,
if(g_settings.getBool("creative_mode"))
{
- // Give some good picks
- {
- InventoryItem *item = new ToolItem("STPick", 0);
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
- {
- InventoryItem *item = new ToolItem("MesePick", 0);
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
-
- /*
- Give materials
- */
- assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
-
- // add torch first
- InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
- player->inventory.addItem("main", item);
-
- // Then others
- for(u16 i=0; iinventory.addItem("main", item);
- }
- // Sign
- {
- InventoryItem *item = new MapBlockObjectItem("Sign Example text");
- void* r = player->inventory.addItem("main", item);
- assert(r == NULL);
- }
+ setCreativeInventory(player);
}
else
{
- {
+ /*{
InventoryItem *item = new ToolItem("WPick", 32000);
void* r = player->inventory.addItem("main", item);
assert(r == NULL);
- }
+ }*/
/*{
InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
void* r = player->inventory.addItem("main", item);
diff --git a/src/server.h b/src/server.h
index a3e1897d9..fcc37631f 100644
--- a/src/server.h
+++ b/src/server.h
@@ -508,6 +508,8 @@ private:
Queue m_peer_change_queue;
+ std::string m_mapsavedir;
+
friend class EmergeThread;
friend class RemoteClient;
};
diff --git a/src/texture.h b/src/texture.h
new file mode 100644
index 000000000..f14efae11
--- /dev/null
+++ b/src/texture.h
@@ -0,0 +1,124 @@
+/*
+Minetest-c55
+Copyright (C) 2010 celeron55, Perttu Ahola
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef TEXTURE_HEADER
+#define TEXTURE_HEADER
+
+#include "common_irrlicht.h"
+//#include "utility.h"
+#include "debug.h"
+
+/*
+ All textures are given a "texture id".
+ 0 = nothing (a NULL pointer texture)
+*/
+typedef u16 textureid_t;
+
+/*
+ Every texture in the game can be specified by this.
+
+ It exists instead of specification strings because arbitary
+ texture combinations for map nodes are handled using this,
+ and strings are too slow for that purpose.
+
+ Plain texture pointers are not used because they don't contain
+ content information by themselves. A texture can be completely
+ reconstructed by just looking at this, while this also is a
+ fast unique key to containers.
+*/
+
+#define TEXTURE_SPEC_TEXTURE_COUNT 4
+
+struct TextureSpec
+{
+ TextureSpec()
+ {
+ clear();
+ }
+
+ TextureSpec(textureid_t id0)
+ {
+ clear();
+ tids[0] = id0;
+ }
+
+ TextureSpec(textureid_t id0, textureid_t id1)
+ {
+ clear();
+ tids[0] = id0;
+ tids[1] = id1;
+ }
+
+ void clear()
+ {
+ for(u32 i=0; i= other.tids[i])
+ return false;
+ }
+ return true;
+ }
+
+ // Ids of textures. They are blit on each other.
+ textureid_t tids[TEXTURE_SPEC_TEXTURE_COUNT];
+};
+
+#endif
diff --git a/src/tile.h b/src/tile.h
index b903d92a8..ff495abc4 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -22,8 +22,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
//#include "utility.h"
+#include "texture.h"
#include
+struct TileSpec
+{
+ TileSpec():
+ alpha(255)
+ {
+ }
+
+ bool operator==(TileSpec &other)
+ {
+ return (spec == other.spec && alpha == other.alpha);
+ }
+
+ TextureSpec spec;
+ u8 alpha;
+};
+
+#if 0
struct TileSpec
{
TileSpec():
@@ -52,5 +70,6 @@ struct TileSpec
std::string name;
u8 alpha;
};
+#endif
#endif
diff --git a/src/utility.h b/src/utility.h
index b517848b1..4f74a0649 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -760,17 +760,20 @@ class Settings
{
public:
- // Returns false on EOF
- bool parseConfigObject(std::istream &is)
+ void writeLines(std::ostream &os)
{
- 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: \""<::Iterator
+ i = m_settings.getIterator();
+ i.atEnd() == false; i++)
+ {
+ std::string name = i.getNode()->getKey();
+ std::string value = i.getNode()->getValue();
+ os<>f;
- return f;
+ return stof(get(name));
}
u16 getU16(std::string name)
@@ -1128,6 +1145,34 @@ public:
return stoi(get(name));
}
+ v3f getV3F(std::string name)
+ {
+ v3f value;
+ Strfnd f(get(name));
+ f.next("(");
+ value.X = stof(f.next(","));
+ value.Y = stof(f.next(","));
+ value.Z = stof(f.next(")"));
+ return value;
+ }
+
+ void setS32(std::string name, s32 value)
+ {
+ set(name, itos(value));
+ }
+
+ void setFloat(std::string name, float value)
+ {
+ set(name, ftos(value));
+ }
+
+ void setV3F(std::string name, v3f value)
+ {
+ std::ostringstream os;
+ os<<"("< m_list;
};
+#if 0
+template
+class MutexedCache
+{
+public:
+ MutexedCache()
+ {
+ m_mutex.Init();
+ assert(m_mutex.IsInitialized());
+ }
+
+ void set(const Key &name, const Value &value)
+ {
+ JMutexAutoLock lock(m_mutex);
+
+ m_values[name] = value;
+ }
+
+ bool get(const Key &name, Value *result)
+ {
+ JMutexAutoLock lock(m_mutex);
+
+ typename core::map::Node *n;
+ n = m_values.find(name);
+
+ if(n == NULL)
+ return false;
+
+ *result = n->getValue();
+ return true;
+ }
+
+private:
+ core::map m_values;
+ JMutex m_mutex;
+};
+#endif
+
+/*
+ Generates ids for comparable values.
+ Id=0 is reserved for "no value".
+
+ Is fast at:
+ - Returning value by id (very fast)
+ - Returning id by value
+ - Generating a new id for a value
+
+ Is not able to:
+ - Remove an id/value pair (is possible to implement but slow)
+*/
+template
+class MutexedIdGenerator
+{
+public:
+ MutexedIdGenerator()
+ {
+ m_mutex.Init();
+ assert(m_mutex.IsInitialized());
+ }
+
+ // Returns true if found
+ bool getValue(u32 id, T &value)
+ {
+ if(id == 0)
+ return false;
+ JMutexAutoLock lock(m_mutex);
+ if(m_id_to_value.size() < id)
+ return false;
+ value = m_id_to_value[id-1];
+ return true;
+ }
+
+ // If id exists for value, returns the id.
+ // Otherwise generates an id for the value.
+ u32 getId(const T &value)
+ {
+ JMutexAutoLock lock(m_mutex);
+ typename core::map::Node *n;
+ n = m_value_to_id.find(value);
+ if(n != NULL)
+ return n->getValue();
+ m_id_to_value.push_back(value);
+ u32 new_id = m_id_to_value.size();
+ m_value_to_id.insert(value, new_id);
+ return new_id;
+ }
+
+private:
+ JMutex m_mutex;
+ // Values are stored here at id-1 position (id 1 = [0])
+ core::array m_id_to_value;
+ core::map m_value_to_id;
+};
+
+/*
+ Checks if a string contains only supplied characters
+*/
+inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
+{
+ for(u32 i=0; i