diff --git a/data/light.png b/data/cloud.png similarity index 100% rename from data/light.png rename to data/cloud.png diff --git a/doc/README.txt b/doc/README.txt index 3467564bd..46e72e0c0 100644 --- a/doc/README.txt +++ b/doc/README.txt @@ -38,6 +38,9 @@ Configuration file: ../minetest.conf ../../minetest.conf +Command-line options: +- Use --help + Running on Windows: - The working directory should be ./bin diff --git a/makepackage_binary.sh b/makepackage_binary.sh index ad3ff33d7..b921c9aee 100755 --- a/makepackage_binary.sh +++ b/makepackage_binary.sh @@ -29,7 +29,7 @@ cp -r data/water.png $PACKAGEPATH/data/ cp -r data/tree.png $PACKAGEPATH/data/ cp -r data/leaves.png $PACKAGEPATH/data/ cp -r data/mese.png $PACKAGEPATH/data/ -cp -r data/light.png $PACKAGEPATH/data/ +cp -r data/cloud.png $PACKAGEPATH/data/ cp -r data/sign.png $PACKAGEPATH/data/ cp -r data/sign_back.png $PACKAGEPATH/data/ cp -r data/rat.png $PACKAGEPATH/data/ diff --git a/src/client.cpp b/src/client.cpp index ed3a43759..f86445720 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1140,6 +1140,35 @@ bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater) block->deSerialize(istr, ser_version); sector->insertBlock(block); //block->setChangedFlag(); + + //DEBUG + /*NodeMod mod; + mod.type = NODEMOD_CHANGECONTENT; + mod.param = CONTENT_MESE; + block->setTempMod(v3s16(8,10,8), mod); + block->setTempMod(v3s16(8,9,8), mod); + block->setTempMod(v3s16(8,8,8), mod); + block->setTempMod(v3s16(8,7,8), mod); + block->setTempMod(v3s16(8,6,8), mod);*/ + + /* + Add some coulds + Well, this is a dumb way to do it, they should just + be drawn as separate objects. + */ + /*if(p.Y == 3) + { + NodeMod mod; + mod.type = NODEMOD_CHANGECONTENT; + mod.param = CONTENT_CLOUD; + v3s16 p2; + p2.Y = 8; + for(p2.X=3; p2.X<=13; p2.X++) + for(p2.Z=3; p2.Z<=13; p2.Z++) + { + block->setTempMod(p2, mod); + } + }*/ } } //envlock @@ -1412,16 +1441,20 @@ void Client::pressGround(u8 button, v3s16 nodepos_undersurface, } /* - length: 19 + length: 17 [0] u16 command - [2] u8 button (0=left, 1=right) + [2] u8 action [3] v3s16 nodepos_undersurface [9] v3s16 nodepos_abovesurface [15] u16 item + actions: + 0: start digging + 1: place block + 2: stop digging (all parameters ignored) */ u8 datasize = 2 + 1 + 6 + 6 + 2; SharedBuffer data(datasize); - writeU16(&data[0], TOSERVER_PRESS_GROUND); + writeU16(&data[0], TOSERVER_GROUND_ACTION); writeU8(&data[2], button); writeV3S16(&data[3], nodepos_undersurface); writeV3S16(&data[9], nodepos_oversurface); @@ -1455,9 +1488,35 @@ void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item) Send(0, data, true); } -void Client::release(u8 button) +void Client::stopDigging() { - //TODO + if(connectedAndInitialized() == false){ + dout_client< data(datasize); + writeU16(&data[0], TOSERVER_GROUND_ACTION); + writeU8(&data[2], 2); + writeV3S16(&data[3], v3s16(0,0,0)); + writeV3S16(&data[9], v3s16(0,0,0)); + writeU16(&data[15], 0); + Send(0, data, true); } void Client::sendSignText(v3s16 blockpos, s16 id, std::string text) diff --git a/src/client.h b/src/client.h index 95bff0ff5..70996cfef 100644 --- a/src/client.h +++ b/src/client.h @@ -196,7 +196,7 @@ public: void pressGround(u8 button, v3s16 nodepos_undersurface, v3s16 nodepos_oversurface, u16 item); void clickObject(u8 button, v3s16 blockpos, s16 id, u16 item); - void release(u8 button); + void stopDigging(); void sendSignText(v3s16 blockpos, s16 id, std::string text); diff --git a/src/clientserver.h b/src/clientserver.h index 9d3545907..4526083da 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -159,22 +159,21 @@ enum ToServerCommand [11] u16 item */ - TOSERVER_PRESS_GROUND = 0x28, + TOSERVER_GROUND_ACTION = 0x28, /* length: 17 [0] u16 command - [2] u8 button (0=left, 1=right) + [2] u8 action [3] v3s16 nodepos_undersurface [9] v3s16 nodepos_abovesurface [15] u16 item + actions: + 0: start digging (from undersurface) + 1: place block (to abovesurface) + 2: stop digging (all parameters ignored) */ - TOSERVER_RELEASE = 0x29, - /* - length: 3 - [0] u16 command - [2] u8 button - */ + TOSERVER_RELEASE = 0x29, // Not used TOSERVER_SIGNTEXT = 0x30, /* diff --git a/src/light.cpp b/src/light.cpp index a9fe023ef..03821a672 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -19,49 +19,45 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "light.h" -/* - -#!/usr/bin/python - -from math import * -from sys import stdout - -# We want 0 at light=0 and 255 at light=LIGHT_MAX -LIGHT_MAX = 15 - -L = [] -for i in range(1,LIGHT_MAX+1): - L.append(int(round(255.0 * 0.69 ** (i-1)))) - L.append(0) - -L.reverse() -for i in L: - stdout.write(str(i)+",\n") - -*/ - -/* - The first value should be 0, the last value should be 255. -*/ +// LIGHT_MAX is 15, 0-15 is 16 values /*u8 light_decode_table[LIGHT_MAX+1] = { 0, -2, -3, -4, -6, 9, -13, -19, -28, -40, -58, -84, -121, -176, +12, +14, +16, +20, +26, +34, +45, +61, +81, +108, +143, +191, 255, };*/ +u8 light_decode_table[LIGHT_MAX+1] = +{ +0, +5, +12, +22, +35, +50, +65, +85, +100, +120, +140, +160, +185, +215, +255, +}; +#if 0 /* #!/usr/bin/python @@ -100,48 +96,6 @@ u8 light_decode_table[LIGHT_MAX+1] = 191, 255, }; - -/* -#!/usr/bin/python - -from math import * -from sys import stdout - -# We want 0 at light=0 and 255 at light=LIGHT_MAX -LIGHT_MAX = 14 -#FACTOR = 0.69 -FACTOR = 0.75 - -maxlight = 255 -minlight = 8 - -L = [] -for i in range(1,LIGHT_MAX+1): - L.append(minlight+int(round((maxlight-minlight) * FACTOR ** (i-1)))) - #L.append(int(round(255.0 * FACTOR ** (i-1)))) -L.append(minlight) - -L.reverse() -for i in L: - stdout.write(str(i)+",\n") -*/ -/*u8 light_decode_table[LIGHT_MAX+1] = -{ -8, -14, -16, -18, -22, -27, -33, -41, -52, -67, -86, -112, -147, -193, -255, -};*/ +#endif diff --git a/src/light.h b/src/light.h index 871426901..1827ab53a 100644 --- a/src/light.h +++ b/src/light.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // This directly sets the range of light #define LIGHT_MAX 14 +// Light is stored as 4 bits, thus 15 is the maximum. // This brightness is reserved for sunlight #define LIGHT_SUN 15 diff --git a/src/main.cpp b/src/main.cpp index b4e2d478c..5d1be0184 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,50 +27,7 @@ NOTE: VBO cannot be turned on for fast-changing stuff because there NOTE: iostream.imbue(std::locale("C")) is very slow NOTE: Global locale is now set at initialization -SUGGESTION: add a second lighting value to the MS nibble of param of - air to tell how bright the air node is when there is no sunlight. - When day changes to night, these two values can be interpolated. - -TODO: Fix address to be ipv6 compatible - -TODO: ESC Pause mode in which the cursor is not kept at the center of window. -TODO: Stop player if focus of window is taken away (go to pause mode) -TODO: Optimize and fix makeFastFace or whatever it's called - - Face calculation is the source of CPU usage on the client -SUGGESTION: The client will calculate and send lighting changes and - the server will randomly check some of them and kick the client out - if it fails to calculate them right. - - Actually, it could just start ignoring them and calculate them - itself. -SUGGESTION: Combine MapBlock's face caches to so big pieces that VBO - gets used - - That is >500 vertices - -TODO: Better dungeons -TODO: There should be very slight natural caves also, starting from - only a straightened-up cliff - -TODO: Changing of block with mouse wheel or something -TODO: Menus - -TODO: Mobs - - Server: - - One single map container with ids as keys - - Client: - - ? -TODO: - Keep track of the place of the mob in the last few hundreth's - of a second - then, if a player hits it, take the value that is - avg_rtt/2 before the moment the packet is received. -TODO: - Scripting - -SUGGESTION: Modify client to calculate single changes asynchronously - -TODO: Moving players more smoothly. Calculate moving animation - in a way that doesn't make the player jump to the right place - immediately when the server sends a new position - -TODO: There are some lighting-related todos and fixmes in - ServerMap::emergeBlock +SUGG: Fix address to be ipv6 compatible FIXME: When a new sector is generated, it may change the ground level of it's and it's neighbors border that two blocks that are @@ -81,15 +38,7 @@ SUGGESTION: Use same technique for sector heightmaps as what we're using for UnlimitedHeightmap? (getting all neighbors when generating) -TODO: Proper handling of spawning place (try to find something that - is not in the middle of an ocean (some land to stand on at - least) and save it in map config. -SUGG: Set server to automatically find a good spawning place in some - place where there is water and land. - - Map to have a getWalkableNear(p) - - Is this a good idea? It's part of the game to find a good place. - -TODO: Transfer more blocks in a single packet +SUGG: Transfer more blocks in a single packet SUGG: A blockdata combiner class, to which blocks are added and at destruction it sends all the stuff in as few packets as possible. @@ -100,53 +49,18 @@ SUGG: Expose Connection's seqnums and ACKs to server and client. - This enables saving many packets and making a faster connection - This also enables server to check if client has received the most recent block sent, for example. -TODO: Add a sane bandwidth throttling system to Connection +SUGG: Add a sane bandwidth throttling system to Connection SUGG: More fine-grained control of client's dumping of blocks from memory - ...What does this mean in the first place? -TODO: Make the amount of blocks sending to client and the total - amount of blocks dynamically limited. Transferring blocks is the - main network eater of this system, so it is the one that has - to be throttled so that RTTs stay low. - -TODO: Server to load starting inventory from disk - -TODO: PLayers to only be hidden when the client quits. -TODO: - Players to be saved on disk, with inventory -TODO: Players to be saved as text in map/players/ - SUGG: A map editing mode (similar to dedicated server mode) -TODO: Make fetching sector's blocks more efficient when rendering - sectors that have very large amounts of blocks (on client) - -TODO: Make the video backend selectable - -Block object server side: - - A "near blocks" buffer, in which some nearby blocks are stored. - - For all blocks in the buffer, objects are stepped(). This - means they are active. - - TODO: A global active buffer is needed for the server - - TODO: All blocks going in and out of the buffer are recorded. - - TODO: For outgoing blocks, a timestamp is written. - - TODO: For incoming blocks, the time difference is calculated and - objects are stepped according to it. -TODO: A timestamp to blocks - SUGG: Add a time value to the param of footstepped grass and check it against a global timer when a block is accessed, to make old steps fade away. -TODO: Add config parameters for server's sending and generating distance - -TODO: Copy the text of the last picked sign to inventory in creative - mode - -TODO: Untie client network operations from framerate - - Needs some input queues or something - SUGG: Make a copy of close-range environment on client for showing on screen, with minimal mutexes to slow down the main loop @@ -161,15 +75,9 @@ SUGG: Split MapBlockObject serialization to to-client and to-disk - This will allow saving ages of rats on disk but not sending them to clients -TODO: Get rid of GotSplitPacketException - SUGG: Implement lighting using VoxelManipulator - Would it be significantly faster? -TODO: Check what goes wrong with caching map to disk (Kray) - -TODO: Remove LazyMeshUpdater. It is not used as supposed. - FIXME: Rats somehow go underground sometimes (you can see it in water) - Does their position get saved to a border value or something? - Does this happen anymore? @@ -184,9 +92,97 @@ SUGG: Implement a "Fast check queue" (a queue with a map for checking SUGG: Signs could be done in the same way as torches. For this, blocks need an additional metadata field for the texts +SUGG: Precalculate lighting translation table at runtime (at startup) + +SUGG: A version number to blocks, which increments when the block is + modified (node add/remove, water update, lighting update) + - This can then be used to make sure the most recent version of + a block has been sent to client + +TODO: Stop player if focus of window is taken away (go to pause mode) + +TODO: Combine MapBlock's face caches to so big pieces that VBO + gets used + - That is >500 vertices + +TODO: Better dungeons +TODO: Cliffs, arcs + +TODO: Menus + +TODO: Mobs + - Server: + - One single map container with ids as keys + - Client: + - ? +TODO: - Keep track of the place of the mob in the last few hundreth's + of a second - then, if a player hits it, take the value that is + avg_rtt/2 before the moment the packet is received. +TODO: - Scripting + +TODO: Moving players more smoothly. Calculate moving animation + in a way that doesn't make the player jump to the right place + immediately when the server sends a new position + +TODO: There are some lighting-related todos and fixmes in + ServerMap::emergeBlock + +TODO: Proper handling of spawning place (try to find something that + is not in the middle of an ocean (some land to stand on at + least) and save it in map config. + +TODO: Make the amount of blocks sending to client and the total + amount of blocks dynamically limited. Transferring blocks is the + main network eater of this system, so it is the one that has + to be throttled so that RTTs stay low. + +TODO: Server to load starting inventory from disk + +TODO: Players to only be hidden when the client quits. +TODO: - Players to be saved on disk, with inventory +TODO: Players to be saved as text in map/players/ + +TODO: Make fetching sector's blocks more efficient when rendering + sectors that have very large amounts of blocks (on client) + +TODO: Make the video backend selectable + +Block object server side: + - A "near blocks" buffer, in which some nearby blocks are stored. + - For all blocks in the buffer, objects are stepped(). This + means they are active. + - TODO: A global active buffer is needed for the server + - TODO: A timestamp to blocks + - TODO: All blocks going in and out of the buffer are recorded. + - TODO: For outgoing blocks, timestamp is written. + - TODO: For incoming blocks, time difference is calculated and + objects are stepped according to it. + +TODO: Add config parameters for server's sending and generating distance + +TODO: Copy the text of the last picked sign to inventory in creative + mode + +TODO: Untie client network operations from framerate + - Needs some input queues or something + +TODO: Get rid of GotSplitPacketException + +TODO: Check what goes wrong with caching map to disk (Kray) + +TODO: Remove LazyMeshUpdater. It is not used as supposed. + +TODO: Node cracking animation when digging + - TODO: A way to generate new textures by combining textures + - TODO: Mesh update to fetch cracked faces from the former + Doing now: ====================================================================== +TODO: Add a second lighting value to the MS nibble of param of + air to tell how bright the air node is when there is no sunlight. + When day changes to night, these two values can be interpolated. + - The biggest job is to add support to the lighting routines ====================================================================== @@ -486,6 +482,10 @@ public: if(event.EventType == irr::EET_MOUSE_INPUT_EVENT) { + left_active = event.MouseInput.isLeftPressed(); + middle_active = event.MouseInput.isMiddlePressed(); + right_active = event.MouseInput.isRightPressed(); + if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { leftclicked = true; @@ -494,6 +494,14 @@ public: { rightclicked = true; } + if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) + { + leftreleased = true; + } + if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) + { + rightreleased = true; + } if(event.MouseInput.Event == EMIE_MOUSE_WHEEL) { /*dstream<<"event.MouseInput.Wheel=" @@ -530,10 +538,23 @@ public: keyIsDown[i] = false; leftclicked = false; rightclicked = false; + leftreleased = false; + rightreleased = false; + + left_active = false; + middle_active = false; + right_active = false; } bool leftclicked; bool rightclicked; + bool leftreleased; + bool rightreleased; + + bool left_active; + bool middle_active; + bool right_active; + private: // We use this array to store the current state of each key bool keyIsDown[KEY_KEY_CODES_COUNT]; @@ -550,13 +571,24 @@ public: virtual ~InputHandler() { } + virtual bool isKeyDown(EKEY_CODE keyCode) = 0; + virtual v2s32 getMousePos() = 0; virtual void setMousePos(s32 x, s32 y) = 0; + + virtual bool getLeftState() = 0; + virtual bool getRightState() = 0; + virtual bool getLeftClicked() = 0; virtual bool getRightClicked() = 0; virtual void resetLeftClicked() = 0; virtual void resetRightClicked() = 0; + + virtual bool getLeftReleased() = 0; + virtual bool getRightReleased() = 0; + virtual void resetLeftReleased() = 0; + virtual void resetRightReleased() = 0; virtual void step(float dtime) {}; @@ -597,6 +629,15 @@ public: m_device->getCursorControl()->setPosition(x, y); } + virtual bool getLeftState() + { + return m_receiver->left_active; + } + virtual bool getRightState() + { + return m_receiver->right_active; + } + virtual bool getLeftClicked() { if(g_game_focused == false) @@ -618,6 +659,27 @@ public: m_receiver->rightclicked = false; } + virtual bool getLeftReleased() + { + if(g_game_focused == false) + return false; + return m_receiver->leftreleased; + } + virtual bool getRightReleased() + { + if(g_game_focused == false) + return false; + return m_receiver->rightreleased; + } + virtual void resetLeftReleased() + { + m_receiver->leftreleased = false; + } + virtual void resetRightReleased() + { + m_receiver->rightreleased = false; + } + void clear() { resetRightClicked(); @@ -651,6 +713,15 @@ public: mousepos = v2s32(x,y); } + virtual bool getLeftState() + { + return false; + } + virtual bool getRightState() + { + return false; + } + virtual bool getLeftClicked() { return leftclicked; @@ -668,6 +739,21 @@ public: rightclicked = false; } + virtual bool getLeftReleased() + { + return false; + } + virtual bool getRightReleased() + { + return false; + } + virtual void resetLeftReleased() + { + } + virtual void resetRightReleased() + { + } + virtual void step(float dtime) { { @@ -1563,6 +1649,11 @@ int main(int argc, char *argv[]) //gui::IGUIWindow* input_window = NULL; gui::IGUIStaticText* input_guitext = NULL; + /* + Digging animation + */ + //f32 + /* Main loop */ @@ -1920,6 +2011,10 @@ int main(int argc, char *argv[]) } else // selected_object == NULL { + + /* + Find out which node we are pointing at + */ bool nodefound = false; v3s16 nodepos; @@ -2066,6 +2161,9 @@ int main(int argc, char *argv[]) } // regular block } // for coords + /*static v3s16 oldnodepos; + static bool oldnodefound = false;*/ + if(nodefound) { //std::cout<setText(positiontext);*/ } hilightboxes.push_back(nodefacebox); - if(g_input->getLeftClicked()) + //if(g_input->getLeftClicked()) + if(g_input->getLeftClicked() || + (g_input->getLeftState() && nodepos != nodepos_old)) { - //std::cout<getRightClicked()) + /*if(g_input->getRightClicked() || + (g_input->getRightState() && nodepos != nodepos_old))*/ { - //std::cout<setText(L""); } + /*oldnodefound = nodefound; + oldnodepos = nodepos;*/ + } // selected_object == NULL g_input->resetLeftClicked(); g_input->resetRightClicked(); + if(g_input->getLeftReleased()) + { + std::cout<getRightReleased()) + { + //std::cout<resetLeftReleased(); + g_input->resetRightReleased(); + /* Calculate stuff for drawing */ diff --git a/src/map.cpp b/src/map.cpp index caebb5161..7b057840d 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -18,7 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "map.h" -//#include "player.h" #include "main.h" #include "jmutexautolock.h" #include "client.h" @@ -112,13 +111,6 @@ Map::~Map() } } -/*bool Map::sectorExists(v2s16 p) -{ - JMutexAutoLock lock(m_sector_mutex); - core::map::Node *n = m_sectors.find(p); - return (n != NULL); -}*/ - MapSector * Map::getSectorNoGenerate(v2s16 p) { JMutexAutoLock lock(m_sector_mutex); @@ -160,20 +152,6 @@ MapBlock * Map::getBlockNoCreate(v3s16 p3d) return block; } -/*MapBlock * Map::getBlock(v3s16 p3d, bool generate) -{ - dstream<<"Map::getBlock() with generate=true called" - <getBlockNoCreate(p3d.Y); -}*/ - f32 Map::getGroundHeight(v2s16 p, bool generate) { try{ @@ -215,156 +193,6 @@ bool Map::isNodeUnderground(v3s16 p) } } -#if 0 -void Map::interpolate(v3s16 block, - core::map & modified_blocks) -{ - const v3s16 dirs[6] = { - v3s16(0,0,1), // back - v3s16(0,1,0), // top - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(0,-1,0), // bottom - v3s16(-1,0,0), // left - }; - - if(from_nodes.size() == 0) - return; - - u32 blockchangecount = 0; - - core::map lighted_nodes; - core::map::Iterator j; - j = from_nodes.getIterator(); - - /* - Initialize block cache - */ - v3s16 blockpos_last; - MapBlock *block = NULL; - // Cache this a bit, too - bool block_checked_in_modified = false; - - for(; j.atEnd() == false; j++) - //for(; j != from_nodes.end(); j++) - { - v3s16 pos = j.getNode()->getKey(); - //v3s16 pos = *j; - //dstream<<"pos=("<isDummy()) - continue; - - // Calculate relative position in block - v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE; - - // Get node straight from the block - MapNode n = block->getNode(relpos); - - u8 oldlight = n.getLight(); - u8 newlight = diminish_light(oldlight); - - // Loop through 6 neighbors - for(u16 i=0; i<6; i++){ - // Get the position of the neighbor node - v3s16 n2pos = pos + dirs[i]; - - // Get the block where the node is located - v3s16 blockpos = getNodeBlockPos(n2pos); - - try - { - // Only fetch a new block if the block position has changed - try{ - if(block == NULL || blockpos != blockpos_last){ - block = getBlockNoCreate(blockpos); - blockpos_last = blockpos; - - block_checked_in_modified = false; - blockchangecount++; - } - } - catch(InvalidPositionException &e) - { - continue; - } - - // Calculate relative position in block - v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; - // Get node straight from the block - MapNode n2 = block->getNode(relpos); - - bool changed = false; - /* - If the neighbor is brighter than the current node, - add to list (it will light up this node on its turn) - */ - if(n2.getLight() > undiminish_light(oldlight)) - { - lighted_nodes.insert(n2pos, true); - //lighted_nodes.push_back(n2pos); - changed = true; - } - /* - If the neighbor is dimmer than how much light this node - would spread on it, add to list - */ - if(n2.getLight() < newlight) - { - if(n2.light_propagates()) - { - n2.setLight(newlight); - block->setNode(relpos, n2); - lighted_nodes.insert(n2pos, true); - //lighted_nodes.push_back(n2pos); - changed = true; - } - } - - // Add to modified_blocks - if(changed == true && block_checked_in_modified == false) - { - // If the block is not found in modified_blocks, add. - if(modified_blocks.find(blockpos) == NULL) - { - modified_blocks.insert(blockpos, block); - } - block_checked_in_modified = true; - } - } - catch(InvalidPositionException &e) - { - continue; - } - } - } - - /*dstream<<"spreadLight(): Changed block " - < 0) - spreadLight(lighted_nodes, modified_blocks); -} -#endif - /* Goes recursively through the neighbours of the node. @@ -813,11 +641,6 @@ void Map::updateLighting(core::map & a_blocks, bool debug=false; u32 count_was = modified_blocks.size(); - /*core::list::Iterator i = a_blocks.begin(); - for(; i != a_blocks.end(); i++) - { - MapBlock *block = *i;*/ - core::map light_sources; core::map unlight_from; @@ -2764,6 +2587,8 @@ ClientMap::ClientMap( m_client(client), mesh(NULL) { + mesh_mutex.Init(); + /*m_box = core::aabbox3d(0,0,0, map->getW()*BS, map->getH()*BS, map->getD()*BS);*/ /*m_box = core::aabbox3d(0,0,0, @@ -2772,8 +2597,8 @@ ClientMap::ClientMap( map->getSizeNodes().Z * BS);*/ m_box = core::aabbox3d(-BS*1000000,-BS*1000000,-BS*1000000, BS*1000000,BS*1000000,BS*1000000); - - mesh_mutex.Init(); + + //setPosition(v3f(BS,BS,BS)); } ClientMap::~ClientMap() diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 86bd9c98c..1afe00001 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -68,7 +68,7 @@ void MapBlock::setNodeParent(v3s16 p, MapNode & n) } } -FastFace * MapBlock::makeFastFace(u16 tile, u8 light, v3f p, +FastFace * MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, v3s16 dir, v3f scale, v3f posRelative_f) { FastFace *f = new FastFace; @@ -118,7 +118,7 @@ FastFace * MapBlock::makeFastFace(u16 tile, u8 light, v3f p, u8 alpha = 255; - if(tile == TILE_WATER) + if(tile.id == TILE_WATER) { alpha = 128; } @@ -184,25 +184,78 @@ u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir) /* Gets node tile from any place relative to block. - Returns CONTENT_IGNORE if doesn't exist or should not be drawn. + Returns TILE_NODE if doesn't exist or should not be drawn. */ -u16 MapBlock::getNodeTile(v3s16 p, v3s16 face_dir) +TileSpec MapBlock::getNodeTile(v3s16 p, v3s16 face_dir) { + TileSpec spec; + + spec.feature = TILEFEAT_NONE; try{ MapNode n = getNodeParent(p); - //return content_tile(n.d); - return n.getTile(face_dir); + spec.id = n.getTile(face_dir); } catch(InvalidPositionException &e) { - //return CONTENT_IGNORE; - return TILE_NONE; + spec.id = TILE_NONE; } + + /* + Check temporary modifications on this node + */ + core::map::Node *n; + n = m_temp_mods.find(p); + + // If modified + if(n != NULL) + { + struct NodeMod mod = n->getValue(); + if(mod.type == NODEMOD_CHANGECONTENT) + { + spec.id = content_tile(mod.param, face_dir); + } + if(mod.type == NODEMOD_CRACK) + { + } + } + + return spec; } u8 MapBlock::getNodeContent(v3s16 p) { + /* + Check temporary modifications on this node + */ + core::map::Node *n; + n = m_temp_mods.find(p); + + // If modified + if(n != NULL) + { + struct NodeMod mod = n->getValue(); + if(mod.type == NODEMOD_CHANGECONTENT) + { + // Overrides content + return mod.param; + } + if(mod.type == NODEMOD_CRACK) + { + /* + Content doesn't change. + + face_contents works just like it should, because + there should not be faces between differently cracked + nodes. + + If a semi-transparent node is cracked in front an + another one, it really doesn't matter whether there + is a cracked face drawn in between or not. + */ + } + } + try{ MapNode n = getNodeParent(p); @@ -243,16 +296,16 @@ void MapBlock::updateFastFaceRow(v3s16 startpos, u16 continuous_tiles_count = 0; - u8 tile0 = getNodeTile(p, face_dir); - u8 tile1 = getNodeTile(p + face_dir, -face_dir); + TileSpec tile0 = getNodeTile(p, face_dir); + TileSpec tile1 = getNodeTile(p + face_dir, -face_dir); for(u16 j=0; jmaterial], f->vertices, 4, - indices, 6);*/ - /*collector.append(g_materials[f->tile], f->vertices, 4, - indices, 6);*/ - collector.append(g_tile_materials[f->tile], f->vertices, 4, - indices, 6); + + if(f->tile.feature == TILEFEAT_NONE) + { + collector.append(g_tile_materials[f->tile.id], f->vertices, 4, + indices, 6); + } + else + { + // Not implemented + assert(0); + } } collector.fillMesh(mesh_new); // Use VBO for mesh (this just would set this for ever buffer) - //mesh_new->setHardwareMappingHint(scene::EHM_STATIC); + mesh_new->setHardwareMappingHint(scene::EHM_STATIC); /*std::cout<<"MapBlock has "<getSize()<<" faces " <<"and uses "<getMeshBufferCount() diff --git a/src/mapblock.h b/src/mapblock.h index 608249383..ebc2b52ff 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -46,10 +46,27 @@ enum{ struct FastFace { - u16 tile; + TileSpec tile; video::S3DVertex vertices[4]; // Precalculated vertices }; +enum NodeModType +{ + NODEMOD_NONE, + NODEMOD_CHANGECONTENT, //param is content id + NODEMOD_CRACK // param is crack progression +}; + +struct NodeMod +{ + NodeMod() + { + type = NODEMOD_NONE; + } + enum NodeModType type; + u16 param; +}; + enum { NODECONTAINER_ID_MAPBLOCK, @@ -283,12 +300,12 @@ public: setNode(x0+x, y0+y, z0+z, node); } - static FastFace * makeFastFace(u16 tile, u8 light, v3f p, + static FastFace * makeFastFace(TileSpec tile, u8 light, v3f p, v3s16 dir, v3f scale, v3f posRelative_f); u8 getFaceLight(v3s16 p, v3s16 face_dir); - u16 getNodeTile(v3s16 p, v3s16 face_dir); + TileSpec getNodeTile(v3s16 p, v3s16 face_dir); u8 getNodeContent(v3s16 p); /* @@ -380,6 +397,24 @@ public: { return m_objects.getCount(); } + + /* + Methods for setting temporary modifications to nodes for + drawing + */ + void setTempMod(v3s16 p, NodeMod mod) + { + m_temp_mods[p] = mod; + } + void clearTempMod(v3s16 p) + { + if(m_temp_mods.find(p)) + m_temp_mods.remove(p); + } + void clearTempMods() + { + m_temp_mods.clear(); + } /* Serialization @@ -432,6 +467,9 @@ private: MapBlockObjectList m_objects; + // Temporary modifications to nodes + // These are only used when drawing + core::map m_temp_mods; }; inline bool blockpos_over_limit(v3s16 p) diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 973b89ddd..883c18842 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -41,6 +41,7 @@ u16 g_content_tiles[USEFUL_CONTENT_COUNT][6] = {TILE_MESE,TILE_MESE,TILE_MESE,TILE_MESE,TILE_MESE,TILE_MESE}, {TILE_MUD,TILE_MUD,TILE_MUD,TILE_MUD,TILE_MUD,TILE_MUD}, {TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER}, + {TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD,TILE_CLOUD}, }; const char * g_content_inventory_textures[USEFUL_CONTENT_COUNT] = @@ -55,5 +56,6 @@ const char * g_content_inventory_textures[USEFUL_CONTENT_COUNT] = "mese", "mud", "water", + "cloud", }; diff --git a/src/mapnode.h b/src/mapnode.h index 680884bcd..731442011 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -75,6 +75,7 @@ enum Content CONTENT_MESE, CONTENT_MUD, CONTENT_OCEAN, + CONTENT_CLOUD, // This is set to the number of the actual values in this enum USEFUL_CONTENT_COUNT @@ -367,7 +368,8 @@ struct MapNode // If not transparent, can't set light if(light_propagates() == false) return; - param = a_light; + param &= 0xf0; + param |= a_light; } u16 getTile(v3s16 dir) diff --git a/src/server.cpp b/src/server.cpp index 88a8492c1..6b026d9a7 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1101,22 +1101,110 @@ void Server::AsyncRunStep() } } - // Run time- and client- related stuff - // NOTE: If you intend to add something here, check that it - // doesn't fit in RemoteClient::GetNextBlocks for example. - /*{ - // Clients are behind connection lock - JMutexAutoLock lock(m_con_mutex); + /* + Update digging + + NOTE: Some of this could be moved to RemoteClient + */ + + { + JMutexAutoLock envlock(m_env_mutex); + JMutexAutoLock conlock(m_con_mutex); for(core::map::Iterator i = m_clients.getIterator(); i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - //con::Peer *peer = m_con.GetPeer(client->peer_id); - //client->RunSendingTimeouts(dtime, peer->resend_timeout); + Player *player = m_env.getPlayer(client->peer_id); + + JMutexAutoLock digmutex(client->m_dig_mutex); + + if(client->m_dig_tool_item == -1) + continue; + + client->m_dig_time_remaining -= dtime; + + if(client->m_dig_time_remaining > 0) + continue; + + v3s16 p_under = client->m_dig_position; + + // Mandatory parameter; actually used for nothing + core::map modified_blocks; + + u8 material; + + try + { + // Get material at position + material = m_env.getMap().getNode(p_under).d; + // If it's not diggable, do nothing + if(content_diggable(material) == false) + { + derr_server<<"Server: Not finishing digging: Node not diggable" + <m_dig_tool_item = -1; + break; + } + } + catch(InvalidPositionException &e) + { + derr_server<<"Server: Not finishing digging: Node not found" + <m_dig_tool_item = -1; + break; + } + + // Create packet + u32 replysize = 8; + SharedBuffer reply(replysize); + writeU16(&reply[0], TOCLIENT_REMOVENODE); + writeS16(&reply[2], p_under.X); + writeS16(&reply[4], p_under.Y); + writeS16(&reply[6], p_under.Z); + // Send as reliable + m_con.SendToAll(0, reply, true); + + if(g_settings.getBool("creative_mode") == false) + { + // Add to inventory and send inventory + InventoryItem *item = new MaterialItem(material, 1); + player->inventory.addItem(item); + SendInventory(player->peer_id); + } + + /* + Remove the node + (this takes some time so it is done after the quick stuff) + */ + m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + + /* + Update water + */ + + // Update water pressure around modification + // This also adds it to m_flow_active_nodes if appropriate + + MapVoxelManipulator v(&m_env.getMap()); + v.m_disable_water_climb = + g_settings.getBool("disable_water_climb"); + + VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1)); + + try + { + v.updateAreaWaterPressure(area, m_flow_active_nodes); + } + catch(ProcessingLimitException &e) + { + dstream<<"Processing limit reached (1)"<removeObject(id); } } - else if(command == TOSERVER_PRESS_GROUND) + else if(command == TOSERVER_GROUND_ACTION) { if(datasize < 17) return; /* length: 17 [0] u16 command - [2] u8 button (0=left, 1=right) + [2] u8 action [3] v3s16 nodepos_undersurface [9] v3s16 nodepos_abovesurface [15] u16 item + actions: + 0: start digging + 1: place block + 2: stop digging (all parameters ignored) */ - u8 button = readU8(&data[2]); + u8 action = readU8(&data[2]); v3s16 p_under; p_under.X = readS16(&data[3]); p_under.Y = readS16(&data[5]); @@ -1492,13 +1584,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) //TODO: Check that target is reasonably close /* - Left button digs ground + 0: start digging */ - if(button == 0) + if(action == 0) { - core::map modified_blocks; - u8 material; try @@ -1513,70 +1603,39 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } catch(InvalidPositionException &e) { - derr_server<<"Server: Ignoring REMOVENODE: Node not found" + derr_server<<"Server: Not starting digging: Node not found" <id); + JMutexAutoLock(client->m_dig_mutex); + client->m_dig_tool_item = 0; + client->m_dig_position = p_under; + client->m_dig_time_remaining = 1.0; + // Reset build time counter getClient(peer->id)->m_time_from_building.set(0.0); - // Create packet - u32 replysize = 8; - SharedBuffer reply(replysize); - writeU16(&reply[0], TOCLIENT_REMOVENODE); - writeS16(&reply[2], p_under.X); - writeS16(&reply[4], p_under.Y); - writeS16(&reply[6], p_under.Z); - // Send as reliable - m_con.SendToAll(0, reply, true); - - if(g_settings.getBool("creative_mode") == false) - { - // Add to inventory and send inventory - InventoryItem *item = new MaterialItem(material, 1); - player->inventory.addItem(item); - SendInventory(player->peer_id); - } + } // action == 0 - /* - Remove the node - (this takes some time so it is done after the quick stuff) - */ - m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); - - /* - Update water - */ - - // Update water pressure around modification - // This also adds it to m_flow_active_nodes if appropriate - - MapVoxelManipulator v(&m_env.getMap()); - v.m_disable_water_climb = - g_settings.getBool("disable_water_climb"); - - VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1)); - - try - { - v.updateAreaWaterPressure(area, m_flow_active_nodes); - } - catch(ProcessingLimitException &e) - { - dstream<<"Processing limit reached (1)"<id); + JMutexAutoLock digmutex(client->m_dig_mutex); + client->m_dig_tool_item = -1; + } + + /* + 1: place block + */ + else if(action == 1) { // Get item @@ -1772,16 +1831,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } } - } // button == 1 + } // action == 1 /* - Catch invalid buttons + Catch invalid actions */ else { - derr_server<<"WARNING: Server: Invalid button " - < groundheight exists assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE); // Don't go underwater if(groundheight < WATER_LEVEL) groundheight = WATER_LEVEL; player->setPosition(intToFloat(v3s16( - 0, + nodepos.X, groundheight + 1, - 0 + nodepos.Y ))); /* diff --git a/src/server.h b/src/server.h index 273a7d5ef..851a5ba67 100644 --- a/src/server.h +++ b/src/server.h @@ -276,7 +276,6 @@ public: RemoteClient(): m_time_from_building(9999) - //m_num_blocks_in_emerge_queue(0) { peer_id = 0; serialization_version = SER_FMT_VER_INVALID; @@ -285,6 +284,10 @@ public: m_blocks_sent_mutex.Init(); m_blocks_sending_mutex.Init(); + + m_dig_mutex.Init(); + m_dig_time_remaining = 0; + m_dig_tool_item = -1; } ~RemoteClient() { @@ -338,8 +341,6 @@ public: JMutexAutoLock l2(m_blocks_sent_mutex); JMutexAutoLock l3(m_blocks_sending_mutex); o<<"RemoteClient "<