Skip to content

Commit

Permalink
feat: login and disconnect protection (opentibiabr#3223)
Browse files Browse the repository at this point in the history
  • Loading branch information
murilo09 authored Jan 9, 2025
1 parent 1ed5cd8 commit 13dbc4f
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 89 deletions.
2 changes: 2 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ maintainModeMessage = ""
-- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced"
-- NOTE: removeBeginningWeaponAmmunition: spears, arrows, bolt have endless ammo (allows training for paladins)
-- NOTE: refundManaOnBeginningWeapons: wand of vortex and snakebite refund mana used (allows training for mages)
-- NOTE: loginProtectionTime in MS
worldType = "pvp"
hotkeyAimbotEnabled = true
protectionLevel = 7
Expand All @@ -47,6 +48,7 @@ monthKillsToRedSkull = 10
redSkullDuration = 1
blackSkullDuration = 3
orangeSkullDuration = 7
loginProtectionTime = 10 * 1000

cleanProtectionZones = false

Expand Down
52 changes: 0 additions & 52 deletions data/events/scripts/creature.lua
Original file line number Diff line number Diff line change
@@ -1,60 +1,8 @@
local function removeCombatProtection(playerUid)
local player = Player(playerUid)
if not player then
return true
end

local time = 0
if player:isMage() then
time = 10
elseif player:isPaladin() then
time = 20
else
time = 30
end

player:kv():set("combat-protection", 2)
addEvent(function(playerFuncUid)
local playerEvent = Player(playerFuncUid)
if not playerEvent then
return
end

playerEvent:kv():remove("combat-protection")
playerEvent:remove()
end, time * 1000, playerUid)
end

function Creature:onTargetCombat(target)
if not self then
return true
end

if target:isPlayer() then
if self:isMonster() then
local isProtected = target:kv():get("combat-protection") or 0

if target:getIp() == 0 then -- If player is disconnected, monster shall ignore to attack the player
if target:isPzLocked() then
return true
end
if isProtected <= 0 then
addEvent(removeCombatProtection, 30 * 1000, target.uid)
target:kv():set("combat-protection", 1)
elseif isProtected == 1 then
self:searchTarget()
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
end

return true
end

if isProtected >= os.time() then
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER
end
end
end

if (target:isMonster() and self:isPlayer() and target:getMaster() == self) or (self:isMonster() and target:isPlayer() and self:getMaster() == target) then
return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE
end
Expand Down
22 changes: 0 additions & 22 deletions data/scripts/creaturescripts/player/login.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,6 @@ local function sendBoostMessage(player, category, isIncreased)
return player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, string.format("Event! %s is %screased. Happy Hunting!", category, isIncreased and "in" or "de"))
end

local function onMovementRemoveProtection(playerId, oldPos, time)
local player = Player(playerId)
if not player then
return true
end

local playerPos = player:getPosition()
if (playerPos.x ~= oldPos.x or playerPos.y ~= oldPos.y or playerPos.z ~= oldPos.z) or player:getTarget() then
player:kv():remove("combat-protection")
return true
end

addEvent(onMovementRemoveProtection, 1000, playerId, oldPos, time - 1)
end

local playerLoginGlobal = CreatureEvent("PlayerLoginGlobal")

function playerLoginGlobal.onLogin(player)
Expand Down Expand Up @@ -162,13 +147,6 @@ function playerLoginGlobal.onLogin(player)
player:setRemoveBossTime(1)
end

-- Remove combat protection
local isProtected = player:kv():get("combat-protection") or 0
if isProtected < 1 then
player:kv():set("combat-protection", 1)
onMovementRemoveProtection(playerId, player:getPosition(), 10)
end

