forked from Mirrorlandia_minetest/minetest
Trigger on_place in many situations even if prediction failed
This commit is contained in:
parent
c413eeb026
commit
0b5c5499ec
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user