Allow binding dig, place actions to keys; remove LMB/RMB hardcoding

Co-authored-by: Sam Caulfield <sam@samcaulfield.com>
This commit is contained in:
ANAND 2020-06-05 18:36:35 +05:30 committed by celeron55
parent fff0393187
commit 291a6b70d6
14 changed files with 284 additions and 310 deletions

@ -110,9 +110,9 @@ doubletap_jump (Double tap jump for fly) bool false
# enabled. # enabled.
always_fly_fast (Always fly and fast) bool true always_fly_fast (Always fly and fast) bool true
# The time in seconds it takes between repeated right clicks when holding the right # The time in seconds it takes between repeated node placements when holding
# mouse button. # the place button.
repeat_rightclick_time (Rightclick repetition interval) float 0.25 0.001 repeat_place_time (Place repetition interval) float 0.25 0.001
# Automatically jump up single-node obstacles. # Automatically jump up single-node obstacles.
autojump (Automatic jumping) bool false autojump (Automatic jumping) bool false
@ -182,6 +182,14 @@ keymap_jump (Jump key) key KEY_SPACE
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3 # See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
keymap_sneak (Sneak key) key KEY_LSHIFT keymap_sneak (Sneak key) key KEY_LSHIFT
# Key for digging.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
keymap_dig (Dig key) key KEY_LBUTTON
# Key for placing.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
keymap_place (Place key) key KEY_RBUTTON
# Key for opening the inventory. # Key for opening the inventory.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3 # See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
keymap_inventory (Inventory key) key KEY_KEY_I keymap_inventory (Inventory key) key KEY_KEY_I

@ -1100,8 +1100,8 @@ Methods:
aux1 = boolean, aux1 = boolean,
sneak = boolean, sneak = boolean,
zoom = boolean, zoom = boolean,
LMB = boolean, dig = boolean,
RMB = boolean, place = boolean,
} }
``` ```

@ -6163,15 +6163,23 @@ object you are working with still exists.
* Only affects formspecs shown after this is called. * Only affects formspecs shown after this is called.
* `get_formspec_prepend(formspec)`: returns a formspec string. * `get_formspec_prepend(formspec)`: returns a formspec string.
* `get_player_control()`: returns table with player pressed keys * `get_player_control()`: returns table with player pressed keys
* The table consists of fields with boolean value representing the pressed * The table consists of fields with the following boolean values
keys, the fields are jump, right, left, LMB, RMB, sneak, aux1, down, up, zoom. representing the pressed keys: `up`, `down`, `left`, `right`, `jump`,
* example: `{jump=false, right=true, left=false, LMB=false, RMB=false, `aux1`, `sneak`, `dig`, `place`, `LMB`, `RMB`, and `zoom`.
sneak=true, aux1=false, down=false, up=false, zoom=false}` * The fields `LMB` and `RMB` are equal to `dig` and `place` respectively,
* The `zoom` field is available since 5.3 and exist only to preserve backwards compatibility.
* `get_player_control_bits()`: returns integer with bit packed player pressed * `get_player_control_bits()`: returns integer with bit packed player pressed
keys. keys. Bits:
* bit nr/meaning: 0/up, 1/down, 2/left, 3/right, 4/jump, 5/aux1, 6/sneak, * 0 - up
7/LMB, 8/RMB, 9/zoom (zoom available since 5.3) * 1 - down
* 2 - left
* 3 - right
* 4 - jump
* 5 - aux1
* 6 - sneak
* 7 - dig
* 8 - place
* 9 - zoom
* `set_physics_override(override_table)` * `set_physics_override(override_table)`
* `override_table` is a table with the following fields: * `override_table` is a table with the following fields:
* `speed`: multiplier to default walking speed value (default: `1`) * `speed`: multiplier to default walking speed value (default: `1`)

@ -1307,7 +1307,7 @@ void Client::sendPlayerPos()
player->last_pitch == player->getPitch() && player->last_pitch == player->getPitch() &&
player->last_yaw == player->getYaw() && player->last_yaw == player->getYaw() &&
player->last_keyPressed == player->keyPressed && player->last_keyPressed == player->keyPressed &&
player->last_camera_fov == camera_fov && player->last_camera_fov == camera_fov &&
player->last_wanted_range == wanted_range) player->last_wanted_range == wanted_range)
return; return;

@ -975,13 +975,13 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
if (controls.sneak && walking) if (controls.sneak && walking)
new_speed /= 2; new_speed /= 2;
if (walking && (controls.LMB || controls.RMB)) { if (walking && (controls.dig || controls.place)) {
new_anim = player->local_animations[3]; new_anim = player->local_animations[3];
player->last_animation = WD_ANIM; player->last_animation = WD_ANIM;
} else if(walking) { } else if (walking) {
new_anim = player->local_animations[1]; new_anim = player->local_animations[1];
player->last_animation = WALK_ANIM; player->last_animation = WALK_ANIM;
} else if(controls.LMB || controls.RMB) { } else if (controls.dig || controls.place) {
new_anim = player->local_animations[2]; new_anim = player->local_animations[2];
player->last_animation = DIG_ANIM; player->last_animation = DIG_ANIM;
} }
@ -1004,9 +1004,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// Update local player animations // Update local player animations
if ((player->last_animation != old_anim || if ((player->last_animation != old_anim ||
m_animation_speed != old_anim_speed) && m_animation_speed != old_anim_speed) &&
player->last_animation != NO_ANIM && allow_update) player->last_animation != NO_ANIM && allow_update)
updateAnimation(); updateAnimation();
} }
} }

