From 5b3fbf9cf75f9f637c666d34e2489fef0cc035d9 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Mon, 11 Sep 2017 14:50:06 +0200 Subject: [PATCH] Implement client node dig prediction Dig prediction allows clients to remove dug nodes without waiting for server acknowledgement. This patch allows mods to override dig prediction, it can either be turned off or a different "prediction node" can be selected. --- doc/lua_api.txt | 7 +++++++ src/game.cpp | 12 +++++++++++- src/nodedef.cpp | 7 +++++++ src/nodedef.h | 2 ++ src/script/common/c_content.cpp | 6 ++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 6bdb63ef..9a575436 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -4240,6 +4240,13 @@ Definition tables on ground when the player places the item. Server will always update actual result to client in a short moment. ]] + node_dig_prediction = "air", + --[[ + ^ if "", no prediction is made + ^ if "air", node is removed + ^ Otherwise should be name of node which the client immediately places + upon digging. Server will always update actual result shortly. + ]] sound = { breaks = "default_tool_break", -- tools only place = --[[]], diff --git a/src/game.cpp b/src/game.cpp index 04688e47..d85e34d3 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -4104,7 +4104,17 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, client->getScript()->on_dignode(nodepos, wasnode)) { return; } - client->removeNode(nodepos); + + const ContentFeatures &f = client->ndef()->get(wasnode); + if (f.node_dig_prediction == "air") { + client->removeNode(nodepos); + } else if (!f.node_dig_prediction.empty()) { + content_t id; + bool found = client->ndef()->getId(f.node_dig_prediction, id); + if (found) + client->addNode(nodepos, id, true); + } + // implicit else: no prediction } client->interact(2, pointed); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index bc03b71e..e547e31b 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -335,6 +335,7 @@ void ContentFeatures::reset() color = video::SColor(0xFFFFFFFF); palette_name = ""; palette = NULL; + node_dig_prediction = "air"; } void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const @@ -422,6 +423,8 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const // legacy writeU8(os, legacy_facedir_simple); writeU8(os, legacy_wallmounted); + + os << serializeString(node_dig_prediction); } void ContentFeatures::correctAlpha(TileDef *tiles, int length) @@ -530,6 +533,10 @@ void ContentFeatures::deSerialize(std::istream &is) // read legacy properties legacy_facedir_simple = readU8(is); legacy_wallmounted = readU8(is); + + try { + node_dig_prediction = deSerializeString(is); + } catch(SerializationError &e) {}; } #ifndef SERVER diff --git a/src/nodedef.h b/src/nodedef.h index 1392e51d..853b9bdd 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -324,6 +324,8 @@ struct ContentFeatures // Player cannot build to these (placement prediction disabled) bool rightclickable; u32 damage_per_second; + // client dig prediction + std::string node_dig_prediction; // --- LIQUID PROPERTIES --- diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 9e1fed2f..ad92741f 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -737,6 +737,10 @@ ContentFeatures read_content_features(lua_State *L, int index) } lua_pop(L, 1); + // Node immediately placed by client when node is dug + getstringfield(L, index, "node_dig_prediction", + f.node_dig_prediction); + return f; } @@ -861,6 +865,8 @@ void push_content_features(lua_State *L, const ContentFeatures &c) lua_setfield(L, -2, "legacy_facedir_simple"); lua_pushboolean(L, c.legacy_wallmounted); lua_setfield(L, -2, "legacy_wallmounted"); + lua_pushstring(L, c.node_dig_prediction.c_str()); + lua_setfield(L, -2, "node_dig_prediction"); } /******************************************************************************/