Trigger on_place in many situations even if prediction failed

This commit is contained in:
DS-Minetest 2019-06-29 17:06:58 +02:00 committed by sfan5
parent c413eeb026
commit 0b5c5499ec
1 changed files with 138 additions and 135 deletions

View File

@ -801,8 +801,8 @@ private:
void updateChat(f32 dtime, const v2u32 &screensize); void updateChat(f32 dtime, const v2u32 &screensize);
bool nodePlacementPrediction(const ItemDefinition &selected_def, bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos); const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed);
static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX]; static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
InputHandler *input = nullptr; InputHandler *input = nullptr;
@ -1083,7 +1083,7 @@ void Game::run()
// RenderingEngine::run() from this iteration // RenderingEngine::run() from this iteration
// + Sleep time until the wanted FPS are reached // + Sleep time until the wanted FPS are reached
limitFps(&draw_times, &dtime); limitFps(&draw_times, &dtime);
// Prepare render data for next iteration // Prepare render data for next iteration
updateStats(&stats, draw_times, dtime); updateStats(&stats, draw_times, dtime);
@ -3225,39 +3225,24 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
camera->setDigging(1); // right click animation (always shown for feedback) camera->setDigging(1); // right click animation (always shown for feedback)
soundmaker->m_player_rightpunch_sound = SimpleSoundSpec();
// If the wielded item has node placement prediction, // If the wielded item has node placement prediction,
// make that happen // make that happen
// And also set the sound and send the interact
auto &def = selected_item.getDefinition(itemdef_manager); auto &def = selected_item.getDefinition(itemdef_manager);
bool placed = nodePlacementPrediction(def, selected_item, nodepos, bool placed = nodePlacement(def, selected_item, nodepos, neighbourpos,
neighbourpos); pointed);
if (placed) { if (placed && client->modsLoaded())
// Report to server client->getScript()->on_placenode(pointed, def);
client->interact(INTERACT_PLACE, pointed);
// Read the sound
soundmaker->m_player_rightpunch_sound =
def.sound_place;
if (client->modsLoaded())
client->getScript()->on_placenode(pointed, def);
} else {
soundmaker->m_player_rightpunch_sound =
SimpleSoundSpec();
if (def.node_placement_prediction.empty() ||
nodedef_manager->get(map.getNode(nodepos)).rightclickable) {
client->interact(INTERACT_PLACE, pointed); // Report to server
} else {
soundmaker->m_player_rightpunch_sound =
def.sound_place_failed;
}
}
} }
} }
} }
bool Game::nodePlacementPrediction(const ItemDefinition &selected_def, bool Game::nodePlacement(const ItemDefinition &selected_def,
const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos) const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
const PointedThing &pointed)
{ {
std::string prediction = selected_def.node_placement_prediction; std::string prediction = selected_def.node_placement_prediction;
const NodeDefManager *nodedef = client->ndef(); const NodeDefManager *nodedef = client->ndef();
@ -3266,144 +3251,162 @@ bool Game::nodePlacementPrediction(const ItemDefinition &selected_def,
bool is_valid_position; bool is_valid_position;
node = map.getNode(nodepos, &is_valid_position); node = map.getNode(nodepos, &is_valid_position);
if (!is_valid_position) if (!is_valid_position) {
soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
return false; return false;
}
if (!prediction.empty() && !(nodedef->get(node).rightclickable && if (prediction.empty() || (nodedef->get(node).rightclickable &&
!isKeyDown(KeyType::SNEAK))) { !isKeyDown(KeyType::SNEAK))) {
verbosestream << "Node placement prediction for " // Report to server
<< selected_item.name << " is " client->interact(INTERACT_PLACE, pointed);
<< prediction << std::endl; return false;
v3s16 p = neighbourpos; }
// Place inside node itself if buildable_to verbosestream << "Node placement prediction for "
MapNode n_under = map.getNode(nodepos, &is_valid_position); << selected_def.name << " is "
if (is_valid_position) << prediction << std::endl;
{ v3s16 p = neighbourpos;
if (nodedef->get(n_under).buildable_to)
p = nodepos; // Place inside node itself if buildable_to
else { MapNode n_under = map.getNode(nodepos, &is_valid_position);
node = map.getNode(p, &is_valid_position); if (is_valid_position) {
if (is_valid_position &&!nodedef->get(node).buildable_to) if (nodedef->get(n_under).buildable_to) {
return false; p = nodepos;
} else {
node = map.getNode(p, &is_valid_position);
if (is_valid_position && !nodedef->get(node).buildable_to) {
// Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
} }
} }
}
// Find id of predicted node // Find id of predicted node
content_t id; content_t id;
bool found = nodedef->getId(prediction, id); bool found = nodedef->getId(prediction, id);
if (!found) { if (!found) {
errorstream << "Node placement prediction failed for " errorstream << "Node placement prediction failed for "
<< selected_item.name << " (places " << selected_def.name << " (places "
<< prediction << prediction
<< ") - Name not known" << std::endl; << ") - Name not known" << std::endl;
return false; // Handle this as if prediction was empty
// Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
}
const ContentFeatures &predicted_f = nodedef->get(id);
// Predict param2 for facedir and wallmounted nodes
u8 param2 = 0;
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_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;
} }
}
const ContentFeatures &predicted_f = nodedef->get(id); if (predicted_f.param_type_2 == CPT2_FACEDIR ||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS);
// Predict param2 for facedir and wallmounted nodes if (abs(dir.X) > abs(dir.Z)) {
u8 param2 = 0; param2 = dir.X < 0 ? 3 : 1;
} else {
param2 = dir.Z < 0 ? 2 : 0;
}
}
assert(param2 <= 5);
//Check attachment if node is in group attached_node
if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
static v3s16 wallmounted_dirs[8] = {
v3s16(0, 1, 0),
v3s16(0, -1, 0),
v3s16(1, 0, 0),
v3s16(-1, 0, 0),
v3s16(0, 0, 1),
v3s16(0, 0, -1),
};
v3s16 pp;
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED || if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_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;
}
}
if (predicted_f.param_type_2 == CPT2_FACEDIR ||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS);
if (abs(dir.X) > abs(dir.Z)) {
param2 = dir.X < 0 ? 3 : 1;
} else {
param2 = dir.Z < 0 ? 2 : 0;
}
}
assert(param2 <= 5);
//Check attachment if node is in group attached_node
if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
static v3s16 wallmounted_dirs[8] = {
v3s16(0, 1, 0),
v3s16(0, -1, 0),
v3s16(1, 0, 0),
v3s16(-1, 0, 0),
v3s16(0, 0, 1),
v3s16(0, 0, -1),
};
v3s16 pp;
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
pp = p + wallmounted_dirs[param2]; pp = p + wallmounted_dirs[param2];
else else
pp = p + v3s16(0, -1, 0); pp = p + v3s16(0, -1, 0);
if (!nodedef->get(map.getNode(pp)).walkable) if (!nodedef->get(map.getNode(pp)).walkable) {
return false; // Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
} }
}
// Apply color // Apply color
if ((predicted_f.param_type_2 == CPT2_COLOR if ((predicted_f.param_type_2 == CPT2_COLOR
|| predicted_f.param_type_2 == CPT2_COLORED_FACEDIR || predicted_f.param_type_2 == CPT2_COLORED_FACEDIR
|| predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) { || predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
const std::string &indexstr = selected_item.metadata.getString( const std::string &indexstr = selected_item.metadata.getString(
"palette_index", 0); "palette_index", 0);
if (!indexstr.empty()) { if (!indexstr.empty()) {
s32 index = mystoi(indexstr); s32 index = mystoi(indexstr);
if (predicted_f.param_type_2 == CPT2_COLOR) { if (predicted_f.param_type_2 == CPT2_COLOR) {
param2 = index; param2 = index;
} else if (predicted_f.param_type_2 } else if (predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
== CPT2_COLORED_WALLMOUNTED) { // param2 = pure palette index + other
// param2 = pure palette index + other param2 = (index & 0xf8) | (param2 & 0x07);
param2 = (index & 0xf8) | (param2 & 0x07); } else if (predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
} else if (predicted_f.param_type_2 // param2 = pure palette index + other
== CPT2_COLORED_FACEDIR) { param2 = (index & 0xe0) | (param2 & 0x1f);
// param2 = pure palette index + other
param2 = (index & 0xe0) | (param2 & 0x1f);
}
} }
} }
}
// Add node to client map // Add node to client map
MapNode n(id, 0, param2); MapNode n(id, 0, param2);
try { try {
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
// Dont place node when player would be inside new node // Dont place node when player would be inside new node
// NOTE: This is to be eventually implemented by a mod as client-side Lua // NOTE: This is to be eventually implemented by a mod as client-side Lua
if (!nodedef->get(n).walkable || if (!nodedef->get(n).walkable ||
g_settings->getBool("enable_build_where_you_stand") || g_settings->getBool("enable_build_where_you_stand") ||
(client->checkPrivilege("noclip") && g_settings->getBool("noclip")) || (client->checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
(nodedef->get(n).walkable && (nodedef->get(n).walkable &&
neighbourpos != player->getStandingNodePos() + v3s16(0, 1, 0) && neighbourpos != player->getStandingNodePos() + v3s16(0, 1, 0) &&
neighbourpos != player->getStandingNodePos() + v3s16(0, 2, 0))) { neighbourpos != player->getStandingNodePos() + v3s16(0, 2, 0))) {
// This triggers the required mesh update too
// This triggers the required mesh update too client->addNode(p, n);
client->addNode(p, n); // Report to server
return true; client->interact(INTERACT_PLACE, pointed);
} // A node is predicted, also play a sound
} catch (InvalidPositionException &e) { soundmaker->m_player_rightpunch_sound = selected_def.sound_place;
errorstream << "Node placement prediction failed for " return true;
<< selected_item.name << " (places " } else {
<< prediction soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
<< ") - Position not loaded" << std::endl; return false;
} }
} catch (InvalidPositionException &e) {
errorstream << "Node placement prediction failed for "
<< selected_def.name << " (places "
<< prediction
<< ") - Position not loaded" << std::endl;
soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
return false;
} }
return false;
} }
void Game::handlePointingAtObject(const PointedThing &pointed, void Game::handlePointingAtObject(const PointedThing &pointed,