@ -604,7 +604,6 @@ public:
#endif #endif
/**************************************************************************** /****************************************************************************
****************************************************************************/ ****************************************************************************/
const float object_hit_delay = 0.2; const float object_hit_delay = 0.2;
@ -625,15 +624,15 @@ struct GameRunData {
u16 new_playeritem; u16 new_playeritem;
PointedThing pointed_old; PointedThing pointed_old;
bool digging; bool digging;
bool ldown_for_dig; bool punching;
bool btn_down_for_dig;
bool dig_instantly; bool dig_instantly;
bool digging_blocked; bool digging_blocked;
bool left_punch;
bool reset_jump_timer; bool reset_jump_timer;
float nodig_delay_timer; float nodig_delay_timer;
float dig_time; float dig_time;
float dig_time_complete; float dig_time_complete;
float repeat_rightclick_timer; float repeat_place_timer;
float object_hit_delay_timer; float object_hit_delay_timer;
float time_from_last_punch; float time_from_last_punch;
ClientActiveObject *selected_object; ClientActiveObject *selected_object;
@ -787,6 +786,14 @@ protected:
{ {
return input->wasKeyDown(k); return input->wasKeyDown(k);
} }
inline bool wasKeyPressed(GameKeyType k)
{
return input->wasKeyPressed(k);
}
inline bool wasKeyReleased(GameKeyType k)
{
return input->wasKeyReleased(k);
}
#ifdef __ANDROID__ #ifdef __ANDROID__
void handleAndroidChatInput(); void handleAndroidChatInput();
@ -900,7 +907,7 @@ private:
bool m_cache_enable_free_move; bool m_cache_enable_free_move;
f32 m_cache_mouse_sensitivity; f32 m_cache_mouse_sensitivity;
f32 m_cache_joystick_frustum_sensitivity; f32 m_cache_joystick_frustum_sensitivity;
f32 m_repeat_right_click_time; f32 m_repeat_place_time;
f32 m_cache_cam_smoothing; f32 m_cache_cam_smoothing;
f32 m_cache_fog_start; f32 m_cache_fog_start;
@ -934,7 +941,7 @@ Game::Game() :
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("joystick_frustum_sensitivity", g_settings->registerChangedCallback("joystick_frustum_sensitivity",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("repeat_rightclick_time", g_settings->registerChangedCallback("repeat_place_time",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("noclip", g_settings->registerChangedCallback("noclip",
&settingChangedCallback, this); &settingChangedCallback, this);
@ -992,7 +999,7 @@ Game::~Game()
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->deregisterChangedCallback("mouse_sensitivity", g_settings->deregisterChangedCallback("mouse_sensitivity",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->deregisterChangedCallback("repeat_rightclick_time", g_settings->deregisterChangedCallback("repeat_place_time",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->deregisterChangedCallback("noclip", g_settings->deregisterChangedCallback("noclip",
&settingChangedCallback, this); &settingChangedCallback, this);
@ -2465,8 +2472,8 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
isKeyDown(KeyType::SPECIAL1), isKeyDown(KeyType::SPECIAL1),
isKeyDown(KeyType::SNEAK), isKeyDown(KeyType::SNEAK),
isKeyDown(KeyType::ZOOM), isKeyDown(KeyType::ZOOM),
input->getLeftState(), isKeyDown(KeyType::DIG),
input->getRightState(), isKeyDown(KeyType::PLACE),
cam.camera_pitch, cam.camera_pitch,
cam.camera_yaw, cam.camera_yaw,
input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE), input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE),
@ -2481,8 +2488,8 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) | ( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) |
( (u32)(isKeyDown(KeyType::SPECIAL1) & 0x1) << 5) | ( (u32)(isKeyDown(KeyType::SPECIAL1) & 0x1) << 5) |
( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) | ( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) |
( (u32)(input->getLeftState() & 0x1) << 7) | ( (u32)(isKeyDown(KeyType::DIG) & 0x1) << 7) |
( (u32)(input->getRightState() & 0x1) << 8) | ( (u32)(isKeyDown(KeyType::PLACE) & 0x1) << 8) |
( (u32)(isKeyDown(KeyType::ZOOM) & 0x1) << 9) ( (u32)(isKeyDown(KeyType::ZOOM) & 0x1) << 9)
); );
@ -3064,7 +3071,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
PointedThing pointed = updatePointedThing(shootline, PointedThing pointed = updatePointedThing(shootline,
selected_def.liquids_pointable, selected_def.liquids_pointable,
!runData.ldown_for_dig, !runData.btn_down_for_dig,
camera_offset); camera_offset);
if (pointed != runData.pointed_old) { if (pointed != runData.pointed_old) {
@ -3072,20 +3079,18 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
hud->updateSelectionMesh(camera_offset); hud->updateSelectionMesh(camera_offset);
} }
if (runData.digging_blocked && !input->getLeftState()) { // Allow digging again if button is not pressed
// allow digging again if button is not pressed if (runData.digging_blocked && !isKeyDown(KeyType::DIG))
runData.digging_blocked = false; runData.digging_blocked = false;
}
/* /*
Stop digging when Stop digging when
- releasing left mouse button - releasing dig button
- pointing away from node - pointing away from node
*/ */
if (runData.digging) { if (runData.digging) {
if (input->getLeftReleased()) { if (wasKeyReleased(KeyType::DIG)) {
infostream << "Left button released" infostream << "Dig button released (stopped digging)" << std::endl;
<< " (stopped digging)" << std::endl;
runData.digging = false; runData.digging = false;
} else if (pointed != runData.pointed_old) { } else if (pointed != runData.pointed_old) {
if (pointed.type == POINTEDTHING_NODE if (pointed.type == POINTEDTHING_NODE
@ -3095,8 +3100,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
// Still pointing to the same node, but a different face. // Still pointing to the same node, but a different face.
// Don't reset. // Don't reset.
} else { } else {
infostream << "Pointing away from node" infostream << "Pointing away from node (stopped digging)" << std::endl;
<< " (stopped digging)" << std::endl;
runData.digging = false; runData.digging = false;
hud->updateSelectionMesh(camera_offset); hud->updateSelectionMesh(camera_offset);
} }
@ -3107,55 +3111,57 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
client->setCrack(-1, v3s16(0, 0, 0)); client->setCrack(-1, v3s16(0, 0, 0));
runData.dig_time = 0.0; runData.dig_time = 0.0;
} }
} else if (runData.dig_instantly && input->getLeftReleased()) { } else if (runData.dig_instantly && wasKeyReleased(KeyType::DIG)) {
// Remove e.g. torches faster when clicking instead of holding LMB // Remove e.g. torches faster when clicking instead of holding dig button
runData.nodig_delay_timer = 0; runData.nodig_delay_timer = 0;
runData.dig_instantly = false; runData.dig_instantly = false;
} }
if (!runData.digging && runData.ldown_for_dig && !input->getLeftState()) { if (!runData.digging && runData.btn_down_for_dig && !isKeyDown(KeyType::DIG))
runData.ldown_for_dig = false; runData.btn_down_for_dig = false;
}
runData.left_punch = false; runData.punching = false;
soundmaker->m_player_leftpunch_sound.name = ""; soundmaker->m_player_leftpunch_sound.name = "";
// Prepare for repeating, unless we're not supposed to // Prepare for repeating, unless we're not supposed to
if (input->getRightState() && !g_settings->getBool("safe_dig_and_place")) if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
runData.repeat_rightclick_timer += dtime; runData.repeat_place_timer += dtime;
else else
runData.repeat_rightclick_timer = 0; runData.repeat_place_timer = 0;
if (selected_def.usable && input->getLeftState()) { if (selected_def.usable && isKeyDown(KeyType::DIG)) {
if (input->getLeftClicked() && (!client->modsLoaded() if (wasKeyPressed(KeyType::DIG) && (!client->modsLoaded() ||
|| !client->getScript()->on_item_use(selected_item, pointed))) !client->getScript()->on_item_use(selected_item, pointed)))
client->interact(INTERACT_USE, pointed); client->interact(INTERACT_USE, pointed);
} else if (pointed.type == POINTEDTHING_NODE) { } else if (pointed.type == POINTEDTHING_NODE) {
handlePointingAtNode(pointed, selected_item, hand_item, dtime); handlePointingAtNode(pointed, selected_item, hand_item, dtime);
} else if (pointed.type == POINTEDTHING_OBJECT) { } else if (pointed.type == POINTEDTHING_OBJECT) {
v3f player_position = player->getPosition(); v3f player_position = player->getPosition();
handlePointingAtObject(pointed, tool_item, player_position, show_debug); handlePointingAtObject(pointed, tool_item, player_position, show_debug);
} else if (input->getLeftState()) { } else if (isKeyDown(KeyType::DIG)) {
// When button is held down in air, show continuous animation // When button is held down in air, show continuous animation
runData.left_punch = true; runData.punching = true;
// Run callback even though item is not usable // Run callback even though item is not usable
if (input->getLeftClicked() && client->modsLoaded()) if (wasKeyPressed(KeyType::DIG) && client->modsLoaded())
client->getScript()->on_item_use(selected_item, pointed); client->getScript()->on_item_use(selected_item, pointed);
} else if (input->getRightClicked()) { } else if (wasKeyPressed(KeyType::PLACE)) {
handlePointingAtNothing(selected_item); handlePointingAtNothing(selected_item);
} }
runData.pointed_old = pointed; runData.pointed_old = pointed;
if (runData.left_punch || input->getLeftClicked()) if (runData.punching || wasKeyPressed(KeyType::DIG))
camera->setDigging(0); // left click animation camera->setDigging(0); // dig animation
input->resetLeftClicked(); input->clearWasKeyPressed();
input->resetRightClicked(); input->clearWasKeyReleased();
input->resetLeftReleased(); input->joystick.clearWasKeyDown(KeyType::MOUSE_L);
input->resetRightReleased(); input->joystick.clearWasKeyDown(KeyType::MOUSE_R);
input->joystick.clearWasKeyReleased(KeyType::MOUSE_L);
input->joystick.clearWasKeyReleased(KeyType::MOUSE_R);
} }
@ -3255,7 +3261,7 @@ PointedThing Game::updatePointedThing(
void Game::handlePointingAtNothing(const ItemStack &playerItem) void Game::handlePointingAtNothing(const ItemStack &playerItem)
{ {
infostream << "Right Clicked in Air" << std::endl; infostream << "Attempted to place item while pointing at nothing" << std::endl;
PointedThing fauxPointed; PointedThing fauxPointed;
fauxPointed.type = POINTEDTHING_NOTHING; fauxPointed.type = POINTEDTHING_NOTHING;
client->interact(INTERACT_ACTIVATE, fauxPointed); client->interact(INTERACT_ACTIVATE, fauxPointed);
@ -3274,7 +3280,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
ClientMap &map = client->getEnv().getClientMap(); ClientMap &map = client->getEnv().getClientMap();
if (runData.nodig_delay_timer <= 0.0 && input->getLeftState() if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG)
&& !runData.digging_blocked && !runData.digging_blocked
&& client->checkPrivilege("interact")) { && client->checkPrivilege("interact")) {
handleDigging(pointed, nodepos, selected_item, hand_item, dtime); handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
@ -3295,13 +3301,14 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
} }
} }
if ((input->getRightClicked() || if ((wasKeyPressed(KeyType::PLACE) ||
runData.repeat_rightclick_timer >= m_repeat_right_click_time) && runData.repeat_place_timer >= m_repeat_place_time) &&
client->checkPrivilege("interact")) { client->checkPrivilege("interact")) {
runData.repeat_rightclick_timer = 0; runData.repeat_place_timer = 0;
infostream << "Ground right-clicked" << std::endl; infostream << "Place button pressed while looking at ground" << std::endl;
camera->setDigging(1); // right click animation (always shown for feedback) // Placing animation (always shown for feedback)
camera->setDigging(1);
soundmaker->m_player_rightpunch_sound = SimpleSoundSpec(); soundmaker->m_player_rightpunch_sound = SimpleSoundSpec();
@ -3367,8 +3374,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
} }
verbosestream << "Node placement prediction for " verbosestream << "Node placement prediction for "
<< selected_def.name << " is " << selected_def.name << " is " << prediction << std::endl;
<< prediction << std::endl;
v3s16 p = neighbourpos; v3s16 p = neighbourpos;
// Place inside node itself if buildable_to // Place inside node itself if buildable_to
@ -3529,7 +3535,7 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
m_game_ui->setInfoText(infotext); m_game_ui->setInfoText(infotext);
if (input->getLeftState()) { if (isKeyDown(KeyType::DIG)) {
bool do_punch = false; bool do_punch = false;
bool do_punch_damage = false; bool do_punch_damage = false;
@ -3539,12 +3545,12 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
runData.object_hit_delay_timer = object_hit_delay; runData.object_hit_delay_timer = object_hit_delay;
} }
if (input->getLeftClicked()) if (wasKeyPressed(KeyType::DIG))
do_punch = true; do_punch = true;
if (do_punch) { if (do_punch) {
infostream << "Left-clicked object" << std::endl; infostream << "Punched object" << std::endl;
runData.left_punch = true; runData.punching = true;
} }
if (do_punch_damage) { if (do_punch_damage) {
@ -3559,8 +3565,8 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
if (!disable_send) if (!disable_send)
client->interact(INTERACT_START_DIGGING, pointed); client->interact(INTERACT_START_DIGGING, pointed);
} }
} else if (input->getRightClicked()) { } else if (wasKeyDown(KeyType::PLACE)) {
infostream << "Right-clicked object" << std::endl; infostream << "Pressed place button while pointing at object" << std::endl;
client->interact(INTERACT_PLACE, pointed); // place client->interact(INTERACT_PLACE, pointed); // place
} }
} }
@ -3606,7 +3612,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
return; return;
client->interact(INTERACT_START_DIGGING, pointed); client->interact(INTERACT_START_DIGGING, pointed);
runData.digging = true; runData.digging = true;
runData.ldown_for_dig = true; runData.btn_down_for_dig = true;
} }
if (!runData.dig_instantly) { if (!runData.dig_instantly) {
@ -3700,7 +3706,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
client->setCrack(-1, nodepos); client->setCrack(-1, nodepos);
} }
camera->setDigging(0); // left click animation camera->setDigging(0); // Dig animation
} }
@ -4039,7 +4045,7 @@ void Game::readSettings()
m_cache_enable_fog = g_settings->getBool("enable_fog"); m_cache_enable_fog = g_settings->getBool("enable_fog");
m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity"); m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity");
m_cache_joystick_frustum_sensitivity = g_settings->getFloat("joystick_frustum_sensitivity"); m_cache_joystick_frustum_sensitivity = g_settings->getFloat("joystick_frustum_sensitivity");
m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time"); m_repeat_place_time = g_settings->getFloat("repeat_place_time");
m_cache_enable_noclip = g_settings->getBool("noclip"); m_cache_enable_noclip = g_settings->getBool("noclip");
m_cache_enable_free_move = g_settings->getBool("free_move"); m_cache_enable_free_move = g_settings->getBool("free_move");
@ -4131,30 +4137,32 @@ void Game::showPauseMenu()
"- %s: move backwards\n" "- %s: move backwards\n"
"- %s: move left\n" "- %s: move left\n"
"- %s: move right\n" "- %s: move right\n"
"- %s: jump/climb\n" "- %s: jump/climb up\n"
"- %s: sneak/go down\n" "- %s: dig/punch\n"
"- %s: place/use\n"
"- %s: sneak/climb down\n"
"- %s: drop item\n" "- %s: drop item\n"
"- %s: inventory\n" "- %s: inventory\n"
"- Mouse: turn/look\n" "- Mouse: turn/look\n"
"- Mouse left: dig/punch\n"
"- Mouse right: place/use\n"
"- Mouse wheel: select item\n" "- Mouse wheel: select item\n"
"- %s: chat\n" "- %s: chat\n"
); );
char control_text_buf[600]; char control_text_buf[600];
porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(), porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
GET_KEY_NAME(keymap_forward), GET_KEY_NAME(keymap_forward),
GET_KEY_NAME(keymap_backward), GET_KEY_NAME(keymap_backward),
GET_KEY_NAME(keymap_left), GET_KEY_NAME(keymap_left),
GET_KEY_NAME(keymap_right), GET_KEY_NAME(keymap_right),
GET_KEY_NAME(keymap_jump), GET_KEY_NAME(keymap_jump),
GET_KEY_NAME(keymap_sneak), GET_KEY_NAME(keymap_dig),
GET_KEY_NAME(keymap_drop), GET_KEY_NAME(keymap_place),
GET_KEY_NAME(keymap_inventory), GET_KEY_NAME(keymap_sneak),
GET_KEY_NAME(keymap_chat) GET_KEY_NAME(keymap_drop),
); GET_KEY_NAME(keymap_inventory),
GET_KEY_NAME(keymap_chat)
);
std::string control_text = std::string(control_text_buf); std::string control_text = std::string(control_text_buf);
str_formspec_escape(control_text); str_formspec_escape(control_text);

