From 699d0e9a5efa555f4b4c7652a0ca571acf0afdb2 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 25 Dec 2010 01:54:39 +0200 Subject: [PATCH] minecraft-like crafting --- Makefile | 4 +- data/stick.png | Bin 0 -> 947 bytes data/wood.png | Bin 0 -> 1400 bytes src/inventory.h | 14 ++ src/main.cpp | 102 +++++++--- src/mapnode.cpp | 2 + src/mapnode.h | 45 ++--- src/materials.cpp | 75 +++++++ src/materials.h | 98 ++++++++++ src/server.cpp | 473 +++++++++++++++++++++++++++------------------ src/servermain.cpp | 2 + src/tile.cpp | 1 + src/tile.h | 1 + 13 files changed, 569 insertions(+), 248 deletions(-) create mode 100644 data/stick.png create mode 100644 data/wood.png create mode 100644 src/materials.cpp create mode 100644 src/materials.h diff --git a/Makefile b/Makefile index 5dad9433f..a6e360f3f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Makefile for Irrlicht Examples # It's usually sufficient to change just the target name and source file list # and be sure that CXX is set to a valid compiler -SOURCE_FILES = guiTextInputMenu.cpp guiInventoryMenu.cpp irrlichtwrapper.cpp guiPauseMenu.cpp defaultsettings.cpp mapnode.cpp tile.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp +SOURCE_FILES = materials.cpp guiTextInputMenu.cpp guiInventoryMenu.cpp irrlichtwrapper.cpp guiPauseMenu.cpp defaultsettings.cpp mapnode.cpp tile.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp DEBUG_TARGET = debugtest DEBUG_SOURCES = $(addprefix src/, $(SOURCE_FILES)) @@ -14,7 +14,7 @@ FAST_BUILD_DIR = fastbuild FAST_OBJECTS = $(addprefix $(FAST_BUILD_DIR)/, $(SOURCE_FILES:.cpp=.o)) SERVER_TARGET = server -SERVER_SOURCE_FILES = 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 servermain.cpp test.cpp +SERVER_SOURCE_FILES = 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 servermain.cpp test.cpp SERVER_SOURCES = $(addprefix src/, $(SERVER_SOURCE_FILES)) SERVER_BUILD_DIR = serverbuild SERVER_OBJECTS = $(addprefix $(SERVER_BUILD_DIR)/, $(SERVER_SOURCE_FILES:.cpp=.o)) diff --git a/data/stick.png b/data/stick.png new file mode 100644 index 0000000000000000000000000000000000000000..7a4663cc3a3ea2e9e4638205d831511abd4af67f GIT binary patch literal 947 zcmZvaF=$jl5Qc|bkPr-98DpU*0}{2ka2BZohKpv1#&`tlB*xCM5hS1(ND&dV$d6zn zq_GJ`%PE6tM6^g}Glhj{EvStayR(m-{r>r9pDfH@85tfMCZZ9UZFh35 z7h~vH&ZmCHGEt2dt}f2xHo7CaOXMz!&)v-ofU1fJGdqzHfk=sjh%>A5%bm;!AXO3} z{@)=dH!={ER7f~)s-#u%Vdj9TLPVJZa8(mQ#;Pu28Hjk!DK*^OU{I*2u&{-}p{4?1 zWdzh!Oc<=8;(3B4guD6feKaxa1uAgFOn(lssihz%ziM8Dxx*|IMKw>rUCji@Sl#pf z48%QWj*9xQaJZ>Kps5$(>L!M)L&L=_>yz-TyT~rX(wSaf8hC`v<{na0N`kxiigQ$U zF1Nj<6ip78D@+tDO6+}JQwr^|o7B87LtvqB(d+?;wOnrTMi8bBvFx0XW}W5NAXM&8 ziX;b_QXUU7Cm1R6*;)`hB~XI8-@&)TVe*Z%w(ukCC$&)j?Yd@@?iW^;CKu61GR;p45<+J}k3*8`p7`{T0PSi5%ieSPB* zuMXX4JUgggUio_RMdRr!9=o&I+**0J_u$Kk<(>OKh|W{%``-5S-$H`S%(vf8FKzq- D$hxuG literal 0 HcmV?d00001 diff --git a/data/wood.png b/data/wood.png new file mode 100644 index 0000000000000000000000000000000000000000..57c1d7c124971fd9fef4f8dc90b86ac7cc45a742 GIT binary patch literal 1400 zcmZuv3ryBk6h9#1H_)L;MFhg|9}5;VqR@hrh)=tG_{jiY@#wL!p>S0YT0k?X4T;=< zgAfiaO9^NQk$Q=u;U|GPOjyXvV`joK#S(!qp11qq=6H0sd+#}S=iJ}#{Lc9(%(!ux zjiU_!EMu<)hpT(JdFw3InO_j^2e1gjLL>Fcl`~t;TvB<`yog8$fry-Q#+asQ1Rwwq zfCDf9O=T^3A_5@*5jY3NK>NQS0umq)kOODHH1*Shw1x0e2tpK`BV%0CBqDJx7(-=q zPK*gnR&g;SEBuAxNhyd>2$jeM@ zI10v5V;nS^r!^>|v*ZRYXkG?GAvqG`ss{)fpIfeZMo&cyE2=e}yZ)>QMxs+u*uhSkSI!@fz+bK7oj z%-YiLeRz|rbwXmE=j2HD63Zmro%+OHw~AX&t^UwyiD&1D9y^cx_0wNB>PgdZOzgyP!H+a=F>Ok(dIuP%ifpObbIC!15Sz+1; znGw$=l${+se_>I|^z>gY?#1uLykz?#{Mz;LsPXFzzheQ;cxvgLh}^`N%llZ-p()db zkqGbR&36MAe_rVKc3(lSuWxb8&_69H|L$|JJASpetZLvsJ^Bgg~F}OPD%@6(q D@ROia literal 0 HcmV?d00001 diff --git a/src/inventory.h b/src/inventory.h index 13bd27d8b..ff0086102 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -390,6 +390,20 @@ public: { return m_wear; } + // Returns true if weared out + bool addWear(u16 add) + { + if(m_wear >= 65535 - add) + { + m_wear = 65535; + return true; + } + else + { + m_wear += add; + return false; + } + } private: std::string m_toolname; u16 m_wear; diff --git a/src/main.cpp b/src/main.cpp index 1a9379e41..47dcbf70f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -167,6 +167,8 @@ TODO: Better handling of objects and mobs - Make separate classes for client and server - Client should not discriminate between blocks, server should - Make other players utilize the same framework + - This is also needed for objects that don't get sent to client + but are used for triggers etc TODO: Draw big amounts of torches better (that is, throw them in the same meshbuffer (can the meshcollector class be used?)) @@ -174,6 +176,9 @@ TODO: Draw big amounts of torches better (that is, throw them in the TODO: Check if the usage of Client::isFetchingBlocks() in updateViewingRange() actually does something +TODO: Make an option to the server to disable building and digging near + the starting position + Doing now: ====================================================================== @@ -239,6 +244,7 @@ TODO: Transferring of the table from server to client #include "guiPauseMenu.h" #include "guiInventoryMenu.h" #include "guiTextInputMenu.h" +#include "materials.h" IrrlichtWrapper *g_irrlicht; @@ -1022,6 +1028,22 @@ private: s32 m_selection; }; +// Chat data +struct ChatLine +{ + ChatLine(): + age(0.0) + { + } + ChatLine(const std::wstring &a_text): + age(0.0), + text(a_text) + { + } + float age; + std::wstring text; +}; + int main(int argc, char *argv[]) { /* @@ -1039,6 +1061,8 @@ int main(int argc, char *argv[]) debug_stacks_init(); DSTACK(__FUNCTION_NAME); + + initializeMaterialProperties(); try { @@ -1541,8 +1565,7 @@ int main(int argc, char *argv[]) L"Chat here\nOther line\nOther line\nOther line\nOther line", core::rect(70, 60, 795, 150), false, true); - core::list chat_lines; - //chat_lines.push_back(L"Minetest-c55 up and running!"); + core::list chat_lines; /* Some statistics are collected in these @@ -2102,34 +2125,38 @@ int main(int argc, char *argv[]) if(g_input->getLeftState()) { MapNode n = client.getNode(nodepos); - - // TODO: Get this from some table that is sent by server - float dig_time_complete = 0.5; - if(n.d == CONTENT_STONE || n.d == CONTENT_COALSTONE) + + // Get tool name. Default is "" = bare hands + std::string toolname = ""; + InventoryList *mlist = local_inventory.getList("main"); + if(mlist != NULL) { - dig_time_complete = 10.0; - - InventoryList *mlist = local_inventory.getList("main"); - if(mlist != NULL) + InventoryItem *item = mlist->getItem(g_selected_item); + if(item && (std::string)item->getName() == "ToolItem") { - InventoryItem *item = mlist->getItem(g_selected_item); - if(item && (std::string)item->getName() == "ToolItem") - { - ToolItem *titem = (ToolItem*)item; - if(titem->getToolName() == "WPick") - { - dig_time_complete = 1.2; - } - else if(titem->getToolName() == "STPick") - { - dig_time_complete = 0.6; - } - } + ToolItem *titem = (ToolItem*)item; + toolname = titem->getToolName(); } } - else if(n.d == CONTENT_TORCH) + + // Get digging properties for material and tool + u8 material = n.d; + DiggingProperties prop = + getDiggingProperties(material, toolname); + + float dig_time_complete = 0.0; + + if(prop.diggable == false) { - dig_time_complete = 0.0; + /*dstream<<"Material "<<(int)material + <<" not diggable with \"" + <= 0.001) @@ -2305,14 +2332,14 @@ int main(int argc, char *argv[]) Get chat messages from client */ { - // Get messages + // Get new messages std::wstring message; while(client.getChatMessage(message)) { - chat_lines.push_back(message); - if(chat_lines.size() > 5) + chat_lines.push_back(ChatLine(message)); + if(chat_lines.size() > 7) { - core::list::Iterator + core::list::Iterator i = chat_lines.begin(); chat_lines.erase(i); } @@ -2320,11 +2347,24 @@ int main(int argc, char *argv[]) // Append them to form the whole static text and throw // it to the gui element std::wstring whole; - for(core::list::Iterator + u16 to_be_removed_count = 0; + for(core::list::Iterator i = chat_lines.begin(); i != chat_lines.end(); i++) { - whole += (*i) + L'\n'; + (*i).age += dtime; + if((*i).age > 30.0) + { + to_be_removed_count++; + continue; + } + whole += (*i).text + L'\n'; + } + for(u16 i=0; i::Iterator + i = chat_lines.begin(); + chat_lines.erase(i); } chat_guitext->setText(whole.c_str()); // Update gui element size and position diff --git a/src/mapnode.cpp b/src/mapnode.cpp index a8e9f07fc..3dae653ed 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -43,6 +43,7 @@ u16 g_content_tiles[USEFUL_CONTENT_COUNT][6] = {TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER}, {TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD}, {TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE,TILE_COALSTONE}, + {TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD,TILE_WOOD}, }; const char * g_content_inventory_textures[USEFUL_CONTENT_COUNT] = @@ -59,5 +60,6 @@ const char * g_content_inventory_textures[USEFUL_CONTENT_COUNT] = "../data/water.png", "../data/cloud.png", "../data/coalstone.png", + "../data/wood.png", }; diff --git a/src/mapnode.h b/src/mapnode.h index ad85d88e8..659d585b5 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -77,6 +77,7 @@ enum Content CONTENT_OCEAN, CONTENT_CLOUD, CONTENT_COALSTONE, + CONTENT_WOOD, // This is set to the number of the actual values in this enum USEFUL_CONTENT_COUNT @@ -96,6 +97,7 @@ inline bool light_propagates_content(u8 m) /* If true, the material allows lossless sunlight propagation. + NOTE: It doesn't seem to go through torches regardlessly of this */ inline bool sunlight_propagates_content(u8 m) { @@ -153,14 +155,12 @@ inline bool content_buildable_to(u8 m) */ inline bool is_ground_content(u8 m) { - return( - m == CONTENT_STONE || - m == CONTENT_GRASS || - m == CONTENT_GRASS_FOOTSTEPS || - m == CONTENT_MESE || - m == CONTENT_MUD || - m == CONTENT_COALSTONE - ); + return (m != CONTENT_WATER + && m != CONTENT_TORCH + && m != CONTENT_TREE + && m != CONTENT_LEAVES + && m != CONTENT_OCEAN + && m != CONTENT_CLOUD); } inline bool is_mineral(u8 c) @@ -169,12 +169,18 @@ inline bool is_mineral(u8 c) || c == CONTENT_COALSTONE); } -/*inline bool content_has_faces(u8 c) +inline bool liquid_replaces_content(u8 c) { - return (m != CONTENT_IGNORE - && m != CONTENT_AIR - && m != CONTENT_TORCH); -}*/ + return (c == CONTENT_AIR || c == CONTENT_TORCH); +} + +/* + When placing a node, drection info is added to it if this is true +*/ +inline bool content_directional(u8 c) +{ + return (c == CONTENT_TORCH); +} /* Nodes make a face if contents differ and solidness differs. @@ -201,19 +207,6 @@ inline u8 face_contents(u8 m1, u8 m2) return 2; } -inline bool liquid_replaces_content(u8 c) -{ - return (c == CONTENT_AIR || c == CONTENT_TORCH); -} - -/* - When placing a node, drection info is added to it if this is true -*/ -inline bool content_directional(u8 c) -{ - return (c == CONTENT_TORCH); -} - /* Packs directions like (1,0,0), (1,-1,0) */ diff --git a/src/materials.cpp b/src/materials.cpp new file mode 100644 index 000000000..5c1419580 --- /dev/null +++ b/src/materials.cpp @@ -0,0 +1,75 @@ +#include "materials.h" + +#define MATERIAL_PROPERTIES_COUNT 256 + +// These correspond to the CONTENT_* constants +MaterialProperties g_material_properties[MATERIAL_PROPERTIES_COUNT]; + +bool g_material_properties_initialized = false; + +void setStoneLikeDiggingProperties(u8 material, float toughness) +{ + g_material_properties[material].setDiggingProperties("", + DiggingProperties(true, 15.0*toughness, 0)); + g_material_properties[material].setDiggingProperties("WPick", + DiggingProperties(true, 2.0*toughness, 65535./20.*toughness)); + g_material_properties[material].setDiggingProperties("STPick", + DiggingProperties(true, 1.0*toughness, 65535./50.*toughness)); +} + +void initializeMaterialProperties() +{ + /* + Now, the g_material_properties array is already initialized + by the constructors to such that no digging is possible. + + Add some digging properties to them. + */ + + setStoneLikeDiggingProperties(CONTENT_STONE, 1.0); + + g_material_properties[CONTENT_GRASS].setDiggingProperties("", + DiggingProperties(true, 0.5, 0)); + + g_material_properties[CONTENT_TORCH].setDiggingProperties("", + DiggingProperties(true, 0.0, 0)); + + g_material_properties[CONTENT_TREE].setDiggingProperties("", + DiggingProperties(true, 1.5, 0)); + + g_material_properties[CONTENT_LEAVES].setDiggingProperties("", + DiggingProperties(true, 0.5, 0)); + + g_material_properties[CONTENT_GRASS_FOOTSTEPS].setDiggingProperties("", + DiggingProperties(true, 0.5, 0)); + + setStoneLikeDiggingProperties(CONTENT_MESE, 0.5); + + g_material_properties[CONTENT_MUD].setDiggingProperties("", + DiggingProperties(true, 0.5, 0)); + + setStoneLikeDiggingProperties(CONTENT_COALSTONE, 1.5); + + g_material_properties[CONTENT_WOOD].setDiggingProperties("", + DiggingProperties(true, 1.0, 0)); + + + g_material_properties_initialized = true; +} + +MaterialProperties * getMaterialProperties(u8 material) +{ + assert(g_material_properties_initialized); + return &g_material_properties[material]; +} + +DiggingProperties getDiggingProperties(u8 material, const std::string &tool) +{ + MaterialProperties *mprop = getMaterialProperties(material); + if(mprop == NULL) + // Not diggable + return DiggingProperties(); + + return mprop->getDiggingProperties(tool); +} + diff --git a/src/materials.h b/src/materials.h new file mode 100644 index 000000000..ae2deac88 --- /dev/null +++ b/src/materials.h @@ -0,0 +1,98 @@ +/* +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 MATERIALS_HEADER +#define MATERIALS_HEADER + +/* + Material properties +*/ + +#include "common_irrlicht.h" +#include "inventory.h" +#include + +struct DiggingProperties +{ + DiggingProperties(): + diggable(false), + time(0.0), + wear(0) + { + } + DiggingProperties(bool a_diggable, float a_time, u16 a_wear): + diggable(a_diggable), + time(a_time), + wear(a_wear) + { + } + bool diggable; + // Digging time in seconds + float time; + // Caused wear + u16 wear; +}; + +class MaterialProperties +{ +public: + MaterialProperties() + { + dstream<<__FUNCTION_NAME<::Node *n; + n = m_digging_properties.find(toolname); + if(n == NULL) + { + // Not diggable by this tool, try to get defaults + n = m_digging_properties.find(""); + if(n == NULL) + { + // Not diggable at all + return DiggingProperties(); + } + } + // Return found properties + return n->getValue(); + } + +private: + // toolname="": default properties (digging by hand) + // Key is toolname + core::map m_digging_properties; +}; + +void initializeMaterialProperties(); + +// Material correspond to the CONTENT_* constants +MaterialProperties * getMaterialProperties(u8 material); +// For getting the default properties, set tool="" +DiggingProperties getDiggingProperties(u8 material, const std::string &tool); + +#endif + diff --git a/src/server.cpp b/src/server.cpp index c0af61b98..e1f7ba739 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "main.h" #include "constants.h" #include "voxel.h" +#include "materials.h" #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) @@ -1821,9 +1822,47 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(g_settings.getBool("creative_mode") == false) { - // Add to inventory and send inventory + /* + Wear out tool + */ + InventoryList *mlist = player->inventory.getList("main"); + if(mlist != NULL) + { + InventoryItem *item = mlist->getItem(item_i); + if(item && (std::string)item->getName() == "ToolItem") + { + ToolItem *titem = (ToolItem*)item; + std::string toolname = titem->getToolName(); + + // Get digging properties for material and tool + DiggingProperties prop = + getDiggingProperties(material, toolname); + + if(prop.diggable == false) + { + derr_server<<"Server: WARNING: Player digged" + <<" with impossible material + tool" + <<" combination"<addWear(prop.wear); + + if(weared_out) + { + mlist->deleteItem(item_i); + } + } + } + + /* + Add digged item to inventory + */ InventoryItem *item = new MaterialItem(material, 1); player->inventory.addItem("main", item); + + /* + Send inventory + */ SendInventory(player->peer_id); } @@ -2404,138 +2443,6 @@ void Server::peerAdded(con::Peer *peer) c.peer_id = peer->id; c.timeout = false; m_peer_change_queue.push_back(c); - -#if 0 - // NOTE: Connection is already locked when this is called. - // NOTE: Environment is already locked when this is called. - - // Error check - core::map::Node *n; - n = m_clients.find(peer->id); - // The client shouldn't already exist - assert(n == NULL); - - // Create client - RemoteClient *client = new RemoteClient(); - client->peer_id = peer->id; - m_clients.insert(client->peer_id, client); - - // Create player - { - Player *player = m_env.getPlayer(peer->id); - - // The player shouldn't already exist - assert(player == NULL); - - player = new ServerRemotePlayer(); - player->peer_id = peer->id; - - /* - Set player position - */ - - // We're going to throw the player to this position - //v2s16 nodepos(29990,29990); - //v2s16 nodepos(9990,9990); - v2s16 nodepos(0,0); - v2s16 sectorpos = getNodeSectorPos(nodepos); - // Get zero sector (it could have been unloaded to disk) - m_env.getMap().emergeSector(sectorpos); - // Get ground height at origin - f32 groundheight = m_env.getMap().getGroundHeight(nodepos, true); - // The sector should have been generated -> groundheight exists - assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE); - // Don't go underwater - if(groundheight < WATER_LEVEL) - groundheight = WATER_LEVEL; - - player->setPosition(intToFloat(v3s16( - nodepos.X, - groundheight + 1, - nodepos.Y - ))); - - /* - Add player to environment - */ - - m_env.addPlayer(player); - - /* - Add stuff to inventory - */ - - if(g_settings.getBool("creative_mode")) - { - // Give a good pick - { - InventoryItem *item = new ToolItem("STPick", 32000); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - // Give all materials - assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE); - 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); - } - /*// Rat - { - InventoryItem *item = new MapBlockObjectItem("Rat"); - bool r = player->inventory.addItem("main", item); - assert(r == true); - }*/ - } - else - { - { - InventoryItem *item = new CraftItem("Stick", 4); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("WPick", 32000); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - { - InventoryItem *item = new ToolItem("STPick", 32000); - void* r = player->inventory.addItem("main", item); - assert(r == NULL); - } - /*// Give some lights - { - InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999); - bool r = player->inventory.addItem("main", item); - assert(r == true); - } - // and some signs - for(u16 i=0; i<4; i++) - { - InventoryItem *item = new MapBlockObjectItem("Sign Example text"); - bool r = player->inventory.addItem("main", item); - assert(r == true); - }*/ - /*// Give some other stuff - { - InventoryItem *item = new MaterialItem(CONTENT_TREE, 999); - bool r = player->inventory.addItem("main", item); - assert(r == true); - }*/ - } - } -#endif } void Server::deletingPeer(con::Peer *peer, bool timeout) @@ -2549,46 +2456,6 @@ void Server::deletingPeer(con::Peer *peer, bool timeout) c.peer_id = peer->id; c.timeout = timeout; m_peer_change_queue.push_back(c); - -#if 0 - // NOTE: Connection is already locked when this is called. - - // NOTE: Environment is already locked when this is called. - // NOTE: Locking environment cannot be moved here because connection - // is already locked and env has to be locked before - - // Error check - core::map::Node *n; - n = m_clients.find(peer->id); - // The client should exist - assert(n != NULL); - - // Send information about leaving in chat - { - std::wstring name = L"unknown"; - Player *player = m_env.getPlayer(peer->id); - if(player != NULL) - name = narrow_to_wide(player->getName()); - - std::wstring message; - message += L"*** "; - message += name; - message += L" left game"; - BroadcastChatMessage(message); - } - - // Delete player - { - m_env.removePlayer(peer->id); - } - - // Delete client - delete m_clients[peer->id]; - m_clients.remove(peer->id); - - // Send player info to all clients - SendPlayerInfos(); -#endif } void Server::SendObjectData(float dtime) @@ -2647,6 +2514,159 @@ void Server::SendPlayerInfos() m_con.SendToAll(0, data, true); } +enum ItemSpecType +{ + ITEM_NONE, + ITEM_MATERIAL, + ITEM_CRAFT, + ITEM_TOOL, + ITEM_MBO +}; + +struct ItemSpec +{ + ItemSpec(): + type(ITEM_NONE) + { + } + ItemSpec(enum ItemSpecType a_type, std::string a_name): + type(a_type), + name(a_name), + num(65535) + { + } + ItemSpec(enum ItemSpecType a_type, u16 a_num): + type(a_type), + name(""), + num(a_num) + { + } + enum ItemSpecType type; + // Only other one of these is used + std::string name; + u16 num; +}; + +/* + items: a pointer to an array of 9 pointers to items + specs: a pointer to an array of 9 ItemSpecs +*/ +bool checkItemCombination(InventoryItem **items, ItemSpec *specs) +{ + u16 items_min_x = 100; + u16 items_max_x = 100; + u16 items_min_y = 100; + u16 items_max_y = 100; + for(u16 y=0; y<3; y++) + for(u16 x=0; x<3; x++) + { + if(items[y*3 + x] == NULL) + continue; + if(items_min_x == 100 || x < items_min_x) + items_min_x = x; + if(items_min_y == 100 || y < items_min_y) + items_min_y = y; + if(items_max_x == 100 || x > items_max_x) + items_max_x = x; + if(items_max_y == 100 || y > items_max_y) + items_max_y = y; + } + // No items at all, just return false + if(items_min_x == 100) + return false; + + u16 items_w = items_max_x - items_min_x + 1; + u16 items_h = items_max_y - items_min_y + 1; + + u16 specs_min_x = 100; + u16 specs_max_x = 100; + u16 specs_min_y = 100; + u16 specs_max_y = 100; + for(u16 y=0; y<3; y++) + for(u16 x=0; x<3; x++) + { + if(specs[y*3 + x].type == ITEM_NONE) + continue; + if(specs_min_x == 100 || x < specs_min_x) + specs_min_x = x; + if(specs_min_y == 100 || y < specs_min_y) + specs_min_y = y; + if(specs_max_x == 100 || x > specs_max_x) + specs_max_x = x; + if(specs_max_y == 100 || y > specs_max_y) + specs_max_y = y; + } + // No specs at all, just return false + if(specs_min_x == 100) + return false; + + u16 specs_w = specs_max_x - specs_min_x + 1; + u16 specs_h = specs_max_y - specs_min_y + 1; + + // Different sizes + if(items_w != specs_w || items_h != specs_h) + return false; + + for(u16 y=0; ygetName(); + + if(spec.type == ITEM_MATERIAL) + { + if(itemname != "MaterialItem") + return false; + MaterialItem *mitem = (MaterialItem*)item; + if(mitem->getMaterial() != spec.num) + return false; + } + else if(spec.type == ITEM_CRAFT) + { + if(itemname != "CraftItem") + return false; + CraftItem *mitem = (CraftItem*)item; + if(mitem->getSubName() != spec.name) + return false; + } + else if(spec.type == ITEM_TOOL) + { + // Not supported yet + assert(0); + } + else if(spec.type == ITEM_MBO) + { + // Not supported yet + assert(0); + } + else + { + // Not supported yet + assert(0); + } + } + + return true; +} + void Server::SendInventory(u16 peer_id) { DSTACK(__FUNCTION_NAME); @@ -2670,31 +2690,96 @@ void Server::SendInventory(u16 peer_id) { items[i] = clist->getItem(i); } - // Sign - if(clist->getUsedSlots() == 1 && items[0]) + + bool found = false; + + // Wood + if(!found) { - if((std::string)items[0]->getName() == "MaterialItem") + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE); + if(checkItemCombination(items, specs)) { - MaterialItem *mitem = (MaterialItem*)items[0]; - if(mitem->getMaterial() == CONTENT_TREE) - { - rlist->addItem(new MapBlockObjectItem("Sign")); - } + rlist->addItem(new MaterialItem(CONTENT_WOOD, 4)); + found = true; } } - // Torch - if(clist->getUsedSlots() == 2 && items[0] && items[3]) + + // Stick + if(!found) { - if( - (std::string)items[0]->getName() == "MaterialItem" - && ((MaterialItem*)items[0])->getMaterial() == CONTENT_COALSTONE - && (std::string)items[3]->getName() == "MaterialItem" - && ((MaterialItem*)items[3])->getMaterial() == CONTENT_TREE - ) + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new CraftItem("Stick", 4)); + found = true; + } + } + + // Sign + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new MapBlockObjectItem("Sign")); + found = true; + } + } + + // Torch + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COALSTONE); + specs[3] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) { rlist->addItem(new MaterialItem(CONTENT_TORCH, 4)); + found = true; } } + + // Wooden pick + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("WPick", 0)); + found = true; + } + } + + // Stone pick + if(!found) + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_STONE); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_STONE); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_STONE); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + if(checkItemCombination(items, specs)) + { + rlist->addItem(new ToolItem("STPick", 0)); + found = true; + } + } + } /* @@ -2958,6 +3043,16 @@ void Server::handlePeerChange(PeerChange &c) } else { + { + InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } + { + InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6); + void* r = player->inventory.addItem("main", item); + assert(r == NULL); + } { InventoryItem *item = new CraftItem("Stick", 4); void* r = player->inventory.addItem("main", item); diff --git a/src/servermain.cpp b/src/servermain.cpp index c2d697cfe..b8bc0dc54 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -123,6 +123,8 @@ int main(int argc, char *argv[]) DSTACK(__FUNCTION_NAME); + initializeMaterialProperties(); + try { diff --git a/src/tile.cpp b/src/tile.cpp index 25d9c00d0..a9470dc8e 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -36,6 +36,7 @@ const char * g_tile_texture_paths[TILES_COUNT] = "../data/mud_with_grass.png", "../data/cloud.png", "../data/coalstone.png", + "../data/wood.png", }; const char * tile_texture_path_get(u32 i) diff --git a/src/tile.h b/src/tile.h index 9823160c2..c35c27e64 100644 --- a/src/tile.h +++ b/src/tile.h @@ -40,6 +40,7 @@ enum TileID TILE_MUD_WITH_GRASS, TILE_CLOUD, TILE_COALSTONE, + TILE_WOOD, // Count of tile ids TILES_COUNT