-- Change support outfit to a normal outfit to open customize character without crashes
local playerOutfit = player:getOutfit()
if table.contains({ 75, 266, 302 }, playerOutfit.lookType) then
Expand Down
1 change: 1 addition & 0 deletions src/config/config_enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ enum ConfigKey_t : uint16_t {
ONSLAUGHT_CHANCE_FORMULA_C,
OPTIMIZE_DATABASE,
ORANGE_SKULL_DURATION,
LOGIN_PROTECTION_TIME,
OWNER_EMAIL,
OWNER_NAME,
PARALLELISM,
Expand Down
1 change: 1 addition & 0 deletions src/config/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ bool ConfigManager::load() {
loadIntConfig(L, MONTH_KILLS_TO_RED, "monthKillsToRedSkull", 10);
loadIntConfig(L, MULTIPLIER_ATTACKONFIST, "multiplierSpeedOnFist", 5);
loadIntConfig(L, ORANGE_SKULL_DURATION, "orangeSkullDuration", 7);
loadIntConfig(L, LOGIN_PROTECTION_TIME, "loginProtectionTime", 10000);
loadIntConfig(L, PARALLELISM, "parallelism", 2);
loadIntConfig(L, PARTY_LIST_MAX_DISTANCE, "partyListMaxDistance", 0);
loadIntConfig(L, PREY_BONUS_REROLL_PRICE, "preyBonusRerollPrice", 1);
Expand Down
8 changes: 8 additions & 0 deletions src/creatures/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ void Creature::onAttacking(uint32_t interval) {
return;
}

if (attackedCreature->getType() == CreatureType_t::CREATURETYPE_PLAYER) {
const auto &player = attackedCreature->getPlayer();
if (player && player->isDisconnected() && !player->isProtected()) {
player->setProtection(true);
player->setLoginProtection(30000);
}
}

onAttacked();
attackedCreature->onAttacked();

Expand Down
24 changes: 15 additions & 9 deletions src/creatures/monsters/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,8 @@ bool Monster::isOpponent(const std::shared_ptr<Creature> &creature) const {
return creature != master;
}

if (creature->getPlayer() && creature->getPlayer()->hasFlag(PlayerFlags_t::IgnoredByMonsters)) {
const auto &player = creature ? creature->getPlayer() : nullptr;
if (player && player->hasFlag(PlayerFlags_t::IgnoredByMonsters)) {
return false;
}

Expand All @@ -679,7 +680,7 @@ bool Monster::isOpponent(const std::shared_ptr<Creature> &creature) const {

const auto &creatureMaster = creature->getMaster();
const auto &creaturePlayer = creatureMaster ? creatureMaster->getPlayer() : nullptr;
if (creature->getPlayer() || creaturePlayer) {
if (player || creaturePlayer) {
return true;
}

Expand Down Expand Up @@ -913,10 +914,6 @@ bool Monster::isTarget(const std::shared_ptr<Creature> &creature) {
}

if (!isSummon()) {
if (creature->getPlayer() && creature->getPlayer()->isDisconnected()) {
return false;
}

if (getFaction() != FACTION_DEFAULT) {
return isEnemyFaction(creature->getFaction());
}
Expand All @@ -934,6 +931,11 @@ bool Monster::selectTarget(const std::shared_ptr<Creature> &creature) {
return false;
}

const auto &player = creature ? creature->getPlayer() : nullptr;
if (player && player->isLoginProtected()) {
return false;
}

auto it = getTargetIterator(creature);
if (it == targetList.end()) {
// Target not found in our target list.
Expand Down Expand Up @@ -1088,11 +1090,10 @@ void Monster::onThink_async() {
setFollowCreature(master);
}
} else if (!targetList.empty()) {
const bool attackedCreatureIsDisconnected = attackedCreature && attackedCreature->getPlayer() && attackedCreature->getPlayer()->isDisconnected();
const bool attackedCreatureIsUnattackable = attackedCreature && !canUseAttack(getPosition(), attackedCreature);
const bool attackedCreatureIsUnreachable = targetDistance <= 1 && attackedCreature && followCreature && !hasFollowPath;
if (!attackedCreature || attackedCreatureIsDisconnected || attackedCreatureIsUnattackable || attackedCreatureIsUnreachable) {
if (!followCreature || !hasFollowPath || attackedCreatureIsDisconnected) {
if (!attackedCreature || attackedCreatureIsUnattackable || attackedCreatureIsUnreachable) {
if (!followCreature || !hasFollowPath) {
searchTarget(TARGETSEARCH_NEAREST);
} else if (attackedCreature && isFleeing() && !canUseAttack(getPosition(), attackedCreature)) {
searchTarget(TARGETSEARCH_DEFAULT);
Expand All @@ -1115,6 +1116,11 @@ void Monster::doAttacking(uint32_t interval) {
return;
}

const auto &player = attackedCreature->getPlayer();
if (player && player->isLoginProtected()) {
return;
}

bool updateLook = true;
bool resetTicks = interval != 0;
attackTicks += interval;
Expand Down
33 changes: 27 additions & 6 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2045,16 +2045,20 @@ void Player::sendPing() {

const int64_t noPongTime = timeNow - lastPong;
const auto &attackedCreature = getAttackedCreature();
if ((hasLostConnection || noPongTime >= 7000) && attackedCreature && attackedCreature->getPlayer()) {
if ((hasLostConnection || noPongTime >= 10000) && attackedCreature) {
setAttackedCreature(nullptr);
}

if (noPongTime >= 60000 && canLogout() && g_creatureEvents().playerLogout(static_self_cast<Player>())) {
g_logger().info("Player {} has been kicked due to ping timeout. (has client: {})", getName(), client != nullptr);
if (client) {
client->logout(true, true);
if (noPongTime >= 60000 && shouldForceLogout) {
if (canLogout() && g_creatureEvents().playerLogout(static_self_cast<Player>())) {
g_logger().info("Player {} has been kicked due to ping timeout. (has client: {})", getName(), client != nullptr);
if (client) {
client->logout(true, true);
} else {
g_game().removeCreature(static_self_cast<Player>(), true);
}
} else {
g_game().removeCreature(static_self_cast<Player>(), true);
shouldForceLogout = false;
}
}
}
Expand Down Expand Up @@ -2930,6 +2934,23 @@ bool Player::canDoPotionAction() const {
return nextPotionAction <= OTSYS_TIME();
}

void Player::setLoginProtection(int64_t time) {
loginProtectionTime = OTSYS_TIME() + time;
}
bool Player::isLoginProtected() const {
return loginProtectionTime > OTSYS_TIME();
}
void Player::resetLoginProtection() {
loginProtectionTime = 0;
}

void Player::setProtection(bool status) {
connProtected = status;
}
bool Player::isProtected() {
return connProtected;
}

void Player::cancelPush() {
if (actionTaskEventPush != 0) {
g_dispatcher().stopEvent(actionTaskEventPush);
Expand Down
10 changes: 10 additions & 0 deletions src/creatures/players/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,13 @@ class Player final : public Creature, public Cylinder, public Bankable {
void setNextPotionAction(int64_t time);
bool canDoPotionAction() const;

void setLoginProtection(int64_t time);
bool isLoginProtected() const;
void resetLoginProtection();

void setProtection(bool status);
bool isProtected();

void cancelPush();

void setModuleDelay(uint8_t byteortype, int16_t delay);
Expand Down Expand Up @@ -1421,6 +1428,7 @@ class Player final : public Creature, public Cylinder, public Bankable {
int64_t nextPotionAction = 0;
int64_t lastQuickLootNotification = 0;
int64_t lastWalking = 0;
int64_t loginProtectionTime = 0;
uint64_t asyncOngoingTasks = 0;

std::vector<Kill> unjustifiedKills;
Expand Down Expand Up @@ -1560,6 +1568,8 @@ class Player final : public Creature, public Cylinder, public Bankable {
bool moved = false;
bool m_isDead = false;
bool imbuementTrackerWindowOpen = false;
bool shouldForceLogout = true;
bool connProtected = false;

// Hazard system
int64_t lastHazardSystemCriticalHit = 0;
Expand Down
10 changes: 10 additions & 0 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3505,6 +3505,7 @@ void Game::playerMove(uint32_t playerId, Direction direction) {
return;
}

player->resetLoginProtection();
player->resetIdleTime();
player->setNextWalkActionTask(nullptr);
player->cancelPush();
Expand All @@ -3518,6 +3519,7 @@ void Game::forcePlayerMove(uint32_t playerId, Direction direction) {
return;
}

player->resetLoginProtection();
player->resetIdleTime();
player->setNextWalkActionTask(nullptr);
player->cancelPush();
Expand Down Expand Up @@ -3693,6 +3695,7 @@ void Game::playerAutoWalk(uint32_t playerId, const std::vector<Direction> &listD
return;
}

player->resetLoginProtection();
player->resetIdleTime();
player->setNextWalkTask(nullptr);
player->startAutoWalk(listDir, false);
Expand All @@ -3709,6 +3712,7 @@ void Game::forcePlayerAutoWalk(uint32_t playerId, const std::vector<Direction> &
player->sendCancelTarget();
player->setFollowCreature(nullptr);

player->resetLoginProtection();
player->resetIdleTime();
player->setNextWalkTask(nullptr);

Expand Down Expand Up @@ -3842,6 +3846,7 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f
return;
}

player->resetLoginProtection();
player->resetIdleTime();
if (it.isRune() || it.type == ITEM_TYPE_POTION) {
player->setNextPotionActionTask(nullptr);
Expand Down Expand Up @@ -3963,6 +3968,7 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo
return;
}

player->resetLoginProtection();
player->resetIdleTime();
player->setNextActionTask(nullptr);

Expand Down Expand Up @@ -4127,6 +4133,7 @@ void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uin
return;
}

player->resetLoginProtection();
player->resetIdleTime();
if (it.isRune() || it.type == ITEM_TYPE_POTION) {
player->setNextPotionActionTask(nullptr);
Expand Down Expand Up @@ -5911,6 +5918,7 @@ void Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId) {
}

if (player->getAttackedCreature() && creatureId == 0) {
player->resetLoginProtection();
player->setAttackedCreature(nullptr);
player->sendCancelTarget();
return;
Expand Down Expand Up @@ -6085,6 +6093,7 @@ void Game::playerTurn(uint32_t playerId, Direction dir) {
return;
}

player->resetLoginProtection();
player->resetIdleTime();
internalCreatureTurn(player, dir);
}
Expand Down Expand Up @@ -6208,6 +6217,7 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type, c
return;
}

player->resetLoginProtection();
player->resetIdleTime();

if (playerSaySpell(player, type, text)) {
Expand Down
7 changes: 7 additions & 0 deletions src/server/network/protocol/protocolgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ void ProtocolGame::login(const std::string &name, uint32_t accountId, OperatingS

player->lastIP = player->getIP();
player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1);
player->loginProtectionTime = OTSYS_TIME() + g_configManager().getNumber(LOGIN_PROTECTION_TIME);
acceptPackets = true;
} else {
if (eventConnect != 0 || !g_configManager().getBoolean(REPLACE_KICK_ON_LOGIN)) {
Expand Down Expand Up @@ -666,6 +667,12 @@ void ProtocolGame::connect(const std::string &playerName, OperatingSystem_t oper
sendAddCreature(player, player->getPosition(), 0, true);
player->lastIP = player->getIP();
player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1);
if (player->isProtected()) {
player->setProtection(false);
player->resetLoginProtection();
} else {
player->setLoginProtection(g_configManager().getNumber(LOGIN_PROTECTION_TIME));
}
player->resetIdleTime();
acceptPackets = true;
}
Expand Down

0 comments on commit 13dbc4f

Please sign in to comment.