@ -37,6 +37,8 @@ void KeyCache::populate()
key[KeyType::JUMP] = getKeySetting("keymap_jump"); key[KeyType::JUMP] = getKeySetting("keymap_jump");
key[KeyType::SPECIAL1] = getKeySetting("keymap_special1"); key[KeyType::SPECIAL1] = getKeySetting("keymap_special1");
key[KeyType::SNEAK] = getKeySetting("keymap_sneak"); key[KeyType::SNEAK] = getKeySetting("keymap_sneak");
key[KeyType::DIG] = getKeySetting("keymap_dig");
key[KeyType::PLACE] = getKeySetting("keymap_place");
key[KeyType::AUTOFORWARD] = getKeySetting("keymap_autoforward"); key[KeyType::AUTOFORWARD] = getKeySetting("keymap_autoforward");
@ -111,57 +113,81 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
if (event.EventType == irr::EET_KEY_INPUT_EVENT) { if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
const KeyPress &keyCode = event.KeyInput; const KeyPress &keyCode = event.KeyInput;
if (keysListenedFor[keyCode]) { if (keysListenedFor[keyCode]) {
// If the key is being held down then the OS may
// send a continuous stream of keydown events.
// In this case, we don't want to let this
// stream reach the application as it will cause
// certain actions to repeat constantly.
if (event.KeyInput.PressedDown) { if (event.KeyInput.PressedDown) {
if (!IsKeyDown(keyCode)) {
keyWasDown.set(keyCode);
keyWasPressed.set(keyCode);
}
keyIsDown.set(keyCode); keyIsDown.set(keyCode);
keyWasDown.set(keyCode);
} else { } else {
if (IsKeyDown(keyCode))
keyWasReleased.set(keyCode);
keyIsDown.unset(keyCode); keyIsDown.unset(keyCode);
} }
return true; return true;
} }
}
#ifdef HAVE_TOUCHSCREENGUI #ifdef HAVE_TOUCHSCREENGUI
// case of touchscreengui we have to handle different events } else if (m_touchscreengui && event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
if (m_touchscreengui && event.EventType == irr::EET_TOUCH_INPUT_EVENT) { // In case of touchscreengui, we have to handle different events
m_touchscreengui->translateEvent(event); m_touchscreengui->translateEvent(event);
return true; return true;
}
#endif #endif
if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) { } else if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
/* TODO add a check like: /* TODO add a check like:
if (event.JoystickEvent != joystick_we_listen_for) if (event.JoystickEvent != joystick_we_listen_for)
return false; return false;
*/ */
return joystick->handleEvent(event.JoystickEvent); return joystick->handleEvent(event.JoystickEvent);
} } else if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
// handle mouse events // Handle mouse events
if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) { KeyPress key;
if (isMenuActive()) { switch (event.MouseInput.Event) {
left_active = false; case EMIE_LMOUSE_PRESSED_DOWN:
middle_active = false; key = "KEY_LBUTTON";
right_active = false; keyIsDown.set(key);
} else { keyWasDown.set(key);
left_active = event.MouseInput.isLeftPressed(); keyWasPressed.set(key);
middle_active = event.MouseInput.isMiddlePressed(); break;
right_active = event.MouseInput.isRightPressed(); case EMIE_MMOUSE_PRESSED_DOWN:
key = "KEY_MBUTTON";
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { keyIsDown.set(key);
leftclicked = true; keyWasDown.set(key);
} keyWasPressed.set(key);
if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) { break;
rightclicked = true; case EMIE_RMOUSE_PRESSED_DOWN:
} key = "KEY_RBUTTON";
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) { keyIsDown.set(key);
leftreleased = true; keyWasDown.set(key);
} keyWasPressed.set(key);
if (event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) { break;
rightreleased = true; case EMIE_LMOUSE_LEFT_UP:
} key = "KEY_LBUTTON";
if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) { keyIsDown.unset(key);
mouse_wheel += event.MouseInput.Wheel; keyWasReleased.set(key);
} break;
case EMIE_MMOUSE_LEFT_UP:
key = "KEY_MBUTTON";
keyIsDown.unset(key);
keyWasReleased.set(key);
break;
case EMIE_RMOUSE_LEFT_UP:
key = "KEY_RBUTTON";
keyIsDown.unset(key);
keyWasReleased.set(key);
break;
case EMIE_MOUSE_WHEEL:
mouse_wheel += event.MouseInput.Wheel;
break;
default: break;
} }
} else if (event.EventType == irr::EET_LOG_TEXT_EVENT) { } else if (event.EventType == irr::EET_LOG_TEXT_EVENT) {
static const LogLevel irr_loglev_conv[] = { static const LogLevel irr_loglev_conv[] = {
@ -188,38 +214,28 @@ s32 RandomInputHandler::Rand(s32 min, s32 max)
return (myrand() % (max - min + 1)) + min; return (myrand() % (max - min + 1)) + min;
} }
struct RandomInputHandlerSimData {
std::string key;
float counter;
int time_max;
};
void RandomInputHandler::step(float dtime) void RandomInputHandler::step(float dtime)
{ {
{ static RandomInputHandlerSimData rnd_data[] = {
static float counter1 = 0; { "keymap_jump", 0.0f, 40 },
counter1 -= dtime; { "keymap_special1", 0.0f, 40 },
if (counter1 < 0.0) { { "keymap_forward", 0.0f, 40 },
counter1 = 0.1 * Rand(1, 40); { "keymap_left", 0.0f, 40 },
keydown.toggle(getKeySetting("keymap_jump")); { "keymap_dig", 0.0f, 30 },
} { "keymap_place", 0.0f, 15 }
} };
{
static float counter1 = 0; for (auto &i : rnd_data) {
counter1 -= dtime; i.counter -= dtime;
if (counter1 < 0.0) { if (i.counter < 0.0) {
counter1 = 0.1 * Rand(1, 40); i.counter = 0.1 * Rand(1, i.time_max);
keydown.toggle(getKeySetting("keymap_special1")); keydown.toggle(getKeySetting(i.key.c_str()));
}
}
{
static float counter1 = 0;
counter1 -= dtime;
if (counter1 < 0.0) {
counter1 = 0.1 * Rand(1, 40);
keydown.toggle(getKeySetting("keymap_forward"));
}
}
{
static float counter1 = 0;
counter1 -= dtime;
if (counter1 < 0.0) {
counter1 = 0.1 * Rand(1, 40);
keydown.toggle(getKeySetting("keymap_left"));
} }
} }
{ {
@ -230,29 +246,5 @@ void RandomInputHandler::step(float dtime)
mousespeed = v2s32(Rand(-20, 20), Rand(-15, 20)); mousespeed = v2s32(Rand(-20, 20), Rand(-15, 20));
} }
} }
{
static float counter1 = 0;
counter1 -= dtime;
if (counter1 < 0.0) {
counter1 = 0.1 * Rand(1, 30);
leftdown = !leftdown;
if (leftdown)
leftclicked = true;
if (!leftdown)
leftreleased = true;
}
}
{
static float counter1 = 0;
counter1 -= dtime;
if (counter1 < 0.0) {
counter1 = 0.1 * Rand(1, 15);
rightdown = !rightdown;
if (rightdown)
rightclicked = true;
if (!rightdown)
rightreleased = true;
}
}
mousepos += mousespeed; mousepos += mousespeed;
} }

