From 64b59757322e29c331c0a75262baec4382673e6f Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Fri, 28 Jan 2011 01:38:16 +0200 Subject: [PATCH] Now texture handling is fast. Also now players are saved on disk. --- data/grass.png | Bin 1599 -> 1675 bytes data/grass_side.png | Bin 1695 -> 1690 bytes minetest.vcproj | 4 + src/CMakeLists.txt | 47 ++-- src/environment.cpp | 181 +++++++++++++++ src/environment.h | 4 + src/inventory.cpp | 8 +- src/inventory.h | 43 ++-- src/irrlichtwrapper.cpp | 487 +++++++++++++++------------------------- src/irrlichtwrapper.h | 89 +++++++- src/main.cpp | 61 ++--- src/mapblock.cpp | 73 +++--- src/mapnode.cpp | 70 +++--- src/mapnode.h | 76 ++++--- src/mineral.cpp | 49 ++++ src/mineral.h | 20 +- src/player.cpp | 57 ++++- src/player.h | 28 ++- src/server.cpp | 194 +++++++--------- src/server.h | 2 + src/texture.h | 124 ++++++++++ src/tile.h | 19 ++ src/utility.h | 187 +++++++++++++-- 23 files changed, 1167 insertions(+), 656 deletions(-) create mode 100644 src/mineral.cpp create mode 100644 src/texture.h diff --git a/data/grass.png b/data/grass.png index 88336c01383752157b9842bd5e0a7230cc47b546..8fe9078caffee8e3a78b9ccd6b70b1782ad8955d 100644 GIT binary patch delta 886 zcmV-+1Bv{<42unr83+ad001BJ|6#Eq4g-G!MoC0LR5;6Z(9cg>1pvVD?|Uufz1P0} z25f1ewNwTxP=;Yqw+UGmql?M5c=YDMKftR|{s7}{##9z>ttk4bK#ZPn51Ms7WrA-&dNUBuhlCbpKPCAAr}I}w|0(x(k1r$lJjNJo&! zXUpuagRv2$FJ~v z9rU{Uc)GC7*rbKxVHqVNqlyCUqD-x;fn73E(#?dr-{!ni!w{Wu%w@|(q9fyUOa%^) zH3kOEBr+xL&3;CyR%UZ6!?53pZ`jMqqDJhwM!u59sJ1YK$DMPk*+jKj$5b<*S3yx7 zv}#S3|NaNb*x>4zg_&C)@!fy7e=ru65k)7ykbfz2rO%B`7^Yfn;Rsq;T+vWf zg|VqH{woqkX`SEye8%m2eR#t@`U8+mpV6hb5Po`gx3lm>BY9Hd`UgS0mTu&3Gu1{C zlkDZ`uj>d-kzB5YFKi<;WM_3gMdVr-#a6?Z(y|QpTj&jRAuBq@hMj*GTN_k`3shSb zdJMcb;UimbU>2P0@9i>sV-PiH;mM;k;_IynZo9;2B*^Z+Ibz#e^mt7a&UE@+9^Rku zkt&{Ya#|%Awvov+`EYiYpC7Ie@Qa9gR(~U0o$Mzze?erxN^&z#Xn2C%O#_)?h3_9O z;8GlKcnDwrc)g=q+!$iyJlP`ygCRSL3WY+0_-Yl~poI0pL(AIc<;n}NiR88BrH3(@ zDw4~cU53QoIpu5#Yp)4UU;x>gV`+JnW~ZC`4qT zU@#CvXhIVRTf3-Tk4USgR%+EmlO|1T)oIeCUF{L7-t?+cpQ1Otsj6*CHEq*QNtHGm z=~5CP2Tmr&=4h}v#29vweQ)p?SHE@9P6s}P40NMX?U9fWYV{kp5`|*JXS2z=;i!L@ zCo%MVba|iODP%>2iP}|dXux4&W>zgJS1vP7()xOHmxlQEX0dW4D{4P5%cSxfCB8OB z7_jqAJx@Em_SF~XLl9Bj8r1ra&!=JL4~fS3WI`MuU)tS}t= z;`z>v+wm!n@;+5@;Er-ZipN~ENxr!f1$e+TWx*-J#24i^Y4O8z5xH#m^6PWeX1l8y zgj#E$>jXZw4rhN$?H{)r#`}-B#99BVwOzm0;dV~{{zoqM0okc2#3D{1#&LfK@0*5p zh<0^L*c@t4`XI7wmXuB+8lPZtr78phmZI3boBXWXSN1aEoS$aryl-C%sSTl}@+dU| z-Y}#rSWg>ZeW3RY1mzg@wKsqM1JU6^jJ$sJ(a~A*kBituQM;B* zK70Ch#*csy2k(8gaykn}{2Ob{c$BD?1{W?Z|NKiyF{nR%e;8z(wMOkU13vkjIi0l{ zX1l|@_>t9!p>kQ5)OyIqc^Hq@ku-Rc-TglU+!1g(V>wbNsD*!Pnx?s?eO8;gmCo_i o=AFCqxokUr-sPb@`EnNdKiEKOVpD8NWdHyG07*qoM6N<$f<``yZvX%Q diff --git a/data/grass_side.png b/data/grass_side.png index ee12491e8deb8177f481b7038ae3d908b734e966..7bacbfb5efe30f092fdde40e89c924f1b7a6cdac 100644 GIT binary patch delta 888 zcmV-;1Bd*d4Vn$GFav*8Nklge|0 z{4<~M$>-sL-DyK|Xy~c}&7(FZy@6uonANxAWU?ptEEei2>}P+|m~>h$&tKtLev8ar z35{poN=xa1q$fT;MeCr+>(@LuO=cc$>|obRJlV)n*ss%UbqG#*NTeTdkgw3!c+mI* z0d$f=G1*1!YPtUYGU?qa-F_2K$j|rRZL#`J42Qc(db`7mRFTM1n3=^e-f<(^RtaQ> zN$9t0GKxi`g~#4`?SCkTI^eshI*IKXee?hx?W7;%nr z_g;$Vl8Hv4i6J5(YXtfYiOx_Dt6s~QYGiVFg4&>i7+8!nOI*h5%kLh171cZ zE;!7qWU|LhMnzm>Zu)A6gZwF;u?fV_zP`%#<1$b7Qv?=9a2fT)qdp9B4fCj-`#)r8 zDCZ>iDqM&|NP3a2jUsdNQ|NRxw7FuLF`tQ%@gaXCgNn9i<&WexZQ&f*(gv5v)kQz$ zZV#hiXaB`>R<4a9hfLi5Ige&9*}`en6OM#<{?`eKR1%k0NBvaA=kV~_qMuyjn96aR z(6oh8N#Tu^6~4W-$#_76MlGxV2@6X;5_ist1kD`mR+*e#LpP1WEiV$n8>SU1f7<8PNm#BX2KG}?Qx?t$|(AC_ICdD5XTqI zFM<3a6U9u6%+m^rqTm|!VYak*yqzL{bjrJHbENia#4fvV%Wl%S9RC2{X>tF+W2b@u O0000|t3Do}+9Dxip51P&bF9L|0};pO*! z!{fVy%`2kn0`02~POF{E$_<;JEs;N~5*i)lR)^EG98TH9!?}M|GKE9($7RIeoEv4( z1DlnlXdLCd&Bu>|_?#}bcT#w)HuiVUD4yQZR=P~ZgY4!0=Dbj0Cb<|;-U@Xkn^Y;7|Z zi^OTSjwH$$f`*|_;p^84Zmi-p)u@*1{I!)qnlN|J^#LZ)!hSZ%^wN7M_6Clqjb+J< z!#m)nHp+idvdCATtZ;Sl2Df>UUiJnlpdoE6N2y5H3=JQpW{YaQ%+O>d{ZEN8%Ls+G zh<#y#4XcTt4-S}}oI$f%sETRsdRLI{P5JSkv39+QY+bZ`z;5}p7j6liud9HkD~ zUW5A|`mj|+%C}d{`{yZ@b4Y=iA#r<{*t8khS7(1xj1cz38Rk{O3vra1#_Gl@%}fTD zwN2>$IxP(Hg%X`o59#a2bNpM(vX!~vkrYOV$u!&}MDGP?{*fb+s324ZI2Y{LaG?)0 z<{W-fM{TlB6=`k8M)pi%HZ+EgO0ij@cC2$)cuivE0h%nM%PQrph;3$>)Nz*7xQ5!e zB6@YFi}XRw5W`g~@U`t|_MaGOijm9mO2g~$pmy|D#F|K8DDV50jIQCi; zX>lb&Xv$A_P{P`?@FriwsSoK$BMb*#BGWN$E@UJnMX%QeyA`|Hk9ZBv{w@ClecXN~ T)SRB*00000NkvXXu0mjfKa#pe 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=" - < 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