Resumable digging
authorZefram <zefram@fysh.org>
Sat, 5 Jul 2014 20:29:07 +0000 (21:29 +0100)
committerZefram <zefram@fysh.org>
Fri, 8 Aug 2014 23:37:03 +0000 (00:37 +0100)
When a node is partially dug but then digging stops, retain the invested
digging effort for a while rather than discard it.  Digging of that node
can be resumed from the partially-dug state.

The ultimate vision towards which this works is that the effort required
to dig a node could be shared not just between multiple left clicks but
also between multiple tools and even multiple players, each involved
tool suffering wear pro rata.  This would necessarily be mediated by
the server, and would even, through partial tool wear, be semantically
visible to mods.  This patch doesn't do that.  This patch does the simple
client-side version, under the prevailing paradigm that all the effort of
digging a node is credited to a single tool.  This requires that the total
time invested to dig the node must be at least what the dominant tool
would take, regardless of which other tools were involved in the digging.

When a node is partially dug, what is retained is the time that was
spent digging it, regardless of which tool was used.  The partially-dug
node shows the crack progression that it had reached with the tool last
used on it, which is based on the time spent digging divided by the time
that would be taken to fully dig using that tool.  When resuming digging,
if a different tool is used, the time spent digging is simply added up,
and the crack progression is recomputed for the new tool's total dig time.
This can result in crack progression jumping forward or backward.

A partially-dug state is retained for only one node at a time: starting
digging on a different node throws away the partially-dug state.
The partial digging effort also decays over time: whatever dig time was
accumulated when digging stops will be lost linearly over the next ten
seconds.  Resuming digging stops the decay, and new dig time is added
onto the decayed accumulated time.  If the resumed digging is stopped
again at a partially-dug state then a fresh ten-second decay process
starts, using the revised accumulated dig time.

src/game.cpp

index 768193147dd575dff3f7bbe4ce1d7ff74cd5249e..823bce1855b09863418684899934db48c508f38f 100644 (file)
@@ -1593,7 +1593,9 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
 
        float nodig_delay_timer = 0.0;
        float dig_time = 0.0;
-       u16 dig_index = 0;
+       float dig_time_decay_rate = 0.0;
+       float dig_time_complete = 0.0;
+       v3s16 dig_pos = v3s16(0,0,0);
        PointedThing pointed_old;
        bool digging = false;
        bool ldown_for_dig = false;
@@ -2783,8 +2785,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        if(!digging)
                        {
                                client.interact(1, pointed_old);
-                               client.setCrack(-1, v3s16(0,0,0));
-                               dig_time = 0.0;
+                               dig_time_decay_rate = dig_time * 0.1;
                        }
                }
                if(!digging && ldown_for_dig && !input->getLeftState())
@@ -2837,8 +2838,14 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                {
                                        infostream<<"Started digging"<<std::endl;
                                        client.interact(0, pointed);
+                                       if(dig_pos != nodepos) {
+                                               dig_pos = nodepos;
+                                               dig_time = 0;
+                                       }
                                        digging = true;
                                        ldown_for_dig = true;
+                               } else {
+                                       dig_time += dtime;
                                }
                                MapNode n = client.getEnv().getClientMap().getNode(nodepos);
 
@@ -2855,8 +2862,6 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                                params = getDigParams(nodedef->get(n).groups, tp);
                                }
 
-                               float dig_time_complete = 0.0;
-
                                if(params.diggable == false)
                                {
                                        // I guess nobody will wait for this long
@@ -2875,17 +2880,6 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        }
                                }
 
-                               if(dig_time_complete >= 0.001)
-                               {
-                                       dig_index = (u16)((float)crack_animation_length
-                                                       * dig_time/dig_time_complete);
-                               }
-                               // This is for torches
-                               else
-                               {
-                                       dig_index = crack_animation_length;
-                               }
-
                                SimpleSoundSpec sound_dig = nodedef->get(n).sound_dig;
                                if(sound_dig.exists() && params.diggable){
                                        if(sound_dig.name == "__group"){
@@ -2900,21 +2894,9 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        }
                                }
 
-                               // Don't show cracks if not diggable
-                               if(dig_time_complete >= 100000.0)
-                               {
-                               }
-                               else if(dig_index < crack_animation_length)
-                               {
-                                       //TimeTaker timer("client.setTempMod");
-                                       //infostream<<"dig_index="<<dig_index<<std::endl;
-                                       client.setCrack(dig_index, nodepos);
-                               }
-                               else
-                               {
+                               if(dig_time >= dig_time_complete) {
                                        infostream<<"Digging completed"<<std::endl;
                                        client.interact(2, pointed);
-                                       client.setCrack(-1, v3s16(0,0,0));
                                        MapNode wasnode = map.getNode(nodepos);
                                        client.removeNode(nodepos);
 
@@ -2948,13 +2930,6 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        gamedef->event()->put(e);
                                }
 
-                               if(dig_time_complete < 100000.0)
-                                       dig_time += dtime;
-                               else {
-                                       dig_time = 0;
-                                       client.setCrack(-1, nodepos);
-                               }
-
                                camera.setDigging(0);  // left click animation
                        }
 
@@ -3073,6 +3048,25 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                input->resetLeftReleased();
                input->resetRightReleased();
 
+               /*
+                       Handle partial digging state
+               */
+               if(!digging && dig_time > 0) {
+                       dig_time -= dig_time_decay_rate * dtime;
+                       if(dig_time < 0)
+                               dig_time = 0;
+               }
+               if(dig_time > 0 && dig_time_complete < 100000.0) {
+                       client.setCrack(dig_time_complete >= 0.001 ?
+                                       (u16)((float)crack_animation_length
+                                               * dig_time/dig_time_complete) :
+                                       // This is for torches
+                                       crack_animation_length,
+                               dig_pos);
+               } else {
+                       client.setCrack(-1, v3s16(0,0,0));
+               }
+
                /*
                        Calculate stuff for drawing
                */