@ -144,6 +144,14 @@ public:
return b; return b;
} }
// Checks whether a key was just pressed. State will be cleared
// in the subsequent iteration of Game::processPlayerInteraction
bool WasKeyPressed(const KeyPress &keycode) const { return keyWasPressed[keycode]; }
// Checks whether a key was just released. State will be cleared
// in the subsequent iteration of Game::processPlayerInteraction
bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; }
void listenForKey(const KeyPress &keyCode) { keysListenedFor.set(keyCode); } void listenForKey(const KeyPress &keyCode) { keysListenedFor.set(keyCode); }
void dontListenForKeys() { keysListenedFor.clear(); } void dontListenForKeys() { keysListenedFor.clear(); }
@ -158,19 +166,22 @@ public:
{ {
keyIsDown.clear(); keyIsDown.clear();
keyWasDown.clear(); keyWasDown.clear();
keyWasPressed.clear();
leftclicked = false; keyWasReleased.clear();
rightclicked = false;
leftreleased = false;
rightreleased = false;
left_active = false;
middle_active = false;
right_active = false;
mouse_wheel = 0; mouse_wheel = 0;
} }
void clearWasKeyPressed()
{
keyWasPressed.clear();
}
void clearWasKeyReleased()
{
keyWasReleased.clear();
}
MyEventReceiver() MyEventReceiver()
{ {
#ifdef HAVE_TOUCHSCREENGUI #ifdef HAVE_TOUCHSCREENGUI
@ -178,15 +189,6 @@ public:
#endif #endif
} }
bool leftclicked = false;
bool rightclicked = false;
bool leftreleased = false;
bool rightreleased = false;
bool left_active = false;
bool middle_active = false;
bool right_active = false;
s32 mouse_wheel = 0; s32 mouse_wheel = 0;
JoystickController *joystick = nullptr; JoystickController *joystick = nullptr;
@ -198,8 +200,16 @@ public:
private: private:
// The current state of keys // The current state of keys
KeyList keyIsDown; KeyList keyIsDown;
// Whether a key has been pressed or not
// Whether a key was down
KeyList keyWasDown; KeyList keyWasDown;
// Whether a key has just been pressed
KeyList keyWasPressed;
// Whether a key has just been released
KeyList keyWasReleased;
// List of keys we listen for // List of keys we listen for
// TODO perhaps the type of this is not really // TODO perhaps the type of this is not really
// performant as KeyList is designed for few but // performant as KeyList is designed for few but
@ -226,27 +236,19 @@ public:
virtual bool isKeyDown(GameKeyType k) = 0; virtual bool isKeyDown(GameKeyType k) = 0;
virtual bool wasKeyDown(GameKeyType k) = 0; virtual bool wasKeyDown(GameKeyType k) = 0;
virtual bool wasKeyPressed(GameKeyType k) = 0;
virtual bool wasKeyReleased(GameKeyType k) = 0;
virtual bool cancelPressed() = 0; virtual bool cancelPressed() = 0;
virtual void clearWasKeyPressed() {}
virtual void clearWasKeyReleased() {}
virtual void listenForKey(const KeyPress &keyCode) {} virtual void listenForKey(const KeyPress &keyCode) {}
virtual void dontListenForKeys() {} virtual void dontListenForKeys() {}
virtual v2s32 getMousePos() = 0; virtual v2s32 getMousePos() = 0;
virtual void setMousePos(s32 x, s32 y) = 0; virtual void setMousePos(s32 x, s32 y) = 0;
virtual bool getLeftState() = 0;
virtual bool getRightState() = 0;
virtual bool getLeftClicked() = 0;
virtual bool getRightClicked() = 0;
virtual void resetLeftClicked() = 0;
virtual void resetRightClicked() = 0;
virtual bool getLeftReleased() = 0;
virtual bool getRightReleased() = 0;
virtual void resetLeftReleased() = 0;
virtual void resetRightReleased() = 0;
virtual s32 getMouseWheel() = 0; virtual s32 getMouseWheel() = 0;
virtual void step(float dtime) {} virtual void step(float dtime) {}
@ -275,10 +277,26 @@ public:
{ {
return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k); return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
} }
virtual bool wasKeyPressed(GameKeyType k)
{
return m_receiver->WasKeyPressed(keycache.key[k]) || joystick.wasKeyReleased(k);
}
virtual bool wasKeyReleased(GameKeyType k)
{
return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k);
}
virtual bool cancelPressed() virtual bool cancelPressed()
{ {
return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey); return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey);
} }
virtual void clearWasKeyPressed()
{
m_receiver->clearWasKeyPressed();
}
virtual void clearWasKeyReleased()
{
m_receiver->clearWasKeyReleased();
}
virtual void listenForKey(const KeyPress &keyCode) virtual void listenForKey(const KeyPress &keyCode)
{ {
m_receiver->listenForKey(keyCode); m_receiver->listenForKey(keyCode);
@ -306,59 +324,6 @@ public:
} }
} }
virtual bool getLeftState()
{
return m_receiver->left_active || joystick.isKeyDown(KeyType::MOUSE_L);
}
virtual bool getRightState()
{
return m_receiver->right_active || joystick.isKeyDown(KeyType::MOUSE_R);
}
virtual bool getLeftClicked()
{
return m_receiver->leftclicked ||
joystick.getWasKeyDown(KeyType::MOUSE_L);
}
virtual bool getRightClicked()
{
return m_receiver->rightclicked ||
joystick.getWasKeyDown(KeyType::MOUSE_R);
}
virtual void resetLeftClicked()
{
m_receiver->leftclicked = false;
joystick.clearWasKeyDown(KeyType::MOUSE_L);
}
virtual void resetRightClicked()
{
m_receiver->rightclicked = false;
joystick.clearWasKeyDown(KeyType::MOUSE_R);
}
virtual bool getLeftReleased()
{
return m_receiver->leftreleased ||
joystick.wasKeyReleased(KeyType::MOUSE_L);
}
virtual bool getRightReleased()
{
return m_receiver->rightreleased ||
joystick.wasKeyReleased(KeyType::MOUSE_R);
}
virtual void resetLeftReleased()
{
m_receiver->leftreleased = false;
joystick.clearWasKeyReleased(KeyType::MOUSE_L);
}
virtual void resetRightReleased()
{
m_receiver->rightreleased = false;
joystick.clearWasKeyReleased(KeyType::MOUSE_R);
}
virtual s32 getMouseWheel() { return m_receiver->getMouseWheel(); } virtual s32 getMouseWheel() { return m_receiver->getMouseWheel(); }
void clear() void clear()
@ -384,23 +349,12 @@ public:
virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; } virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
virtual bool wasKeyDown(GameKeyType k) { return false; } virtual bool wasKeyDown(GameKeyType k) { return false; }
virtual bool wasKeyPressed(GameKeyType k) { return false; }
virtual bool wasKeyReleased(GameKeyType k) { return false; }
virtual bool cancelPressed() { return false; } virtual bool cancelPressed() { return false; }
virtual v2s32 getMousePos() { return mousepos; } virtual v2s32 getMousePos() { return mousepos; }
virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); } virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
virtual bool getLeftState() { return leftdown; }
virtual bool getRightState() { return rightdown; }
virtual bool getLeftClicked() { return leftclicked; }
virtual bool getRightClicked() { return rightclicked; }
virtual void resetLeftClicked() { leftclicked = false; }
virtual void resetRightClicked() { rightclicked = false; }
virtual bool getLeftReleased() { return leftreleased; }
virtual bool getRightReleased() { return rightreleased; }
virtual void resetLeftReleased() { leftreleased = false; }
virtual void resetRightReleased() { rightreleased = false; }
virtual s32 getMouseWheel() { return 0; } virtual s32 getMouseWheel() { return 0; }
virtual void step(float dtime); virtual void step(float dtime);
@ -411,10 +365,4 @@ private:
KeyList keydown; KeyList keydown;
v2s32 mousepos; v2s32 mousepos;
v2s32 mousespeed; v2s32 mousespeed;
bool leftdown = false;
bool rightdown = false;
bool leftclicked = false;
bool rightclicked = false;
bool leftreleased = false;
bool rightreleased = false;
}; };

