+void nodePlacementPrediction(Client &client,
+ const ItemDefinition &playeritem_def,
+ v3s16 nodepos, v3s16 neighbourpos)
+{
+ std::string prediction = playeritem_def.node_placement_prediction;
+ INodeDefManager *nodedef = client.ndef();
+ ClientMap &map = client.getEnv().getClientMap();
+
+ if(prediction != "" && !nodedef->get(map.getNode(nodepos)).rightclickable)
+ {
+ verbosestream<<"Node placement prediction for "
+ <<playeritem_def.name<<" is "
+ <<prediction<<std::endl;
+ v3s16 p = neighbourpos;
+ // Place inside node itself if buildable_to
+ try{
+ MapNode n_under = map.getNode(nodepos);
+ if(nodedef->get(n_under).buildable_to)
+ p = nodepos;
+ }catch(InvalidPositionException &e){}
+ // Find id of predicted node
+ content_t id;
+ bool found = nodedef->getId(prediction, id);
+ if(!found){
+ errorstream<<"Node placement prediction failed for "
+ <<playeritem_def.name<<" (places "
+ <<prediction
+ <<") - Name not known"<<std::endl;
+ return;
+ }
+ // Predict param2
+ u8 param2 = 0;
+ if(nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED){
+ v3s16 dir = nodepos - neighbourpos;
+ if(abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))){
+ param2 = dir.Y < 0 ? 1 : 0;
+ } else if(abs(dir.X) > abs(dir.Z)){
+ param2 = dir.X < 0 ? 3 : 2;
+ } else {
+ param2 = dir.Z < 0 ? 5 : 4;
+ }
+ }
+ // TODO: Facedir prediction
+ // TODO: If predicted node is in attached_node group, check attachment
+ // Add node to client map
+ MapNode n(id, 0, param2);
+ try{
+ // This triggers the required mesh update too
+ client.addNode(p, n);
+ }catch(InvalidPositionException &e){
+ errorstream<<"Node placement prediction failed for "
+ <<playeritem_def.name<<" (places "
+ <<prediction
+ <<") - Position not loaded"<<std::endl;
+ }
+ }
+}
+
+