diff options
-rw-r--r-- | builtin/item.lua | 1 | ||||
-rw-r--r-- | doc/lua_api.txt | 7 | ||||
-rw-r--r-- | src/game.cpp | 33 | ||||
-rw-r--r-- | src/itemdef.cpp | 9 | ||||
-rw-r--r-- | src/itemdef.h | 5 | ||||
-rw-r--r-- | src/nodedef.cpp | 1 | ||||
-rw-r--r-- | src/scriptapi.cpp | 30 | ||||
-rw-r--r-- | src/server.cpp | 21 |
8 files changed, 99 insertions, 8 deletions
diff --git a/builtin/item.lua b/builtin/item.lua index 6d75fbf70..f249d9e5a 100644 --- a/builtin/item.lua +++ b/builtin/item.lua @@ -342,6 +342,7 @@ minetest.nodedef_default = { usable = false, liquids_pointable = false, tool_capabilities = nil, + node_placement_prediction = nil, -- Interaction callbacks on_place = redef_wrapper(minetest, 'item_place'), -- minetest.item_place diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 61bc8e1c2..c1ac13773 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1100,6 +1100,13 @@ Item definition (register_node, register_craftitem, register_tool) choppy={times={[3]=0.90}, maxwear=0.05, maxlevel=0} } } + node_placement_prediction = nil, + ^ If nil and item is node, prediction is made automatically + ^ If nil and item is not a node, no prediction is made + ^ If "" and item is anything, no prediction is made + ^ Otherwise should be name of node which the client immediately places + on ground when the player places the item. Server will always update + actual result to client in a short moment. on_place = func(itemstack, placer, pointed_thing), ^ default: minetest.item_place diff --git a/src/game.cpp b/src/game.cpp index 485bcbb50..6ccf02677 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2366,8 +2366,41 @@ void the_game( // Otherwise report right click to server else { + // Report to server client.interact(3, pointed); camera.setDigging(1); // right click animation + + // If the wielded item has node placement prediction, + // make that happen + const ItemDefinition &def = + playeritem.getDefinition(itemdef); + if(def.node_placement_prediction != "") + do{ // breakable + verbosestream<<"Node placement prediction for " + <<playeritem.name<<" is " + <<def.node_placement_prediction<<std::endl; + v3s16 p = neighbourpos; + content_t id; + bool found = + nodedef->getId(def.node_placement_prediction, id); + if(!found){ + errorstream<<"Node placement prediction failed for " + <<playeritem.name<<" (places " + <<def.node_placement_prediction + <<") - Name not known"<<std::endl; + break; + } + MapNode n(id); + try{ + // This triggers the required mesh update too + client.addNode(p, n); + }catch(InvalidPositionException &e){ + errorstream<<"Node placement prediction failed for " + <<playeritem.name<<" (places " + <<def.node_placement_prediction + <<") - Position not loaded"<<std::endl; + } + }while(0); } } } diff --git a/src/itemdef.cpp b/src/itemdef.cpp index fc0942c47..e8de06387 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -70,6 +70,7 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def) *def.tool_capabilities); } groups = def.groups; + node_placement_prediction = def.node_placement_prediction; #ifndef SERVER inventory_texture = def.inventory_texture; if(def.wield_mesh) @@ -115,6 +116,8 @@ void ItemDefinition::reset() } groups.clear(); + node_placement_prediction = ""; + #ifndef SERVER inventory_texture = NULL; if(wield_mesh) @@ -150,6 +153,7 @@ void ItemDefinition::serialize(std::ostream &os) const os<<serializeString(i->first); writeS16(os, i->second); } + os<<serializeString(node_placement_prediction); } void ItemDefinition::deSerialize(std::istream &is) @@ -184,6 +188,11 @@ void ItemDefinition::deSerialize(std::istream &is) int value = readS16(is); groups[name] = value; } + // If you add anything here, insert it primarily inside the try-catch + // block to not need to increase the version. + try{ + node_placement_prediction = deSerializeString(is); + }catch(SerializationError &e) {}; } /* diff --git a/src/itemdef.h b/src/itemdef.h index 385becd48..ac3a5ab87 100644 --- a/src/itemdef.h +++ b/src/itemdef.h @@ -67,6 +67,11 @@ struct ItemDefinition ToolCapabilities *tool_capabilities; ItemGroupList groups; + // Client shall immediately place this node when player places the item. + // Server will update the precise end result a moment later. + // "" = no prediction + std::string node_placement_prediction; + /* Cached stuff */ diff --git a/src/nodedef.cpp b/src/nodedef.cpp index eaf061287..72f1ea2ea 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -633,6 +633,7 @@ public: std::string wrapper = deSerializeString(is2); std::istringstream wrapper_is(wrapper, std::ios::binary); f->deSerialize(wrapper_is); + verbosestream<<"deserialized "<<f->name<<std::endl; if(f->name != "") addNameIdMapping(i, f->name); } diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 3766496a0..afd8546d9 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -930,13 +930,14 @@ static void read_object_properties(lua_State *L, int index, ItemDefinition */ -static ItemDefinition read_item_definition(lua_State *L, int index) +static ItemDefinition read_item_definition(lua_State *L, int index, + ItemDefinition default_def = ItemDefinition()) { if(index < 0) index = lua_gettop(L) + 1 + index; // Read the item definition - ItemDefinition def; + ItemDefinition def = default_def; def.type = (ItemType)getenumfield(L, index, "type", es_ItemType, ITEM_NONE); @@ -981,6 +982,12 @@ static ItemDefinition read_item_definition(lua_State *L, int index) read_groups(L, -1, def.groups); lua_pop(L, 1); + // Client shall immediately place this node when player places the item. + // Server will update the precise end result a moment later. + // "" = no prediction + getstringfield(L, index, "node_placement_prediction", + def.node_placement_prediction); + return def; } @@ -3891,9 +3898,10 @@ static int l_register_item_raw(lua_State *L) get_server(L)->getWritableNodeDefManager(); // Check if name is defined + std::string name; lua_getfield(L, table, "name"); if(lua_isstring(L, -1)){ - std::string name = lua_tostring(L, -1); + name = lua_tostring(L, -1); verbosestream<<"register_item_raw: "<<name<<std::endl; } else { throw LuaError(L, "register_item_raw: name is not defined or not a string"); @@ -3901,8 +3909,20 @@ static int l_register_item_raw(lua_State *L) // Check if on_use is defined - // Read the item definition and register it - ItemDefinition def = read_item_definition(L, table); + ItemDefinition def; + // Set a distinctive default value to check if this is set + def.node_placement_prediction = "__default"; + + // Read the item definition + def = read_item_definition(L, table, def); + + // Default to having client-side placement prediction for nodes + // ("" in item definition sets it off) + if(def.type == ITEM_NODE && def.node_placement_prediction == "__default"){ + def.node_placement_prediction = name; + } + + // Register item definition idef->registerItem(def); // Read the node definition (content features) and register it diff --git a/src/server.cpp b/src/server.cpp index a7bd5e953..98072e854 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2971,8 +2971,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <<std::endl; // Re-send block to revert change on client-side RemoteClient *client = getClient(peer_id); - v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); - client->SetBlockNotSent(blockpos); + // Digging completed -> under + if(action == 2){ + v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); + client->SetBlockNotSent(blockpos); + } + // Placement -> above + if(action == 3){ + v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS)); + client->SetBlockNotSent(blockpos); + } return; } @@ -3104,7 +3112,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(g_settings->getBool("creative_mode") == false) playersao->setWieldedItem(item); } - + + // If item has node placement prediction, always send the above + // node to make sure the client knows what exactly happened + if(item.getDefinition(m_itemdef).node_placement_prediction != ""){ + RemoteClient *client = getClient(peer_id); + v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS)); + client->SetBlockNotSent(blockpos); + } } // action == 3 /* |