@ -35,6 +35,8 @@ public:
SPECIAL1, SPECIAL1,
SNEAK, SNEAK,
AUTOFORWARD, AUTOFORWARD,
DIG,
PLACE,
ESC, ESC,

@ -73,6 +73,8 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_right", "KEY_KEY_D"); settings->setDefault("keymap_right", "KEY_KEY_D");
settings->setDefault("keymap_jump", "KEY_SPACE"); settings->setDefault("keymap_jump", "KEY_SPACE");
settings->setDefault("keymap_sneak", "KEY_LSHIFT"); settings->setDefault("keymap_sneak", "KEY_LSHIFT");
settings->setDefault("keymap_dig", "KEY_LBUTTON");
settings->setDefault("keymap_place", "KEY_RBUTTON");
settings->setDefault("keymap_drop", "KEY_KEY_Q"); settings->setDefault("keymap_drop", "KEY_KEY_Q");
settings->setDefault("keymap_zoom", "KEY_KEY_Z"); settings->setDefault("keymap_zoom", "KEY_KEY_Z");
settings->setDefault("keymap_inventory", "KEY_KEY_I"); settings->setDefault("keymap_inventory", "KEY_KEY_I");
@ -269,7 +271,7 @@ void set_default_settings(Settings *settings)
// Input // Input
settings->setDefault("invert_mouse", "false"); settings->setDefault("invert_mouse", "false");
settings->setDefault("mouse_sensitivity", "0.2"); settings->setDefault("mouse_sensitivity", "0.2");
settings->setDefault("repeat_rightclick_time", "0.25"); settings->setDefault("repeat_place_time", "0.25");
settings->setDefault("safe_dig_and_place", "false"); settings->setDefault("safe_dig_and_place", "false");
settings->setDefault("random_input", "false"); settings->setDefault("random_input", "false");
settings->setDefault("aux1_descends", "false"); settings->setDefault("aux1_descends", "false");

@ -491,17 +491,18 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
playersao->setPlayerYaw(yaw); playersao->setPlayerYaw(yaw);
playersao->setFov(fov); playersao->setFov(fov);
playersao->setWantedRange(wanted_range); playersao->setWantedRange(wanted_range);
player->keyPressed = keyPressed; player->keyPressed = keyPressed;
player->control.up = (keyPressed & 1); player->control.up = (keyPressed & (0x1 << 0));
player->control.down = (keyPressed & 2); player->control.down = (keyPressed & (0x1 << 1));
player->control.left = (keyPressed & 4); player->control.left = (keyPressed & (0x1 << 2));
player->control.right = (keyPressed & 8); player->control.right = (keyPressed & (0x1 << 3));
player->control.jump = (keyPressed & 16); player->control.jump = (keyPressed & (0x1 << 4));
player->control.aux1 = (keyPressed & 32); player->control.aux1 = (keyPressed & (0x1 << 5));
player->control.sneak = (keyPressed & 64); player->control.sneak = (keyPressed & (0x1 << 6));
player->control.LMB = (keyPressed & 128); player->control.dig = (keyPressed & (0x1 << 7));
player->control.RMB = (keyPressed & 256); player->control.place = (keyPressed & (0x1 << 8));
player->control.zoom = (keyPressed & 512); player->control.zoom = (keyPressed & (0x1 << 9));
if (playersao->checkMovementCheat()) { if (playersao->checkMovementCheat()) {
// Call callbacks // Call callbacks

@ -57,8 +57,8 @@ struct PlayerControl
bool a_aux1, bool a_aux1,
bool a_sneak, bool a_sneak,
bool a_zoom, bool a_zoom,
bool a_LMB, bool a_dig,
bool a_RMB, bool a_place,
float a_pitch, float a_pitch,
float a_yaw, float a_yaw,
float a_sidew_move_joystick_axis, float a_sidew_move_joystick_axis,
@ -73,8 +73,8 @@ struct PlayerControl
aux1 = a_aux1; aux1 = a_aux1;
sneak = a_sneak; sneak = a_sneak;
zoom = a_zoom; zoom = a_zoom;
LMB = a_LMB; dig = a_dig;
RMB = a_RMB; place = a_place;
pitch = a_pitch; pitch = a_pitch;
yaw = a_yaw; yaw = a_yaw;
sidew_move_joystick_axis = a_sidew_move_joystick_axis; sidew_move_joystick_axis = a_sidew_move_joystick_axis;
@ -88,8 +88,8 @@ struct PlayerControl
bool aux1 = false; bool aux1 = false;
bool sneak = false; bool sneak = false;
bool zoom = false; bool zoom = false;
bool LMB = false; bool dig = false;
bool RMB = false; bool place = false;
float pitch = 0.0f; float pitch = 0.0f;
float yaw = 0.0f; float yaw = 0.0f;
float sidew_move_joystick_axis = 0.0f; float sidew_move_joystick_axis = 0.0f;

@ -231,8 +231,8 @@ int LuaLocalPlayer::l_get_control(lua_State *L)
set("aux1", c.aux1); set("aux1", c.aux1);
set("sneak", c.sneak); set("sneak", c.sneak);
set("zoom", c.zoom); set("zoom", c.zoom);
set("LMB", c.LMB); set("dig", c.dig);
set("RMB", c.RMB); set("place", c.place);
return 1; return 1;
} }

@ -1455,9 +1455,14 @@ int ObjectRef::l_get_player_control(lua_State *L)
lua_setfield(L, -2, "aux1"); lua_setfield(L, -2, "aux1");
lua_pushboolean(L, control.sneak); lua_pushboolean(L, control.sneak);
lua_setfield(L, -2, "sneak"); lua_setfield(L, -2, "sneak");
lua_pushboolean(L, control.LMB); lua_pushboolean(L, control.dig);
lua_setfield(L, -2, "dig");
lua_pushboolean(L, control.place);
lua_setfield(L, -2, "place");
// Legacy fields to ensure mod compatibility
lua_pushboolean(L, control.dig);
lua_setfield(L, -2, "LMB"); lua_setfield(L, -2, "LMB");
lua_pushboolean(L, control.RMB); lua_pushboolean(L, control.place);
lua_setfield(L, -2, "RMB"); lua_setfield(L, -2, "RMB");
lua_pushboolean(L, control.zoom); lua_pushboolean(L, control.zoom);
lua_setfield(L, -2, "zoom"); lua_setfield(L, -2, "zoom");