Addition of Disconnection class.

Adapted from: L2jUnity free files.
This commit is contained in:
MobiusDev 2018-04-01 17:23:59 +00:00
parent a117a04126
commit c5b6a0d7c9
186 changed files with 3372 additions and 3468 deletions

View File

@ -26,6 +26,7 @@ import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2AccessLevel;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -129,7 +130,7 @@ public final class AdminChangeAccessLevel implements IAdminCommandHandler
{
player.setAccessLevel(lvl, false, true);
player.sendMessage("Your character has been banned. Bye.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -19,6 +19,7 @@ package handlers.admincommandhandlers;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
/**
* This class handles following admin commands: - character_disconnect = disconnects target player
@ -68,7 +69,7 @@ public class AdminDisconnect implements IAdminCommandHandler
{
activeChar.sendMessage("Character " + player.getName() + " disconnected from server.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -18,10 +18,10 @@ package handlers.admincommandhandlers;
import java.util.StringTokenizer;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
public class AdminKick implements IAdminCommandHandler
{
@ -44,11 +44,7 @@ public class AdminKick implements IAdminCommandHandler
final L2PcInstance plyr = L2World.getInstance().getPlayer(player);
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
activeChar.sendMessage("You kicked " + plyr.getName() + " from the game.");
}
}
@ -61,7 +57,7 @@ public class AdminKick implements IAdminCommandHandler
if (!player.isGM())
{
counter++;
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
activeChar.sendMessage("Kicked " + counter + " players.");

View File

@ -21,7 +21,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.handler.AdminCommandHandler;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
@ -31,6 +30,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -170,11 +170,7 @@ public class AdminMenu implements IAdminCommandHandler
String text;
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
text = "You kicked " + plyr.getName() + " from the game.";
}
else

View File

@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -58,7 +59,7 @@ public class BanHandler implements IPunishmentHandler
}
else
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
}
}
break;
@ -90,7 +91,7 @@ public class BanHandler implements IPunishmentHandler
*/
private static void applyToPlayer(L2PcInstance player)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
}
@Override

View File

@ -18,6 +18,7 @@ package handlers.telnethandlers.player;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.telnet.ITelnetCommand;
import io.netty.channel.ChannelHandlerContext;
@ -49,7 +50,7 @@ public class Kick implements ITelnetCommand
final L2PcInstance player = L2World.getInstance().getPlayer(args[0]);
if (player != null)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
return "Player has been successfully kicked.";
}
return "Couldn't find player with such name.";

View File

@ -562,15 +562,8 @@ public class LoginServerThread extends Thread
final L2GameClient client = _accountsInGameServer.get(account);
if (client != null)
{
if (client.isDetached())
{
client.getActiveChar().logout();
}
else
{
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
ACCOUNTING_LOGGER.info(getClass().getSimpleName() + ": Kicked by login, " + client);
ACCOUNTING_LOGGER.info("Kicked by login, " + client);
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
}

View File

@ -38,11 +38,10 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Hero;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.network.ClientNetworkManager;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.EventLoopGroupManager;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.telnet.TelnetServer;
import com.l2jmobius.gameserver.util.Broadcast;
@ -610,27 +609,7 @@ public class Shutdown extends Thread
{
for (L2PcInstance player : L2World.getInstance().getPlayers())
{
// Logout Character
try
{
final L2GameClient client = player.getClient();
if ((client != null) && !client.isDetached())
{
client.close(ServerClose.STATIC_PACKET);
client.setActiveChar(null);
player.setClient(null);
}
else if ((client == null) || client.isDetached())
// player is probably a bot - force logout
{
player.logout();
}
player.deleteMe();
}
catch (Throwable t)
{
LOGGER.log(Level.WARNING, "Failed logour char " + player, t);
}
Disconnection.of(player).defaultSequence(true);
}
}

View File

@ -33,6 +33,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.TradeItem;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SellBuffHolder;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
public class OfflineTradersTable
@ -49,6 +50,10 @@ public class OfflineTradersTable
private static final String LOAD_OFFLINE_STATUS = "SELECT * FROM character_offline_trade";
private static final String LOAD_OFFLINE_ITEMS = "SELECT * FROM character_offline_trade_items WHERE `charId`=?";
protected OfflineTradersTable()
{
}
public void storeOffliners()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
@ -300,7 +305,7 @@ public class OfflineTradersTable
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error loading trader: " + player, e);
if (player != null)
{
player.deleteMe();
Disconnection.of(player).defaultSequence(false);
}
}
}
@ -470,11 +475,11 @@ public class OfflineTradersTable
*/
public static OfflineTradersTable getInstance()
{
return SingletonHolder._instance;
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final OfflineTradersTable _instance = new OfflineTradersTable();
protected static final OfflineTradersTable INSTANCE = new OfflineTradersTable();
}
}

View File

@ -72,6 +72,12 @@ public final class AntiFeedManager
return false;
}
// Players in offline mode should't be valid targets.
if (targetPlayer.getClient().isDetached())
{
return false;
}
if ((Config.ANTIFEED_INTERVAL > 0) && _lastDeathTimes.containsKey(targetPlayer.getObjectId()))
{
if ((System.currentTimeMillis() - _lastDeathTimes.get(targetPlayer.getObjectId())) < Config.ANTIFEED_INTERVAL)
@ -211,7 +217,7 @@ public final class AntiFeedManager
*/
public final void onDisconnect(L2GameClient client)
{
if ((client == null) || client.isDetached())
if ((client == null) || (client.getConnectionAddress() == null))
{
return;
}

View File

@ -39,6 +39,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnNpcCreatureSee;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
import com.l2jmobius.gameserver.util.Util;
@ -143,8 +144,8 @@ public final class L2World
final L2PcInstance existingPlayer = _allPlayers.putIfAbsent(object.getObjectId(), newPlayer);
if (existingPlayer != null)
{
existingPlayer.logout();
newPlayer.logout();
Disconnection.of(existingPlayer).defaultSequence(false);
Disconnection.of(newPlayer).defaultSequence(false);
LOGGER.warning(getClass().getSimpleName() + ": Duplicate character!? Disconnected both characters (" + newPlayer.getName() + ")");
}
else if (Config.FACTION_SYSTEM_ENABLED)

View File

@ -131,6 +131,7 @@ import com.l2jmobius.gameserver.model.stats.MoveType;
import com.l2jmobius.gameserver.model.stats.Stats;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.model.zone.ZoneRegion;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.Attack;
@ -3287,7 +3288,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
if (isPlayer())
{
getActingPlayer().logout();
Disconnection.of(getActingPlayer()).defaultSequence(false);
}
else if (isSummon())
{

View File

@ -257,6 +257,7 @@ import com.l2jmobius.gameserver.model.variables.AccountVariables;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AbstractHtmlPacket;
@ -292,7 +293,6 @@ import com.l2jmobius.gameserver.network.serverpackets.HennaInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import com.l2jmobius.gameserver.network.serverpackets.ItemList;
import com.l2jmobius.gameserver.network.serverpackets.LeaveWorld;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.MyTargetSelected;
import com.l2jmobius.gameserver.network.serverpackets.NicknameChanged;
@ -311,7 +311,6 @@ import com.l2jmobius.gameserver.network.serverpackets.RecipeShopMsg;
import com.l2jmobius.gameserver.network.serverpackets.RecipeShopSellList;
import com.l2jmobius.gameserver.network.serverpackets.RelationChanged;
import com.l2jmobius.gameserver.network.serverpackets.Ride;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SetupGauge;
import com.l2jmobius.gameserver.network.serverpackets.ShortCutInit;
import com.l2jmobius.gameserver.network.serverpackets.SkillCoolTime;
@ -803,6 +802,8 @@ public final class L2PcInstance extends L2Playable
private final Fishing _fishing = new Fishing(this);
private Future<?> _autoSaveTask = null;
public void setPvpFlagLasts(long time)
{
_pvpFlagLasts = time;
@ -1253,38 +1254,6 @@ public final class L2PcInstance extends L2Playable
_inCraftMode = b;
}
/**
* Manage Logout Task:
* <ul>
* <li>Remove player from world</li>
* <li>Save player data into DB</li>
* </ul>
*/
public void logout()
{
logout(true);
}
/**
* Manage Logout Task:
* <ul>
* <li>Remove player from world</li>
* <li>Save player data into DB</li>
* </ul>
* @param closeClient
*/
public void logout(boolean closeClient)
{
try
{
closeNetConnection(closeClient);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception on logout(): " + e.getMessage(), e);
}
}
/**
* @return a table containing all Common L2RecipeList of the L2PcInstance.
*/
@ -3975,33 +3944,6 @@ public final class L2PcInstance extends L2Playable
return ip;
}
/**
* Close the active connection with the client.
* @param closeClient
*/
private void closeNetConnection(boolean closeClient)
{
final L2GameClient client = _client;
if (client != null)
{
if (client.isDetached())
{
client.cleanMe(true);
}
else if (client.getChannel().isActive())
{
if (closeClient)
{
client.close(LeaveWorld.STATIC_PACKET);
}
else
{
client.close(ServerClose.STATIC_PACKET);
}
}
}
}
public Location getCurrentSkillWorldPosition()
{
return _currentSkillWorldPosition;
@ -6824,6 +6766,8 @@ public final class L2PcInstance extends L2Playable
player.startOnlineTimeUpdateTask();
player.setOnlineStatus(true, false);
player.startAutoSaveTask();
}
catch (Exception e)
{
@ -8102,6 +8046,61 @@ public final class L2PcInstance extends L2Playable
return isInCategory(CategoryType.SIXTH_CLASS_GROUP);
}
private void startAutoSaveTask()
{
if ((Config.CHAR_DATA_STORE_INTERVAL > 0) && (_autoSaveTask == null))
{
_autoSaveTask = ThreadPoolManager.scheduleAtFixedRate(this::autoSave, 300_000L, TimeUnit.MINUTES.toMillis(Config.CHAR_DATA_STORE_INTERVAL));
}
}
private void stopAutoSaveTask()
{
if (_autoSaveTask != null)
{
_autoSaveTask.cancel(false);
_autoSaveTask = null;
}
}
protected void autoSave()
{
storeMe();
storeRecommendations();
if (Config.UPDATE_ITEMS_ON_CHAR_STORE)
{
getInventory().updateDatabase();
getWarehouse().updateDatabase();
}
}
public boolean canLogout()
{
if (hasItemRequest())
{
return false;
}
if (isLocked())
{
_log.warning("Player " + getName() + " tried to restart/logout during class change.");
return false;
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(this) && !(isGM() && Config.GM_RESTART_FIGHTING))
{
return false;
}
if (isBlockedFromExit())
{
return false;
}
return true;
}
/**
* Return True if the L2PcInstance is autoAttackable.<br>
* <B><U>Actions</U>:</B>
@ -10691,28 +10690,19 @@ public final class L2PcInstance extends L2Playable
* <li>If the L2PcInstance is in observer mode, set its position to its position before entering in observer mode</li>
* <li>Set the online Flag to True or False and update the characters table of the database with online status and lastAccess</li>
* <li>Stop the HP/MP/CP Regeneration task</li>
* <li>Cancel Crafting, Attak or Cast</li>
* <li>Cancel Crafting, Attack or Cast</li>
* <li>Remove the L2PcInstance from the world</li>
* <li>Stop Party and Unsummon Pet</li>
* <li>Update database with items in its inventory and remove them from the world</li>
* <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI</li>
* <li>Close the connection with the client</li>
* </ul>
* <br>
* Remember this method is not to be used to half-ass disconnect players! This method is dedicated only to erase the player from the world.<br>
* If you intend to disconnect a player please use {@link Disconnection}
*/
@Override
public boolean deleteMe()
{
cleanup();
storeMe();
// Stop all passives and augment options without broadcasting changes.
getEffectList().stopAllPassives(false, false);
getEffectList().stopAllOptions(false, false);
return super.deleteMe();
}
private synchronized void cleanup()
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerLogout(this), this);
@ -11093,6 +11083,15 @@ public final class L2PcInstance extends L2Playable
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerMentorStatus(this, false), this);
}
// we store all data from players who are disconnected while in an event in order to restore it in the next login
if (L2Event.isParticipant(this))
{
L2Event.savePlayerEventStatus(this);
}
// Anti Feed
AntiFeedManager.getInstance().onDisconnect(getClient());
try
{
notifyFriends(L2FriendStatus.MODE_OFFLINE);
@ -11102,6 +11101,14 @@ public final class L2PcInstance extends L2Playable
{
_log.log(Level.WARNING, "Exception on deleteMe() notifyFriends: " + e.getMessage(), e);
}
// Stop all passives and augment options
getEffectList().stopAllPassives(false, false);
getEffectList().stopAllOptions(false, false);
stopAutoSaveTask();
return super.deleteMe();
}
public int getInventoryLimit()

View File

@ -26,6 +26,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.Disconnection;
/**
* Task that handles illegal player actions.
@ -86,7 +87,7 @@ public final class IllegalPlayerActionTask implements Runnable
}
case KICK:
{
_actor.logout(false);
Disconnection.of(_actor).defaultSequence(false);
break;
}
case KICKBAN:

View File

@ -0,0 +1,189 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.network;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
/**
* @author NB4L1
*/
public final class Disconnection
{
private static final Logger LOGGER = Logger.getLogger(Disconnection.class.getName());
public static L2GameClient getClient(L2GameClient client, L2PcInstance activeChar)
{
if (client != null)
{
return client;
}
if (activeChar != null)
{
return activeChar.getClient();
}
return null;
}
public static L2PcInstance getActiveChar(L2GameClient client, L2PcInstance activeChar)
{
if (activeChar != null)
{
return activeChar;
}
if (client != null)
{
return client.getActiveChar();
}
return null;
}
private final L2GameClient _client;
private final L2PcInstance _activeChar;
private Disconnection(L2GameClient client)
{
this(client, null);
}
public static Disconnection of(L2GameClient client)
{
return new Disconnection(client);
}
private Disconnection(L2PcInstance activeChar)
{
this(null, activeChar);
}
public static Disconnection of(L2PcInstance activeChar)
{
return new Disconnection(activeChar);
}
private Disconnection(L2GameClient client, L2PcInstance activeChar)
{
_client = getClient(client, activeChar);
_activeChar = getActiveChar(client, activeChar);
if (_client != null)
{
_client.setActiveChar(null);
}
if (_activeChar != null)
{
_activeChar.setClient(null);
}
}
public static Disconnection of(L2GameClient client, L2PcInstance activeChar)
{
return new Disconnection(client, activeChar);
}
public Disconnection storeMe()
{
try
{
if (_activeChar != null)
{
_activeChar.storeMe();
}
}
catch (RuntimeException e)
{
LOGGER.warning(e.getMessage());
}
return this;
}
public Disconnection deleteMe()
{
try
{
if (_activeChar != null)
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerLogout(_activeChar), _activeChar);
_activeChar.deleteMe();
}
}
catch (RuntimeException e)
{
LOGGER.warning(e.getMessage());
}
return this;
}
public Disconnection close(boolean toLoginScreen)
{
if (_client != null)
{
_client.close(toLoginScreen);
}
return this;
}
public Disconnection close(IClientOutgoingPacket packet)
{
if (_client != null)
{
_client.close(packet);
}
return this;
}
public void defaultSequence(boolean toLoginScreen)
{
defaultSequence();
close(toLoginScreen);
}
public void defaultSequence(IClientOutgoingPacket packet)
{
defaultSequence();
close(packet);
}
private void defaultSequence()
{
storeMe();
deleteMe();
}
public void onDisconnection()
{
if (_activeChar != null)
{
ThreadPoolManager.schedule(() -> defaultSequence(), _activeChar.canLogout() ? 0 : AttackStanceTaskManager.COMBAT_TIME);
}
}
}

View File

@ -21,9 +21,6 @@ import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -33,36 +30,28 @@ import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.network.ChannelInboundHandler;
import com.l2jmobius.commons.network.ICrypt;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.LoginServerThread.SessionKey;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.data.xml.impl.SecondaryAuthData;
import com.l2jmobius.gameserver.enums.CharacterDeleteFailType;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.AntiFeedManager;
import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
import com.l2jmobius.gameserver.model.CharSelectInfoPackage;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.L2Event;
import com.l2jmobius.gameserver.model.holders.ClientHardwareInfoHolder;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.LeaveWorld;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.security.SecondaryPasswordAuth;
import com.l2jmobius.gameserver.util.FloodProtectors;
import com.l2jmobius.gameserver.util.Util;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
@ -74,7 +63,7 @@ import io.netty.channel.ChannelHandlerContext;
public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
protected static final Logger LOGGER = Logger.getLogger(L2GameClient.class.getName());
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
private final int _objectId;
@ -88,20 +77,15 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
private SecondaryPasswordAuth _secondaryAuth;
private ClientHardwareInfoHolder _hardwareInfo;
private boolean _isAuthedGG;
private final long _connectionStartTime = System.currentTimeMillis();
private CharSelectInfoPackage[] _charSlotMapping = null;
// flood protectors
private final FloodProtectors _floodProtectors = new FloodProtectors(this);
// Task
protected final ScheduledFuture<?> _autoSaveInDB;
protected ScheduledFuture<?> _cleanupTask = null;
// Crypt
private final Crypt _crypt;
private boolean _isDetached = false;
private volatile boolean _isDetached = false;
private boolean _protocol;
@ -111,14 +95,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
_objectId = IdFactory.getInstance().getNextId();
_crypt = new Crypt(this);
if (Config.CHAR_DATA_STORE_INTERVAL > 0)
{
_autoSaveInDB = ThreadPoolManager.scheduleAtFixedRate(new AutoSaveTask(), 300000L, Config.CHAR_DATA_STORE_INTERVAL);
}
else
{
_autoSaveInDB = null;
}
}
public int getObjectId()
@ -135,23 +111,18 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
final InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
_addr = address.getAddress();
_channel = ctx.channel();
LOGGER.finer("Client Connected: " + ctx.channel());
LOG_ACCOUNTING.finer("Client Connected: " + ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx)
{
LOGGER.finer("Client Disconnected: " + ctx.channel());
LOG_ACCOUNTING.finer("Client Disconnected: " + ctx.channel());
// no long running tasks here, do it async
try
{
ThreadPoolManager.execute(new DisconnectTask());
}
catch (RejectedExecutionException e)
{
// server is closing
}
LoginServerThread.getInstance().sendLogout(getAccountName());
IdFactory.getInstance().releaseId(getObjectId());
Disconnection.of(this).onDisconnection();
}
@Override
@ -172,6 +143,25 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
}
public void closeNow()
{
if (_channel != null)
{
_channel.close();
}
}
public void close(IClientOutgoingPacket packet)
{
sendPacket(packet);
closeNow();
}
public void close(boolean toLoginScreen)
{
close(toLoginScreen ? ServerClose.STATIC_PACKET : LeaveWorld.STATIC_PACKET);
}
public Channel getChannel()
{
return _channel;
@ -193,19 +183,14 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _addr;
}
public long getConnectionStartTime()
{
return _connectionStartTime;
}
public L2PcInstance getActiveChar()
{
return _activeChar;
}
public void setActiveChar(L2PcInstance pActiveChar)
public void setActiveChar(L2PcInstance activeChar)
{
_activeChar = pActiveChar;
_activeChar = activeChar;
}
public ReentrantLock getActiveCharLock()
@ -228,9 +213,9 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _isAuthedGG;
}
public void setAccountName(String pAccountName)
public void setAccountName(String activeChar)
{
_accountName = pAccountName;
_accountName = activeChar;
if (SecondaryAuthData.getInstance().isEnabled())
{
@ -287,16 +272,16 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
/**
* Method to handle character deletion
* @param charslot
* @param characterSlot
* @return a byte:
* <li>-1: Error: No char was found for such charslot, caught exception, etc...
* <li>0: character is not member of any clan, proceed with deletion
* <li>1: character is member of a clan, but not clan leader
* <li>2: character is clan leader
*/
public CharacterDeleteFailType markToDeleteChar(int charslot)
public CharacterDeleteFailType markToDeleteChar(int characterSlot)
{
final int objectId = getObjectIdForSlot(charslot);
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return CharacterDeleteFailType.UNKNOWN;
@ -354,38 +339,14 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
_logAccounting.info("Delete, " + objectId + ", " + this);
LOG_ACCOUNTING.info("Delete, " + objectId + ", " + this);
return CharacterDeleteFailType.NONE;
}
/**
* Save the L2PcInstance to the database.
*/
public void saveCharToDisk()
public void restore(int characterSlot)
{
try
{
if (getActiveChar() != null)
{
getActiveChar().storeMe();
getActiveChar().storeRecommendations();
if (Config.UPDATE_ITEMS_ON_CHAR_STORE)
{
getActiveChar().getInventory().updateDatabase();
getActiveChar().getWarehouse().updateDatabase();
}
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Error saving character..", e);
}
}
public void markRestoredChar(int charslot)
{
final int objid = getObjectIdForSlot(charslot);
if (objid < 0)
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return;
}
@ -393,7 +354,7 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE characters SET deletetime=0 WHERE charId=?"))
{
statement.setInt(1, objid);
statement.setInt(1, objectId);
statement.execute();
}
catch (Exception e)
@ -401,7 +362,7 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
LOGGER.log(Level.SEVERE, "Error restoring character.", e);
}
_logAccounting.info("Restore, " + objid + ", " + this);
LOG_ACCOUNTING.info("Restore, " + objectId + ", " + this);
}
public static void deleteCharByObjId(int objid)
@ -555,38 +516,30 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
public L2PcInstance loadCharFromDisk(int charslot)
public L2PcInstance load(int characterSlot)
{
final int objId = getObjectIdForSlot(charslot);
if (objId < 0)
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return null;
}
L2PcInstance character = L2World.getInstance().getPlayer(objId);
if (character != null)
L2PcInstance player = L2World.getInstance().getPlayer(objectId);
if (player != null)
{
// exploit prevention, should not happens in normal way
LOGGER.severe("Attempt of double login: " + character.getName() + "(" + objId + ") " + getAccountName());
if (character.getClient() != null)
{
character.getClient().closeNow();
}
else
{
character.deleteMe();
}
LOGGER.severe("Attempt of double login: " + player.getName() + "(" + objectId + ") " + getAccountName());
Disconnection.of(player).defaultSequence(false);
return null;
}
character = L2PcInstance.load(objId);
if (character == null)
player = L2PcInstance.load(objectId);
if (player == null)
{
LOGGER.severe("could not restore in slot: " + charslot);
LOGGER.severe("Could not restore in slot: " + characterSlot);
}
// setCharacter(character);
return character;
return player;
}
/**
@ -611,47 +564,21 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _secondaryAuth;
}
public void close(IOutgoingPacket packet)
{
if (packet != null)
{
_channel.writeAndFlush(packet);
}
_channel.close();
}
/**
* @param charslot
* @param characterSlot
* @return
*/
private int getObjectIdForSlot(int charslot)
private int getObjectIdForSlot(int characterSlot)
{
final CharSelectInfoPackage info = getCharSelection(charslot);
final CharSelectInfoPackage info = getCharSelection(characterSlot);
if (info == null)
{
LOGGER.warning(toString() + " tried to delete Character in slot " + charslot + " but no characters exits at that slot.");
LOGGER.warning(toString() + " tried to delete Character in slot " + characterSlot + " but no characters exits at that slot.");
return -1;
}
return info.getObjectId();
}
/**
* Close client connection with {@link ServerClose} packet
*/
public void closeNow()
{
_isDetached = true; // prevents more packets execution
close(ServerClose.STATIC_PACKET);
synchronized (this)
{
if (_cleanupTask != null)
{
cancelCleanup();
}
_cleanupTask = ThreadPoolManager.schedule(new CleanupTask(), 0); // instant
}
}
/**
* Produces the best possible string representation of this client.
*/
@ -688,209 +615,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
protected class DisconnectTask implements Runnable
{
@Override
public void run()
{
boolean fast = true;
try
{
if ((getActiveChar() != null) && !isDetached())
{
setDetached(true);
if (offlineMode(getActiveChar()))
{
getActiveChar().leaveParty();
OlympiadManager.getInstance().unRegisterNoble(getActiveChar());
// If the L2PcInstance has Pet, unsummon it
L2Summon pet = getActiveChar().getPet();
if (pet != null)
{
pet.setRestoreSummon(true);
pet.unSummon(getActiveChar());
pet = getActiveChar().getPet();
// Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
if (pet != null)
{
pet.broadcastNpcInfo(0);
}
}
getActiveChar().getServitors().values().forEach(s ->
{
s.setRestoreSummon(true);
s.unSummon(getActiveChar());
});
if (Config.OFFLINE_SET_NAME_COLOR)
{
getActiveChar().getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
getActiveChar().broadcastUserInfo();
}
if (getActiveChar().getOfflineStartTime() == 0)
{
getActiveChar().setOfflineStartTime(System.currentTimeMillis());
}
// Store trade on exit, if realtime saving is enabled.
if (Config.STORE_OFFLINE_TRADE_IN_REALTIME)
{
OfflineTradersTable.onTransaction(getActiveChar(), false, true);
}
_logAccounting.info("Entering offline mode, " + L2GameClient.this);
return;
}
fast = !getActiveChar().isInCombat() && !getActiveChar().isLocked();
}
cleanMe(fast);
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error while disconnecting client.", e1);
}
IdFactory.getInstance().releaseId(getObjectId());
}
}
/**
* @param player the player to be check.
* @return {@code true} if the player is allowed to remain as off-line shop.
*/
protected boolean offlineMode(L2PcInstance player)
{
if (player.isInOlympiadMode() || player.isBlockedFromExit() || player.isJailed() || (player.getVehicle() != null))
{
return false;
}
boolean canSetShop = false;
switch (player.getPrivateStoreType())
{
case SELL:
case PACKAGE_SELL:
case BUY:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
case MANUFACTURE:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
default:
{
canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isInCraftMode();
break;
}
}
if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
{
canSetShop = false;
}
return canSetShop;
}
public void cleanMe(boolean fast)
{
try
{
synchronized (this)
{
if (_cleanupTask == null)
{
_cleanupTask = ThreadPoolManager.schedule(new CleanupTask(), fast ? 5 : 15000L);
}
}
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error during cleanup.", e1);
}
}
protected class CleanupTask implements Runnable
{
@Override
public void run()
{
try
{
// we are going to manually save the char bellow thus we can force the cancel
if (_autoSaveInDB != null)
{
_autoSaveInDB.cancel(true);
// ThreadPoolManager.getInstance().removeGeneral((Runnable) _autoSaveInDB);
}
if (getActiveChar() != null) // this should only happen on connection loss
{
if (getActiveChar().isLocked())
{
LOGGER.warning("Player " + getActiveChar().getName() + " still performing subclass actions during disconnect.");
}
// we store all data from players who are disconnected while in an event in order to restore it in the next login
if (L2Event.isParticipant(getActiveChar()))
{
L2Event.savePlayerEventStatus(getActiveChar());
}
if (getActiveChar().isOnline())
{
getActiveChar().deleteMe();
AntiFeedManager.getInstance().onDisconnect(L2GameClient.this);
}
// prevent closing again
getActiveChar().setClient(null);
}
setActiveChar(null);
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error while cleanup client.", e1);
}
finally
{
LoginServerThread.getInstance().sendLogout(getAccountName());
}
}
}
protected class AutoSaveTask implements Runnable
{
@Override
public void run()
{
try
{
final L2PcInstance player = getActiveChar();
if ((player != null) && player.isOnline()) // safety precaution
{
saveCharToDisk();
final L2Summon pet = player.getPet();
if (pet != null)
{
pet.storeMe();
}
player.getServitors().values().forEach(L2Summon::storeMe);
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Error on AutoSaveTask.", e);
}
}
}
public boolean isProtocolOk()
{
return _protocol;
@ -901,20 +625,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
_protocol = b;
}
public boolean handleCheat(String punishment)
{
if (_activeChar != null)
{
Util.handleIllegalPlayerAction(_activeChar, toString() + ": " + punishment, Config.DEFAULT_PUNISH);
return true;
}
final Logger logAudit = Logger.getLogger("audit");
logAudit.info("AUDIT: Client " + toString() + " kicked for reason: " + punishment);
closeNow();
return false;
}
public void setClientTracert(int[][] tracert)
{
trace = tracert;
@ -925,17 +635,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return trace;
}
private boolean cancelCleanup()
{
final Future<?> task = _cleanupTask;
if (task != null)
{
_cleanupTask = null;
return task.cancel(true);
}
return false;
}
public void sendActionFailed()
{
sendPacket(ActionFailed.STATIC_PACKET);

View File

@ -54,7 +54,7 @@ public final class AuthLogin implements IClientIncomingPacket
{
if (_loginName.isEmpty() || !client.isProtocolOk())
{
client.close(null);
client.closeNow();
return;
}

View File

@ -41,6 +41,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerCreate;
import com.l2jmobius.gameserver.model.items.PcItemTemplate;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.CharCreateFail;
import com.l2jmobius.gameserver.network.serverpackets.CharCreateOk;
@ -333,7 +334,7 @@ public final class CharacterCreate implements IClientIncomingPacket
{
newChar.getVariables().set("intro_god_video", true);
}
newChar.deleteMe();
Disconnection.of(client, newChar).storeMe().deleteMe();
final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1);
client.setCharSelection(cl.getCharInfo());

View File

@ -47,7 +47,7 @@ public final class CharacterRestore implements IClientIncomingPacket
return;
}
client.markRestoredChar(_charSlot);
client.restore(_charSlot);
final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1, 0);
client.sendPacket(cl);
client.setCharSelection(cl.getCharInfo());

View File

@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.CharSelected;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
@ -146,7 +147,7 @@ public class CharacterSelect implements IClientIncomingPacket
}
// load up character from disk
final L2PcInstance cha = client.loadCharFromDisk(_charSlot);
final L2PcInstance cha = client.load(_charSlot);
if (cha == null)
{
return; // handled in L2GameClient
@ -161,7 +162,7 @@ public class CharacterSelect implements IClientIncomingPacket
final TerminateReturn terminate = EventDispatcher.getInstance().notifyEvent(new OnPlayerSelect(cha, cha.getObjectId(), cha.getName(), client), Containers.Players(), TerminateReturn.class);
if ((terminate != null) && terminate.terminate())
{
cha.deleteMe();
Disconnection.of(cha).defaultSequence(false);
return;
}

View File

@ -57,6 +57,7 @@ import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
@ -137,7 +138,7 @@ public class EnterWorld implements IClientIncomingPacket
if (activeChar == null)
{
_log.warning("EnterWorld failed! activeChar returned 'null'.");
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
@ -648,7 +649,7 @@ public class EnterWorld implements IClientIncomingPacket
{
if (client.getHardwareInfo() == null)
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
}, 5000);

View File

@ -18,14 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.L2Event;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jmobius.gameserver.util.OfflineTradeUtil;
/**
* This class ...
@ -33,7 +31,7 @@ import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
*/
public final class Logout implements IClientIncomingPacket
{
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
@Override
public boolean read(L2GameClient client, PacketReader packet)
@ -47,42 +45,21 @@ public final class Logout implements IClientIncomingPacket
final L2PcInstance player = client.getActiveChar();
if (player == null)
{
client.closeNow();
return;
}
if (player.hasItemRequest())
if (!player.canLogout())
{
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
if (player.isLocked())
LOG_ACCOUNTING.info("Logged out, " + client);
if (!OfflineTradeUtil.enteredOfflineMode(player))
{
_log.warning("Player " + player.getName() + " tried to logout during class change.");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
Disconnection.of(client, player).defaultSequence(false);
}
// Don't allow leaving if player is fighting
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player))
{
if (!player.isGM() || (player.isGM() && !Config.GM_RESTART_FIGHTING))
{
player.sendPacket(SystemMessageId.YOU_CANNOT_EXIT_THE_GAME_WHILE_IN_COMBAT);
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
if (L2Event.isParticipant(player))
{
player.sendMessage("A superior power doesn't allow you to leave the event.");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
_logAccounting.info("Disconnected, " + client);
player.logout();
}
}

View File

@ -47,7 +47,7 @@ public final class ProtocolVersion implements IClientIncomingPacket
if (_version == -2)
{
// this is just a ping attempt from the new C2 client
client.close(null);
client.closeNow();
}
else if (!Config.PROTOCOL_LIST.contains(_version))
{

View File

@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnNpcMenuSelect;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerBypass;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
@ -86,7 +87,7 @@ public final class RequestBypassToServer implements IClientIncomingPacket
if (_command.isEmpty())
{
_log.warning("Player " + activeChar.getName() + " sent empty bypass!");
activeChar.logout();
Disconnection.of(client, activeChar).defaultSequence(false);
return;
}

View File

@ -21,6 +21,7 @@ import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.ClientHardwareInfoHolder;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -93,7 +94,7 @@ public final class RequestHardWareInfo implements IClientIncomingPacket
}
if (count >= Config.MAX_PLAYERS_PER_HWID)
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
}

View File

@ -18,16 +18,15 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.instancemanager.AntiFeedManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.CharSelectionInfo;
import com.l2jmobius.gameserver.network.serverpackets.RestartResponse;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jmobius.gameserver.util.OfflineTradeUtil;
/**
* This class ...
@ -35,7 +34,7 @@ import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
*/
public final class RequestRestart implements IClientIncomingPacket
{
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
@Override
public boolean read(L2GameClient client, PacketReader packet)
@ -52,43 +51,20 @@ public final class RequestRestart implements IClientIncomingPacket
return;
}
if (player.hasItemRequest())
if (!player.canLogout())
{
client.sendPacket(RestartResponse.FALSE);
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
if (player.isLocked())
LOG_ACCOUNTING.info("Logged out, " + client);
if (!OfflineTradeUtil.enteredOfflineMode(player))
{
_log.warning("Player " + player.getName() + " tried to restart during class change.");
client.sendPacket(RestartResponse.FALSE);
return;
Disconnection.of(client, player).storeMe().deleteMe();
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player) && !(player.isGM() && Config.GM_RESTART_FIGHTING))
{
player.sendPacket(SystemMessageId.YOU_CANNOT_RESTART_WHILE_IN_COMBAT);
client.sendPacket(RestartResponse.FALSE);
return;
}
if (player.isBlockedFromExit())
{
client.sendPacket(RestartResponse.FALSE);
return;
}
_logAccounting.info("Logged out, " + client);
player.deleteMe();
client.setActiveChar(null);
// detach the client from the char so that the connection isnt closed in the deleteMe
player.setClient(null);
AntiFeedManager.getInstance().onDisconnect(client);
// return the client to the authed status
client.setConnectionState(ConnectionState.AUTHENTICATED);

View File

@ -31,6 +31,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerChat;
import com.l2jmobius.gameserver.model.events.returns.ChatFilterReturn;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
@ -110,7 +111,7 @@ public final class Say2 implements IClientIncomingPacket
{
_log.warning("Say2: Invalid type: " + _type + " Player : " + activeChar.getName() + " text: " + _text);
activeChar.sendPacket(ActionFailed.STATIC_PACKET);
activeChar.logout();
Disconnection.of(activeChar).defaultSequence(false);
return;
}
@ -118,7 +119,7 @@ public final class Say2 implements IClientIncomingPacket
{
_log.warning(activeChar.getName() + ": sending empty text. Possible packet hack!");
activeChar.sendPacket(ActionFailed.STATIC_PACKET);
activeChar.logout();
Disconnection.of(activeChar).defaultSequence(false);
return;
}

View File

@ -29,6 +29,7 @@ import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.data.xml.impl.SecondaryAuthData;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.Ex2ndPasswordAck;
import com.l2jmobius.gameserver.network.serverpackets.Ex2ndPasswordCheck;
@ -104,7 +105,7 @@ public class SecondaryPasswordAuth
if (passwordExist())
{
_log.warning("[SecondaryPasswordAuth]" + _activeClient.getAccountName() + " forced savePassword");
_activeClient.closeNow();
Disconnection.of(_activeClient).defaultSequence(false);
return false;
}
@ -157,7 +158,7 @@ public class SecondaryPasswordAuth
if (!passwordExist())
{
_log.warning("[SecondaryPasswordAuth]" + _activeClient.getAccountName() + " forced changePassword");
_activeClient.closeNow();
Disconnection.of(_activeClient).defaultSequence(false);
return false;
}

View File

@ -38,6 +38,8 @@ public class AttackStanceTaskManager
protected static final Map<L2Character, Long> _attackStanceTasks = new ConcurrentHashMap<>();
public static final long COMBAT_TIME = 15_000;
/**
* Instantiates a new attack stance task manager.
*/
@ -106,7 +108,7 @@ public class AttackStanceTaskManager
while (iter.hasNext())
{
e = iter.next();
if ((current - e.getValue()) > 15000)
if ((current - e.getValue()) > COMBAT_TIME)
{
actor = e.getKey();
if (actor != null)

View File

@ -28,6 +28,7 @@ import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -142,14 +143,7 @@ public final class FloodProtectorAction
*/
private void kickPlayer()
{
if (_client.getActiveChar() != null)
{
_client.getActiveChar().logout(false);
}
else
{
_client.closeNow();
}
Disconnection.of(_client).defaultSequence(false);
if (_log.getLevel() == Level.WARNING)
{

View File

@ -0,0 +1,151 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.util;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
* @author lord_rex
*/
public final class OfflineTradeUtil
{
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
private OfflineTradeUtil()
{
// utility class
}
/**
* Check whether player is able to enter offline mode.
* @param player the player to be check.
* @return {@code true} if the player is allowed to remain as off-line shop.
*/
private static boolean offlineMode(L2PcInstance player)
{
if ((player == null) || player.isInOlympiadMode() || player.isBlockedFromExit() || player.isJailed() || (player.getVehicle() != null))
{
return false;
}
boolean canSetShop = false;
switch (player.getPrivateStoreType())
{
case SELL:
case PACKAGE_SELL:
case BUY:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
case MANUFACTURE:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
default:
{
canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isInCraftMode();
break;
}
}
if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
{
canSetShop = false;
}
// Check whether client is null or player is already in offline mode.
final L2GameClient client = player.getClient();
if ((client == null) || client.isDetached())
{
return false;
}
return canSetShop;
}
/**
* Manages the disconnection process of offline traders.
* @param player
* @return {@code true} when player entered offline mode, otherwise {@code false}
*/
public static boolean enteredOfflineMode(L2PcInstance player)
{
if (!OfflineTradeUtil.offlineMode(player))
{
return false;
}
final L2GameClient client = player.getClient();
client.setDetached(true);
player.leaveParty();
OlympiadManager.getInstance().unRegisterNoble(player);
// If the L2PcInstance has Pet, unsummon it
L2Summon pet = player.getPet();
if (pet != null)
{
pet.setRestoreSummon(true);
pet.unSummon(player);
pet = player.getPet();
// Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
if (pet != null)
{
pet.broadcastNpcInfo(0);
}
}
player.getServitors().values().forEach(s ->
{
s.setRestoreSummon(true);
s.unSummon(player);
});
if (Config.OFFLINE_SET_NAME_COLOR)
{
player.getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
player.broadcastUserInfo();
}
if (player.getOfflineStartTime() == 0)
{
player.setOfflineStartTime(System.currentTimeMillis());
}
// Store trade on exit, if realtime saving is enabled.
if (Config.STORE_OFFLINE_TRADE_IN_REALTIME)
{
OfflineTradersTable.onTransaction(player, false, true);
}
Disconnection.of(player).storeMe().close(false);
LOG_ACCOUNTING.info("Entering offline mode, " + client);
return true;
}
}

View File

@ -26,6 +26,7 @@ import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2AccessLevel;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -129,7 +130,7 @@ public final class AdminChangeAccessLevel implements IAdminCommandHandler
{
player.setAccessLevel(lvl, false, true);
player.sendMessage("Your character has been banned. Bye.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -19,6 +19,7 @@ package handlers.admincommandhandlers;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
/**
* This class handles following admin commands: - character_disconnect = disconnects target player
@ -68,7 +69,7 @@ public class AdminDisconnect implements IAdminCommandHandler
{
activeChar.sendMessage("Character " + player.getName() + " disconnected from server.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -18,10 +18,10 @@ package handlers.admincommandhandlers;
import java.util.StringTokenizer;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
public class AdminKick implements IAdminCommandHandler
{
@ -44,11 +44,7 @@ public class AdminKick implements IAdminCommandHandler
final L2PcInstance plyr = L2World.getInstance().getPlayer(player);
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
activeChar.sendMessage("You kicked " + plyr.getName() + " from the game.");
}
}
@ -61,7 +57,7 @@ public class AdminKick implements IAdminCommandHandler
if (!player.isGM())
{
counter++;
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
activeChar.sendMessage("Kicked " + counter + " players.");

View File

@ -21,7 +21,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.handler.AdminCommandHandler;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
@ -31,6 +30,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -170,11 +170,7 @@ public class AdminMenu implements IAdminCommandHandler
String text;
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
text = "You kicked " + plyr.getName() + " from the game.";
}
else

View File

@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -58,7 +59,7 @@ public class BanHandler implements IPunishmentHandler
}
else
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
}
}
break;
@ -90,7 +91,7 @@ public class BanHandler implements IPunishmentHandler
*/
private static void applyToPlayer(L2PcInstance player)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
}
@Override

View File

@ -18,6 +18,7 @@ package handlers.telnethandlers.player;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.telnet.ITelnetCommand;
import io.netty.channel.ChannelHandlerContext;
@ -49,7 +50,7 @@ public class Kick implements ITelnetCommand
final L2PcInstance player = L2World.getInstance().getPlayer(args[0]);
if (player != null)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
return "Player has been successfully kicked.";
}
return "Couldn't find player with such name.";

View File

@ -562,15 +562,8 @@ public class LoginServerThread extends Thread
final L2GameClient client = _accountsInGameServer.get(account);
if (client != null)
{
if (client.isDetached())
{
client.getActiveChar().logout();
}
else
{
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
ACCOUNTING_LOGGER.info(getClass().getSimpleName() + ": Kicked by login, " + client);
ACCOUNTING_LOGGER.info("Kicked by login, " + client);
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
}

View File

@ -38,11 +38,10 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Hero;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.network.ClientNetworkManager;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.EventLoopGroupManager;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.telnet.TelnetServer;
import com.l2jmobius.gameserver.util.Broadcast;
@ -610,27 +609,7 @@ public class Shutdown extends Thread
{
for (L2PcInstance player : L2World.getInstance().getPlayers())
{
// Logout Character
try
{
final L2GameClient client = player.getClient();
if ((client != null) && !client.isDetached())
{
client.close(ServerClose.STATIC_PACKET);
client.setActiveChar(null);
player.setClient(null);
}
else if ((client == null) || client.isDetached())
// player is probably a bot - force logout
{
player.logout();
}
player.deleteMe();
}
catch (Throwable t)
{
LOGGER.log(Level.WARNING, "Failed logour char " + player, t);
}
Disconnection.of(player).defaultSequence(true);
}
}

View File

@ -33,6 +33,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.TradeItem;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SellBuffHolder;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
public class OfflineTradersTable
@ -49,6 +50,10 @@ public class OfflineTradersTable
private static final String LOAD_OFFLINE_STATUS = "SELECT * FROM character_offline_trade";
private static final String LOAD_OFFLINE_ITEMS = "SELECT * FROM character_offline_trade_items WHERE `charId`=?";
protected OfflineTradersTable()
{
}
public void storeOffliners()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
@ -300,7 +305,7 @@ public class OfflineTradersTable
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error loading trader: " + player, e);
if (player != null)
{
player.deleteMe();
Disconnection.of(player).defaultSequence(false);
}
}
}
@ -470,11 +475,11 @@ public class OfflineTradersTable
*/
public static OfflineTradersTable getInstance()
{
return SingletonHolder._instance;
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final OfflineTradersTable _instance = new OfflineTradersTable();
protected static final OfflineTradersTable INSTANCE = new OfflineTradersTable();
}
}

View File

@ -72,6 +72,12 @@ public final class AntiFeedManager
return false;
}
// Players in offline mode should't be valid targets.
if (targetPlayer.getClient().isDetached())
{
return false;
}
if ((Config.ANTIFEED_INTERVAL > 0) && _lastDeathTimes.containsKey(targetPlayer.getObjectId()))
{
if ((System.currentTimeMillis() - _lastDeathTimes.get(targetPlayer.getObjectId())) < Config.ANTIFEED_INTERVAL)
@ -211,7 +217,7 @@ public final class AntiFeedManager
*/
public final void onDisconnect(L2GameClient client)
{
if ((client == null) || client.isDetached())
if ((client == null) || (client.getConnectionAddress() == null))
{
return;
}

View File

@ -39,6 +39,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnNpcCreatureSee;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
import com.l2jmobius.gameserver.util.Util;
@ -143,8 +144,8 @@ public final class L2World
final L2PcInstance existingPlayer = _allPlayers.putIfAbsent(object.getObjectId(), newPlayer);
if (existingPlayer != null)
{
existingPlayer.logout();
newPlayer.logout();
Disconnection.of(existingPlayer).defaultSequence(false);
Disconnection.of(newPlayer).defaultSequence(false);
LOGGER.warning(getClass().getSimpleName() + ": Duplicate character!? Disconnected both characters (" + newPlayer.getName() + ")");
}
else if (Config.FACTION_SYSTEM_ENABLED)

View File

@ -131,6 +131,7 @@ import com.l2jmobius.gameserver.model.stats.MoveType;
import com.l2jmobius.gameserver.model.stats.Stats;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.model.zone.ZoneRegion;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.Attack;
@ -3287,7 +3288,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
if (isPlayer())
{
getActingPlayer().logout();
Disconnection.of(getActingPlayer()).defaultSequence(false);
}
else if (isSummon())
{

View File

@ -259,6 +259,7 @@ import com.l2jmobius.gameserver.model.variables.AccountVariables;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AbstractHtmlPacket;
@ -294,7 +295,6 @@ import com.l2jmobius.gameserver.network.serverpackets.HennaInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import com.l2jmobius.gameserver.network.serverpackets.ItemList;
import com.l2jmobius.gameserver.network.serverpackets.LeaveWorld;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.MyTargetSelected;
import com.l2jmobius.gameserver.network.serverpackets.NicknameChanged;
@ -313,7 +313,6 @@ import com.l2jmobius.gameserver.network.serverpackets.RecipeShopMsg;
import com.l2jmobius.gameserver.network.serverpackets.RecipeShopSellList;
import com.l2jmobius.gameserver.network.serverpackets.RelationChanged;
import com.l2jmobius.gameserver.network.serverpackets.Ride;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SetupGauge;
import com.l2jmobius.gameserver.network.serverpackets.ShortCutInit;
import com.l2jmobius.gameserver.network.serverpackets.SkillCoolTime;
@ -805,6 +804,8 @@ public final class L2PcInstance extends L2Playable
private final Fishing _fishing = new Fishing(this);
private Future<?> _autoSaveTask = null;
public void setPvpFlagLasts(long time)
{
_pvpFlagLasts = time;
@ -1259,38 +1260,6 @@ public final class L2PcInstance extends L2Playable
_inCraftMode = b;
}
/**
* Manage Logout Task:
* <ul>
* <li>Remove player from world</li>
* <li>Save player data into DB</li>
* </ul>
*/
public void logout()
{
logout(true);
}
/**
* Manage Logout Task:
* <ul>
* <li>Remove player from world</li>
* <li>Save player data into DB</li>
* </ul>
* @param closeClient
*/
public void logout(boolean closeClient)
{
try
{
closeNetConnection(closeClient);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception on logout(): " + e.getMessage(), e);
}
}
/**
* @return a table containing all Common L2RecipeList of the L2PcInstance.
*/
@ -3981,33 +3950,6 @@ public final class L2PcInstance extends L2Playable
return ip;
}
/**
* Close the active connection with the client.
* @param closeClient
*/
private void closeNetConnection(boolean closeClient)
{
final L2GameClient client = _client;
if (client != null)
{
if (client.isDetached())
{
client.cleanMe(true);
}
else if (client.getChannel().isActive())
{
if (closeClient)
{
client.close(LeaveWorld.STATIC_PACKET);
}
else
{
client.close(ServerClose.STATIC_PACKET);
}
}
}
}
public Location getCurrentSkillWorldPosition()
{
return _currentSkillWorldPosition;
@ -6831,6 +6773,8 @@ public final class L2PcInstance extends L2Playable
player.startOnlineTimeUpdateTask();
player.setOnlineStatus(true, false);
player.startAutoSaveTask();
}
catch (Exception e)
{
@ -8109,6 +8053,61 @@ public final class L2PcInstance extends L2Playable
return isInCategory(CategoryType.SIXTH_CLASS_GROUP);
}
private void startAutoSaveTask()
{
if ((Config.CHAR_DATA_STORE_INTERVAL > 0) && (_autoSaveTask == null))
{
_autoSaveTask = ThreadPoolManager.scheduleAtFixedRate(this::autoSave, 300_000L, TimeUnit.MINUTES.toMillis(Config.CHAR_DATA_STORE_INTERVAL));
}
}
private void stopAutoSaveTask()
{
if (_autoSaveTask != null)
{
_autoSaveTask.cancel(false);
_autoSaveTask = null;
}
}
protected void autoSave()
{
storeMe();
storeRecommendations();
if (Config.UPDATE_ITEMS_ON_CHAR_STORE)
{
getInventory().updateDatabase();
getWarehouse().updateDatabase();
}
}
public boolean canLogout()
{
if (hasItemRequest())
{
return false;
}
if (isLocked())
{
_log.warning("Player " + getName() + " tried to restart/logout during class change.");
return false;
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(this) && !(isGM() && Config.GM_RESTART_FIGHTING))
{
return false;
}
if (isBlockedFromExit())
{
return false;
}
return true;
}
/**
* Return True if the L2PcInstance is autoAttackable.<br>
* <B><U>Actions</U>:</B>
@ -10698,28 +10697,19 @@ public final class L2PcInstance extends L2Playable
* <li>If the L2PcInstance is in observer mode, set its position to its position before entering in observer mode</li>
* <li>Set the online Flag to True or False and update the characters table of the database with online status and lastAccess</li>
* <li>Stop the HP/MP/CP Regeneration task</li>
* <li>Cancel Crafting, Attak or Cast</li>
* <li>Cancel Crafting, Attack or Cast</li>
* <li>Remove the L2PcInstance from the world</li>
* <li>Stop Party and Unsummon Pet</li>
* <li>Update database with items in its inventory and remove them from the world</li>
* <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI</li>
* <li>Close the connection with the client</li>
* </ul>
* <br>
* Remember this method is not to be used to half-ass disconnect players! This method is dedicated only to erase the player from the world.<br>
* If you intend to disconnect a player please use {@link Disconnection}
*/
@Override
public boolean deleteMe()
{
cleanup();
storeMe();
// Stop all passives and augment options without broadcasting changes.
getEffectList().stopAllPassives(false, false);
getEffectList().stopAllOptions(false, false);
return super.deleteMe();
}
private synchronized void cleanup()
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerLogout(this), this);
@ -11100,6 +11090,15 @@ public final class L2PcInstance extends L2Playable
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerMentorStatus(this, false), this);
}
// we store all data from players who are disconnected while in an event in order to restore it in the next login
if (L2Event.isParticipant(this))
{
L2Event.savePlayerEventStatus(this);
}
// Anti Feed
AntiFeedManager.getInstance().onDisconnect(getClient());
try
{
notifyFriends(L2FriendStatus.MODE_OFFLINE);
@ -11109,6 +11108,14 @@ public final class L2PcInstance extends L2Playable
{
_log.log(Level.WARNING, "Exception on deleteMe() notifyFriends: " + e.getMessage(), e);
}
// Stop all passives and augment options
getEffectList().stopAllPassives(false, false);
getEffectList().stopAllOptions(false, false);
stopAutoSaveTask();
return super.deleteMe();
}
public int getInventoryLimit()

View File

@ -26,6 +26,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.Disconnection;
/**
* Task that handles illegal player actions.
@ -86,7 +87,7 @@ public final class IllegalPlayerActionTask implements Runnable
}
case KICK:
{
_actor.logout(false);
Disconnection.of(_actor).defaultSequence(false);
break;
}
case KICKBAN:

View File

@ -0,0 +1,189 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.network;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
/**
* @author NB4L1
*/
public final class Disconnection
{
private static final Logger LOGGER = Logger.getLogger(Disconnection.class.getName());
public static L2GameClient getClient(L2GameClient client, L2PcInstance activeChar)
{
if (client != null)
{
return client;
}
if (activeChar != null)
{
return activeChar.getClient();
}
return null;
}
public static L2PcInstance getActiveChar(L2GameClient client, L2PcInstance activeChar)
{
if (activeChar != null)
{
return activeChar;
}
if (client != null)
{
return client.getActiveChar();
}
return null;
}
private final L2GameClient _client;
private final L2PcInstance _activeChar;
private Disconnection(L2GameClient client)
{
this(client, null);
}
public static Disconnection of(L2GameClient client)
{
return new Disconnection(client);
}
private Disconnection(L2PcInstance activeChar)
{
this(null, activeChar);
}
public static Disconnection of(L2PcInstance activeChar)
{
return new Disconnection(activeChar);
}
private Disconnection(L2GameClient client, L2PcInstance activeChar)
{
_client = getClient(client, activeChar);
_activeChar = getActiveChar(client, activeChar);
if (_client != null)
{
_client.setActiveChar(null);
}
if (_activeChar != null)
{
_activeChar.setClient(null);
}
}
public static Disconnection of(L2GameClient client, L2PcInstance activeChar)
{
return new Disconnection(client, activeChar);
}
public Disconnection storeMe()
{
try
{
if (_activeChar != null)
{
_activeChar.storeMe();
}
}
catch (RuntimeException e)
{
LOGGER.warning(e.getMessage());
}
return this;
}
public Disconnection deleteMe()
{
try
{
if (_activeChar != null)
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerLogout(_activeChar), _activeChar);
_activeChar.deleteMe();
}
}
catch (RuntimeException e)
{
LOGGER.warning(e.getMessage());
}
return this;
}
public Disconnection close(boolean toLoginScreen)
{
if (_client != null)
{
_client.close(toLoginScreen);
}
return this;
}
public Disconnection close(IClientOutgoingPacket packet)
{
if (_client != null)
{
_client.close(packet);
}
return this;
}
public void defaultSequence(boolean toLoginScreen)
{
defaultSequence();
close(toLoginScreen);
}
public void defaultSequence(IClientOutgoingPacket packet)
{
defaultSequence();
close(packet);
}
private void defaultSequence()
{
storeMe();
deleteMe();
}
public void onDisconnection()
{
if (_activeChar != null)
{
ThreadPoolManager.schedule(() -> defaultSequence(), _activeChar.canLogout() ? 0 : AttackStanceTaskManager.COMBAT_TIME);
}
}
}

View File

@ -21,9 +21,6 @@ import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -33,36 +30,28 @@ import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.network.ChannelInboundHandler;
import com.l2jmobius.commons.network.ICrypt;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.LoginServerThread.SessionKey;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.data.xml.impl.SecondaryAuthData;
import com.l2jmobius.gameserver.enums.CharacterDeleteFailType;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.AntiFeedManager;
import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
import com.l2jmobius.gameserver.model.CharSelectInfoPackage;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.L2Event;
import com.l2jmobius.gameserver.model.holders.ClientHardwareInfoHolder;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.LeaveWorld;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.security.SecondaryPasswordAuth;
import com.l2jmobius.gameserver.util.FloodProtectors;
import com.l2jmobius.gameserver.util.Util;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
@ -74,7 +63,7 @@ import io.netty.channel.ChannelHandlerContext;
public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
protected static final Logger LOGGER = Logger.getLogger(L2GameClient.class.getName());
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
private final int _objectId;
@ -88,20 +77,15 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
private SecondaryPasswordAuth _secondaryAuth;
private ClientHardwareInfoHolder _hardwareInfo;
private boolean _isAuthedGG;
private final long _connectionStartTime = System.currentTimeMillis();
private CharSelectInfoPackage[] _charSlotMapping = null;
// flood protectors
private final FloodProtectors _floodProtectors = new FloodProtectors(this);
// Task
protected final ScheduledFuture<?> _autoSaveInDB;
protected ScheduledFuture<?> _cleanupTask = null;
// Crypt
private final Crypt _crypt;
private boolean _isDetached = false;
private volatile boolean _isDetached = false;
private boolean _protocol;
@ -111,14 +95,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
_objectId = IdFactory.getInstance().getNextId();
_crypt = new Crypt(this);
if (Config.CHAR_DATA_STORE_INTERVAL > 0)
{
_autoSaveInDB = ThreadPoolManager.scheduleAtFixedRate(new AutoSaveTask(), 300000L, Config.CHAR_DATA_STORE_INTERVAL);
}
else
{
_autoSaveInDB = null;
}
}
public int getObjectId()
@ -135,23 +111,18 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
final InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
_addr = address.getAddress();
_channel = ctx.channel();
LOGGER.finer("Client Connected: " + ctx.channel());
LOG_ACCOUNTING.finer("Client Connected: " + ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx)
{
LOGGER.finer("Client Disconnected: " + ctx.channel());
LOG_ACCOUNTING.finer("Client Disconnected: " + ctx.channel());
// no long running tasks here, do it async
try
{
ThreadPoolManager.execute(new DisconnectTask());
}
catch (RejectedExecutionException e)
{
// server is closing
}
LoginServerThread.getInstance().sendLogout(getAccountName());
IdFactory.getInstance().releaseId(getObjectId());
Disconnection.of(this).onDisconnection();
}
@Override
@ -172,6 +143,25 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
}
public void closeNow()
{
if (_channel != null)
{
_channel.close();
}
}
public void close(IClientOutgoingPacket packet)
{
sendPacket(packet);
closeNow();
}
public void close(boolean toLoginScreen)
{
close(toLoginScreen ? ServerClose.STATIC_PACKET : LeaveWorld.STATIC_PACKET);
}
public Channel getChannel()
{
return _channel;
@ -193,19 +183,14 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _addr;
}
public long getConnectionStartTime()
{
return _connectionStartTime;
}
public L2PcInstance getActiveChar()
{
return _activeChar;
}
public void setActiveChar(L2PcInstance pActiveChar)
public void setActiveChar(L2PcInstance activeChar)
{
_activeChar = pActiveChar;
_activeChar = activeChar;
}
public ReentrantLock getActiveCharLock()
@ -228,9 +213,9 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _isAuthedGG;
}
public void setAccountName(String pAccountName)
public void setAccountName(String activeChar)
{
_accountName = pAccountName;
_accountName = activeChar;
if (SecondaryAuthData.getInstance().isEnabled())
{
@ -287,16 +272,16 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
/**
* Method to handle character deletion
* @param charslot
* @param characterSlot
* @return a byte:
* <li>-1: Error: No char was found for such charslot, caught exception, etc...
* <li>0: character is not member of any clan, proceed with deletion
* <li>1: character is member of a clan, but not clan leader
* <li>2: character is clan leader
*/
public CharacterDeleteFailType markToDeleteChar(int charslot)
public CharacterDeleteFailType markToDeleteChar(int characterSlot)
{
final int objectId = getObjectIdForSlot(charslot);
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return CharacterDeleteFailType.UNKNOWN;
@ -354,38 +339,14 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
_logAccounting.info("Delete, " + objectId + ", " + this);
LOG_ACCOUNTING.info("Delete, " + objectId + ", " + this);
return CharacterDeleteFailType.NONE;
}
/**
* Save the L2PcInstance to the database.
*/
public void saveCharToDisk()
public void restore(int characterSlot)
{
try
{
if (getActiveChar() != null)
{
getActiveChar().storeMe();
getActiveChar().storeRecommendations();
if (Config.UPDATE_ITEMS_ON_CHAR_STORE)
{
getActiveChar().getInventory().updateDatabase();
getActiveChar().getWarehouse().updateDatabase();
}
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Error saving character..", e);
}
}
public void markRestoredChar(int charslot)
{
final int objid = getObjectIdForSlot(charslot);
if (objid < 0)
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return;
}
@ -393,7 +354,7 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE characters SET deletetime=0 WHERE charId=?"))
{
statement.setInt(1, objid);
statement.setInt(1, objectId);
statement.execute();
}
catch (Exception e)
@ -401,7 +362,7 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
LOGGER.log(Level.SEVERE, "Error restoring character.", e);
}
_logAccounting.info("Restore, " + objid + ", " + this);
LOG_ACCOUNTING.info("Restore, " + objectId + ", " + this);
}
public static void deleteCharByObjId(int objid)
@ -555,38 +516,30 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
public L2PcInstance loadCharFromDisk(int charslot)
public L2PcInstance load(int characterSlot)
{
final int objId = getObjectIdForSlot(charslot);
if (objId < 0)
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return null;
}
L2PcInstance character = L2World.getInstance().getPlayer(objId);
if (character != null)
L2PcInstance player = L2World.getInstance().getPlayer(objectId);
if (player != null)
{
// exploit prevention, should not happens in normal way
LOGGER.severe("Attempt of double login: " + character.getName() + "(" + objId + ") " + getAccountName());
if (character.getClient() != null)
{
character.getClient().closeNow();
}
else
{
character.deleteMe();
}
LOGGER.severe("Attempt of double login: " + player.getName() + "(" + objectId + ") " + getAccountName());
Disconnection.of(player).defaultSequence(false);
return null;
}
character = L2PcInstance.load(objId);
if (character == null)
player = L2PcInstance.load(objectId);
if (player == null)
{
LOGGER.severe("could not restore in slot: " + charslot);
LOGGER.severe("Could not restore in slot: " + characterSlot);
}
// setCharacter(character);
return character;
return player;
}
/**
@ -611,47 +564,21 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _secondaryAuth;
}
public void close(IOutgoingPacket packet)
{
if (packet != null)
{
_channel.writeAndFlush(packet);
}
_channel.close();
}
/**
* @param charslot
* @param characterSlot
* @return
*/
private int getObjectIdForSlot(int charslot)
private int getObjectIdForSlot(int characterSlot)
{
final CharSelectInfoPackage info = getCharSelection(charslot);
final CharSelectInfoPackage info = getCharSelection(characterSlot);
if (info == null)
{
LOGGER.warning(toString() + " tried to delete Character in slot " + charslot + " but no characters exits at that slot.");
LOGGER.warning(toString() + " tried to delete Character in slot " + characterSlot + " but no characters exits at that slot.");
return -1;
}
return info.getObjectId();
}
/**
* Close client connection with {@link ServerClose} packet
*/
public void closeNow()
{
_isDetached = true; // prevents more packets execution
close(ServerClose.STATIC_PACKET);
synchronized (this)
{
if (_cleanupTask != null)
{
cancelCleanup();
}
_cleanupTask = ThreadPoolManager.schedule(new CleanupTask(), 0); // instant
}
}
/**
* Produces the best possible string representation of this client.
*/
@ -688,209 +615,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
protected class DisconnectTask implements Runnable
{
@Override
public void run()
{
boolean fast = true;
try
{
if ((getActiveChar() != null) && !isDetached())
{
setDetached(true);
if (offlineMode(getActiveChar()))
{
getActiveChar().leaveParty();
OlympiadManager.getInstance().unRegisterNoble(getActiveChar());
// If the L2PcInstance has Pet, unsummon it
L2Summon pet = getActiveChar().getPet();
if (pet != null)
{
pet.setRestoreSummon(true);
pet.unSummon(getActiveChar());
pet = getActiveChar().getPet();
// Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
if (pet != null)
{
pet.broadcastNpcInfo(0);
}
}
getActiveChar().getServitors().values().forEach(s ->
{
s.setRestoreSummon(true);
s.unSummon(getActiveChar());
});
if (Config.OFFLINE_SET_NAME_COLOR)
{
getActiveChar().getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
getActiveChar().broadcastUserInfo();
}
if (getActiveChar().getOfflineStartTime() == 0)
{
getActiveChar().setOfflineStartTime(System.currentTimeMillis());
}
// Store trade on exit, if realtime saving is enabled.
if (Config.STORE_OFFLINE_TRADE_IN_REALTIME)
{
OfflineTradersTable.onTransaction(getActiveChar(), false, true);
}
_logAccounting.info("Entering offline mode, " + L2GameClient.this);
return;
}
fast = !getActiveChar().isInCombat() && !getActiveChar().isLocked();
}
cleanMe(fast);
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error while disconnecting client.", e1);
}
IdFactory.getInstance().releaseId(getObjectId());
}
}
/**
* @param player the player to be check.
* @return {@code true} if the player is allowed to remain as off-line shop.
*/
protected boolean offlineMode(L2PcInstance player)
{
if (player.isInOlympiadMode() || player.isBlockedFromExit() || player.isJailed() || (player.getVehicle() != null))
{
return false;
}
boolean canSetShop = false;
switch (player.getPrivateStoreType())
{
case SELL:
case PACKAGE_SELL:
case BUY:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
case MANUFACTURE:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
default:
{
canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isInCraftMode();
break;
}
}
if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
{
canSetShop = false;
}
return canSetShop;
}
public void cleanMe(boolean fast)
{
try
{
synchronized (this)
{
if (_cleanupTask == null)
{
_cleanupTask = ThreadPoolManager.schedule(new CleanupTask(), fast ? 5 : 15000L);
}
}
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error during cleanup.", e1);
}
}
protected class CleanupTask implements Runnable
{
@Override
public void run()
{
try
{
// we are going to manually save the char bellow thus we can force the cancel
if (_autoSaveInDB != null)
{
_autoSaveInDB.cancel(true);
// ThreadPoolManager.getInstance().removeGeneral((Runnable) _autoSaveInDB);
}
if (getActiveChar() != null) // this should only happen on connection loss
{
if (getActiveChar().isLocked())
{
LOGGER.warning("Player " + getActiveChar().getName() + " still performing subclass actions during disconnect.");
}
// we store all data from players who are disconnected while in an event in order to restore it in the next login
if (L2Event.isParticipant(getActiveChar()))
{
L2Event.savePlayerEventStatus(getActiveChar());
}
if (getActiveChar().isOnline())
{
getActiveChar().deleteMe();
AntiFeedManager.getInstance().onDisconnect(L2GameClient.this);
}
// prevent closing again
getActiveChar().setClient(null);
}
setActiveChar(null);
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error while cleanup client.", e1);
}
finally
{
LoginServerThread.getInstance().sendLogout(getAccountName());
}
}
}
protected class AutoSaveTask implements Runnable
{
@Override
public void run()
{
try
{
final L2PcInstance player = getActiveChar();
if ((player != null) && player.isOnline()) // safety precaution
{
saveCharToDisk();
final L2Summon pet = player.getPet();
if (pet != null)
{
pet.storeMe();
}
player.getServitors().values().forEach(L2Summon::storeMe);
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Error on AutoSaveTask.", e);
}
}
}
public boolean isProtocolOk()
{
return _protocol;
@ -901,20 +625,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
_protocol = b;
}
public boolean handleCheat(String punishment)
{
if (_activeChar != null)
{
Util.handleIllegalPlayerAction(_activeChar, toString() + ": " + punishment, Config.DEFAULT_PUNISH);
return true;
}
final Logger logAudit = Logger.getLogger("audit");
logAudit.info("AUDIT: Client " + toString() + " kicked for reason: " + punishment);
closeNow();
return false;
}
public void setClientTracert(int[][] tracert)
{
trace = tracert;
@ -925,17 +635,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return trace;
}
private boolean cancelCleanup()
{
final Future<?> task = _cleanupTask;
if (task != null)
{
_cleanupTask = null;
return task.cancel(true);
}
return false;
}
public void sendActionFailed()
{
sendPacket(ActionFailed.STATIC_PACKET);

View File

@ -54,7 +54,7 @@ public final class AuthLogin implements IClientIncomingPacket
{
if (_loginName.isEmpty() || !client.isProtocolOk())
{
client.close(null);
client.closeNow();
return;
}

View File

@ -41,6 +41,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerCreate;
import com.l2jmobius.gameserver.model.items.PcItemTemplate;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.CharCreateFail;
import com.l2jmobius.gameserver.network.serverpackets.CharCreateOk;
@ -333,7 +334,7 @@ public final class CharacterCreate implements IClientIncomingPacket
{
newChar.getVariables().set("intro_god_video", true);
}
newChar.deleteMe();
Disconnection.of(client, newChar).storeMe().deleteMe();
final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1);
client.setCharSelection(cl.getCharInfo());

View File

@ -47,7 +47,7 @@ public final class CharacterRestore implements IClientIncomingPacket
return;
}
client.markRestoredChar(_charSlot);
client.restore(_charSlot);
final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1, 0);
client.sendPacket(cl);
client.setCharSelection(cl.getCharInfo());

View File

@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.CharSelected;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
@ -146,7 +147,7 @@ public class CharacterSelect implements IClientIncomingPacket
}
// load up character from disk
final L2PcInstance cha = client.loadCharFromDisk(_charSlot);
final L2PcInstance cha = client.load(_charSlot);
if (cha == null)
{
return; // handled in L2GameClient
@ -161,7 +162,7 @@ public class CharacterSelect implements IClientIncomingPacket
final TerminateReturn terminate = EventDispatcher.getInstance().notifyEvent(new OnPlayerSelect(cha, cha.getObjectId(), cha.getName(), client), Containers.Players(), TerminateReturn.class);
if ((terminate != null) && terminate.terminate())
{
cha.deleteMe();
Disconnection.of(cha).defaultSequence(false);
return;
}

View File

@ -58,6 +58,7 @@ import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
@ -142,7 +143,7 @@ public class EnterWorld implements IClientIncomingPacket
if (activeChar == null)
{
_log.warning("EnterWorld failed! activeChar returned 'null'.");
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
@ -681,7 +682,7 @@ public class EnterWorld implements IClientIncomingPacket
{
if (client.getHardwareInfo() == null)
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
}, 5000);

View File

@ -18,14 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.L2Event;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jmobius.gameserver.util.OfflineTradeUtil;
/**
* This class ...
@ -33,7 +31,7 @@ import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
*/
public final class Logout implements IClientIncomingPacket
{
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
@Override
public boolean read(L2GameClient client, PacketReader packet)
@ -47,42 +45,21 @@ public final class Logout implements IClientIncomingPacket
final L2PcInstance player = client.getActiveChar();
if (player == null)
{
client.closeNow();
return;
}
if (player.hasItemRequest())
if (!player.canLogout())
{
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
if (player.isLocked())
LOG_ACCOUNTING.info("Logged out, " + client);
if (!OfflineTradeUtil.enteredOfflineMode(player))
{
_log.warning("Player " + player.getName() + " tried to logout during class change.");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
Disconnection.of(client, player).defaultSequence(false);
}
// Don't allow leaving if player is fighting
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player))
{
if (!player.isGM() || (player.isGM() && !Config.GM_RESTART_FIGHTING))
{
player.sendPacket(SystemMessageId.YOU_CANNOT_EXIT_THE_GAME_WHILE_IN_COMBAT);
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
if (L2Event.isParticipant(player))
{
player.sendMessage("A superior power doesn't allow you to leave the event.");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
_logAccounting.info("Disconnected, " + client);
player.logout();
}
}

View File

@ -47,7 +47,7 @@ public final class ProtocolVersion implements IClientIncomingPacket
if (_version == -2)
{
// this is just a ping attempt from the new C2 client
client.close(null);
client.closeNow();
}
else if (!Config.PROTOCOL_LIST.contains(_version))
{

View File

@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnNpcMenuSelect;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerBypass;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
@ -86,7 +87,7 @@ public final class RequestBypassToServer implements IClientIncomingPacket
if (_command.isEmpty())
{
_log.warning("Player " + activeChar.getName() + " sent empty bypass!");
activeChar.logout();
Disconnection.of(client, activeChar).defaultSequence(false);
return;
}

View File

@ -21,6 +21,7 @@ import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.ClientHardwareInfoHolder;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -93,7 +94,7 @@ public final class RequestHardWareInfo implements IClientIncomingPacket
}
if (count >= Config.MAX_PLAYERS_PER_HWID)
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
}

View File

@ -18,16 +18,15 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.instancemanager.AntiFeedManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.CharSelectionInfo;
import com.l2jmobius.gameserver.network.serverpackets.RestartResponse;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jmobius.gameserver.util.OfflineTradeUtil;
/**
* This class ...
@ -35,7 +34,7 @@ import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
*/
public final class RequestRestart implements IClientIncomingPacket
{
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
@Override
public boolean read(L2GameClient client, PacketReader packet)
@ -52,43 +51,20 @@ public final class RequestRestart implements IClientIncomingPacket
return;
}
if (player.hasItemRequest())
if (!player.canLogout())
{
client.sendPacket(RestartResponse.FALSE);
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
if (player.isLocked())
LOG_ACCOUNTING.info("Logged out, " + client);
if (!OfflineTradeUtil.enteredOfflineMode(player))
{
_log.warning("Player " + player.getName() + " tried to restart during class change.");
client.sendPacket(RestartResponse.FALSE);
return;
Disconnection.of(client, player).storeMe().deleteMe();
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player) && !(player.isGM() && Config.GM_RESTART_FIGHTING))
{
player.sendPacket(SystemMessageId.YOU_CANNOT_RESTART_WHILE_IN_COMBAT);
client.sendPacket(RestartResponse.FALSE);
return;
}
if (player.isBlockedFromExit())
{
client.sendPacket(RestartResponse.FALSE);
return;
}
_logAccounting.info("Logged out, " + client);
player.deleteMe();
client.setActiveChar(null);
// detach the client from the char so that the connection isnt closed in the deleteMe
player.setClient(null);
AntiFeedManager.getInstance().onDisconnect(client);
// return the client to the authed status
client.setConnectionState(ConnectionState.AUTHENTICATED);

View File

@ -31,6 +31,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerChat;
import com.l2jmobius.gameserver.model.events.returns.ChatFilterReturn;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
@ -110,7 +111,7 @@ public final class Say2 implements IClientIncomingPacket
{
_log.warning("Say2: Invalid type: " + _type + " Player : " + activeChar.getName() + " text: " + _text);
activeChar.sendPacket(ActionFailed.STATIC_PACKET);
activeChar.logout();
Disconnection.of(activeChar).defaultSequence(false);
return;
}
@ -118,7 +119,7 @@ public final class Say2 implements IClientIncomingPacket
{
_log.warning(activeChar.getName() + ": sending empty text. Possible packet hack!");
activeChar.sendPacket(ActionFailed.STATIC_PACKET);
activeChar.logout();
Disconnection.of(activeChar).defaultSequence(false);
return;
}

View File

@ -29,6 +29,7 @@ import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.data.xml.impl.SecondaryAuthData;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.Ex2ndPasswordAck;
import com.l2jmobius.gameserver.network.serverpackets.Ex2ndPasswordCheck;
@ -104,7 +105,7 @@ public class SecondaryPasswordAuth
if (passwordExist())
{
_log.warning("[SecondaryPasswordAuth]" + _activeClient.getAccountName() + " forced savePassword");
_activeClient.closeNow();
Disconnection.of(_activeClient).defaultSequence(false);
return false;
}
@ -157,7 +158,7 @@ public class SecondaryPasswordAuth
if (!passwordExist())
{
_log.warning("[SecondaryPasswordAuth]" + _activeClient.getAccountName() + " forced changePassword");
_activeClient.closeNow();
Disconnection.of(_activeClient).defaultSequence(false);
return false;
}

View File

@ -38,6 +38,8 @@ public class AttackStanceTaskManager
protected static final Map<L2Character, Long> _attackStanceTasks = new ConcurrentHashMap<>();
public static final long COMBAT_TIME = 15_000;
/**
* Instantiates a new attack stance task manager.
*/
@ -106,7 +108,7 @@ public class AttackStanceTaskManager
while (iter.hasNext())
{
e = iter.next();
if ((current - e.getValue()) > 15000)
if ((current - e.getValue()) > COMBAT_TIME)
{
actor = e.getKey();
if (actor != null)

View File

@ -28,6 +28,7 @@ import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -142,14 +143,7 @@ public final class FloodProtectorAction
*/
private void kickPlayer()
{
if (_client.getActiveChar() != null)
{
_client.getActiveChar().logout(false);
}
else
{
_client.closeNow();
}
Disconnection.of(_client).defaultSequence(false);
if (_log.getLevel() == Level.WARNING)
{

View File

@ -0,0 +1,151 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.util;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
* @author lord_rex
*/
public final class OfflineTradeUtil
{
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
private OfflineTradeUtil()
{
// utility class
}
/**
* Check whether player is able to enter offline mode.
* @param player the player to be check.
* @return {@code true} if the player is allowed to remain as off-line shop.
*/
private static boolean offlineMode(L2PcInstance player)
{
if ((player == null) || player.isInOlympiadMode() || player.isBlockedFromExit() || player.isJailed() || (player.getVehicle() != null))
{
return false;
}
boolean canSetShop = false;
switch (player.getPrivateStoreType())
{
case SELL:
case PACKAGE_SELL:
case BUY:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
case MANUFACTURE:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
default:
{
canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isInCraftMode();
break;
}
}
if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
{
canSetShop = false;
}
// Check whether client is null or player is already in offline mode.
final L2GameClient client = player.getClient();
if ((client == null) || client.isDetached())
{
return false;
}
return canSetShop;
}
/**
* Manages the disconnection process of offline traders.
* @param player
* @return {@code true} when player entered offline mode, otherwise {@code false}
*/
public static boolean enteredOfflineMode(L2PcInstance player)
{
if (!OfflineTradeUtil.offlineMode(player))
{
return false;
}
final L2GameClient client = player.getClient();
client.setDetached(true);
player.leaveParty();
OlympiadManager.getInstance().unRegisterNoble(player);
// If the L2PcInstance has Pet, unsummon it
L2Summon pet = player.getPet();
if (pet != null)
{
pet.setRestoreSummon(true);
pet.unSummon(player);
pet = player.getPet();
// Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
if (pet != null)
{
pet.broadcastNpcInfo(0);
}
}
player.getServitors().values().forEach(s ->
{
s.setRestoreSummon(true);
s.unSummon(player);
});
if (Config.OFFLINE_SET_NAME_COLOR)
{
player.getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
player.broadcastUserInfo();
}
if (player.getOfflineStartTime() == 0)
{
player.setOfflineStartTime(System.currentTimeMillis());
}
// Store trade on exit, if realtime saving is enabled.
if (Config.STORE_OFFLINE_TRADE_IN_REALTIME)
{
OfflineTradersTable.onTransaction(player, false, true);
}
Disconnection.of(player).storeMe().close(false);
LOG_ACCOUNTING.info("Entering offline mode, " + client);
return true;
}
}

View File

@ -26,6 +26,7 @@ import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2AccessLevel;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -129,7 +130,7 @@ public final class AdminChangeAccessLevel implements IAdminCommandHandler
{
player.setAccessLevel(lvl, false, true);
player.sendMessage("Your character has been banned. Bye.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -19,6 +19,7 @@ package handlers.admincommandhandlers;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
/**
* This class handles following admin commands: - character_disconnect = disconnects target player
@ -68,7 +69,7 @@ public class AdminDisconnect implements IAdminCommandHandler
{
activeChar.sendMessage("Character " + player.getName() + " disconnected from server.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -18,10 +18,10 @@ package handlers.admincommandhandlers;
import java.util.StringTokenizer;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
public class AdminKick implements IAdminCommandHandler
{
@ -44,11 +44,7 @@ public class AdminKick implements IAdminCommandHandler
final L2PcInstance plyr = L2World.getInstance().getPlayer(player);
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
activeChar.sendMessage("You kicked " + plyr.getName() + " from the game.");
}
}
@ -61,7 +57,7 @@ public class AdminKick implements IAdminCommandHandler
if (!player.isGM())
{
counter++;
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
activeChar.sendMessage("Kicked " + counter + " players.");

View File

@ -21,7 +21,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.handler.AdminCommandHandler;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
@ -31,6 +30,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -170,11 +170,7 @@ public class AdminMenu implements IAdminCommandHandler
String text;
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
text = "You kicked " + plyr.getName() + " from the game.";
}
else

View File

@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -58,7 +59,7 @@ public class BanHandler implements IPunishmentHandler
}
else
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
}
}
break;
@ -90,7 +91,7 @@ public class BanHandler implements IPunishmentHandler
*/
private static void applyToPlayer(L2PcInstance player)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
}
@Override

View File

@ -18,6 +18,7 @@ package handlers.telnethandlers.player;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.telnet.ITelnetCommand;
import io.netty.channel.ChannelHandlerContext;
@ -49,7 +50,7 @@ public class Kick implements ITelnetCommand
final L2PcInstance player = L2World.getInstance().getPlayer(args[0]);
if (player != null)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
return "Player has been successfully kicked.";
}
return "Couldn't find player with such name.";

View File

@ -565,15 +565,8 @@ public class LoginServerThread extends Thread
final L2GameClient client = _accountsInGameServer.get(account);
if (client != null)
{
if (client.isDetached())
{
client.getActiveChar().logout();
}
else
{
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
ACCOUNTING_LOGGER.info(getClass().getSimpleName() + ": Kicked by login, " + client);
ACCOUNTING_LOGGER.info("Kicked by login, " + client);
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
}

View File

@ -38,11 +38,10 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Hero;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.network.ClientNetworkManager;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.EventLoopGroupManager;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.loginserverpackets.game.ServerStatus;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.telnet.TelnetServer;
import com.l2jmobius.gameserver.util.Broadcast;
@ -610,27 +609,7 @@ public class Shutdown extends Thread
{
for (L2PcInstance player : L2World.getInstance().getPlayers())
{
// Logout Character
try
{
final L2GameClient client = player.getClient();
if ((client != null) && !client.isDetached())
{
client.close(ServerClose.STATIC_PACKET);
client.setActiveChar(null);
player.setClient(null);
}
else if ((client == null) || client.isDetached())
// player is probably a bot - force logout
{
player.logout();
}
player.deleteMe();
}
catch (Throwable t)
{
LOGGER.log(Level.WARNING, "Failed logour char " + player, t);
}
Disconnection.of(player).defaultSequence(true);
}
}

View File

@ -33,6 +33,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.TradeItem;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SellBuffHolder;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
public class OfflineTradersTable
@ -49,6 +50,10 @@ public class OfflineTradersTable
private static final String LOAD_OFFLINE_STATUS = "SELECT * FROM character_offline_trade";
private static final String LOAD_OFFLINE_ITEMS = "SELECT * FROM character_offline_trade_items WHERE `charId`=?";
protected OfflineTradersTable()
{
}
public void storeOffliners()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
@ -300,7 +305,7 @@ public class OfflineTradersTable
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error loading trader: " + player, e);
if (player != null)
{
player.deleteMe();
Disconnection.of(player).defaultSequence(false);
}
}
}
@ -470,11 +475,11 @@ public class OfflineTradersTable
*/
public static OfflineTradersTable getInstance()
{
return SingletonHolder._instance;
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final OfflineTradersTable _instance = new OfflineTradersTable();
protected static final OfflineTradersTable INSTANCE = new OfflineTradersTable();
}
}

View File

@ -72,6 +72,12 @@ public final class AntiFeedManager
return false;
}
// Players in offline mode should't be valid targets.
if (targetPlayer.getClient().isDetached())
{
return false;
}
if ((Config.ANTIFEED_INTERVAL > 0) && _lastDeathTimes.containsKey(targetPlayer.getObjectId()))
{
if ((System.currentTimeMillis() - _lastDeathTimes.get(targetPlayer.getObjectId())) < Config.ANTIFEED_INTERVAL)
@ -211,7 +217,7 @@ public final class AntiFeedManager
*/
public final void onDisconnect(L2GameClient client)
{
if ((client == null) || client.isDetached())
if ((client == null) || (client.getConnectionAddress() == null))
{
return;
}

View File

@ -39,6 +39,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnNpcCreatureSee;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
import com.l2jmobius.gameserver.util.Util;
@ -143,8 +144,8 @@ public final class L2World
final L2PcInstance existingPlayer = _allPlayers.putIfAbsent(object.getObjectId(), newPlayer);
if (existingPlayer != null)
{
existingPlayer.logout();
newPlayer.logout();
Disconnection.of(existingPlayer).defaultSequence(false);
Disconnection.of(newPlayer).defaultSequence(false);
LOGGER.warning(getClass().getSimpleName() + ": Duplicate character!? Disconnected both characters (" + newPlayer.getName() + ")");
}
else if (Config.FACTION_SYSTEM_ENABLED)

View File

@ -131,6 +131,7 @@ import com.l2jmobius.gameserver.model.stats.MoveType;
import com.l2jmobius.gameserver.model.stats.Stats;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.model.zone.ZoneRegion;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.Attack;
@ -3287,7 +3288,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
if (isPlayer())
{
getActingPlayer().logout();
Disconnection.of(getActingPlayer()).defaultSequence(false);
}
else if (isSummon())
{

View File

@ -260,6 +260,7 @@ import com.l2jmobius.gameserver.model.variables.AccountVariables;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AbstractHtmlPacket;
@ -296,7 +297,6 @@ import com.l2jmobius.gameserver.network.serverpackets.HennaInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import com.l2jmobius.gameserver.network.serverpackets.ItemList;
import com.l2jmobius.gameserver.network.serverpackets.LeaveWorld;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.MyTargetSelected;
import com.l2jmobius.gameserver.network.serverpackets.NicknameChanged;
@ -315,7 +315,6 @@ import com.l2jmobius.gameserver.network.serverpackets.RecipeShopMsg;
import com.l2jmobius.gameserver.network.serverpackets.RecipeShopSellList;
import com.l2jmobius.gameserver.network.serverpackets.RelationChanged;
import com.l2jmobius.gameserver.network.serverpackets.Ride;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SetupGauge;
import com.l2jmobius.gameserver.network.serverpackets.ShortCutInit;
import com.l2jmobius.gameserver.network.serverpackets.SkillCoolTime;
@ -807,6 +806,8 @@ public final class L2PcInstance extends L2Playable
private final Fishing _fishing = new Fishing(this);
private Future<?> _autoSaveTask = null;
public void setPvpFlagLasts(long time)
{
_pvpFlagLasts = time;
@ -1261,38 +1262,6 @@ public final class L2PcInstance extends L2Playable
_inCraftMode = b;
}
/**
* Manage Logout Task:
* <ul>
* <li>Remove player from world</li>
* <li>Save player data into DB</li>
* </ul>
*/
public void logout()
{
logout(true);
}
/**
* Manage Logout Task:
* <ul>
* <li>Remove player from world</li>
* <li>Save player data into DB</li>
* </ul>
* @param closeClient
*/
public void logout(boolean closeClient)
{
try
{
closeNetConnection(closeClient);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception on logout(): " + e.getMessage(), e);
}
}
/**
* @return a table containing all Common L2RecipeList of the L2PcInstance.
*/
@ -3983,33 +3952,6 @@ public final class L2PcInstance extends L2Playable
return ip;
}
/**
* Close the active connection with the client.
* @param closeClient
*/
private void closeNetConnection(boolean closeClient)
{
final L2GameClient client = _client;
if (client != null)
{
if (client.isDetached())
{
client.cleanMe(true);
}
else if (client.getChannel().isActive())
{
if (closeClient)
{
client.close(LeaveWorld.STATIC_PACKET);
}
else
{
client.close(ServerClose.STATIC_PACKET);
}
}
}
}
public Location getCurrentSkillWorldPosition()
{
return _currentSkillWorldPosition;
@ -6833,6 +6775,8 @@ public final class L2PcInstance extends L2Playable
player.startOnlineTimeUpdateTask();
player.setOnlineStatus(true, false);
player.startAutoSaveTask();
}
catch (Exception e)
{
@ -8111,6 +8055,61 @@ public final class L2PcInstance extends L2Playable
return isInCategory(CategoryType.SIXTH_CLASS_GROUP);
}
private void startAutoSaveTask()
{
if ((Config.CHAR_DATA_STORE_INTERVAL > 0) && (_autoSaveTask == null))
{
_autoSaveTask = ThreadPoolManager.scheduleAtFixedRate(this::autoSave, 300_000L, TimeUnit.MINUTES.toMillis(Config.CHAR_DATA_STORE_INTERVAL));
}
}
private void stopAutoSaveTask()
{
if (_autoSaveTask != null)
{
_autoSaveTask.cancel(false);
_autoSaveTask = null;
}
}
protected void autoSave()
{
storeMe();
storeRecommendations();
if (Config.UPDATE_ITEMS_ON_CHAR_STORE)
{
getInventory().updateDatabase();
getWarehouse().updateDatabase();
}
}
public boolean canLogout()
{
if (hasItemRequest())
{
return false;
}
if (isLocked())
{
_log.warning("Player " + getName() + " tried to restart/logout during class change.");
return false;
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(this) && !(isGM() && Config.GM_RESTART_FIGHTING))
{
return false;
}
if (isBlockedFromExit())
{
return false;
}
return true;
}
/**
* Return True if the L2PcInstance is autoAttackable.<br>
* <B><U>Actions</U>:</B>
@ -10708,28 +10707,19 @@ public final class L2PcInstance extends L2Playable
* <li>If the L2PcInstance is in observer mode, set its position to its position before entering in observer mode</li>
* <li>Set the online Flag to True or False and update the characters table of the database with online status and lastAccess</li>
* <li>Stop the HP/MP/CP Regeneration task</li>
* <li>Cancel Crafting, Attak or Cast</li>
* <li>Cancel Crafting, Attack or Cast</li>
* <li>Remove the L2PcInstance from the world</li>
* <li>Stop Party and Unsummon Pet</li>
* <li>Update database with items in its inventory and remove them from the world</li>
* <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI</li>
* <li>Close the connection with the client</li>
* </ul>
* <br>
* Remember this method is not to be used to half-ass disconnect players! This method is dedicated only to erase the player from the world.<br>
* If you intend to disconnect a player please use {@link Disconnection}
*/
@Override
public boolean deleteMe()
{
cleanup();
storeMe();
// Stop all passives and augment options without broadcasting changes.
getEffectList().stopAllPassives(false, false);
getEffectList().stopAllOptions(false, false);
return super.deleteMe();
}
private synchronized void cleanup()
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerLogout(this), this);
@ -11110,6 +11100,15 @@ public final class L2PcInstance extends L2Playable
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerMentorStatus(this, false), this);
}
// we store all data from players who are disconnected while in an event in order to restore it in the next login
if (L2Event.isParticipant(this))
{
L2Event.savePlayerEventStatus(this);
}
// Anti Feed
AntiFeedManager.getInstance().onDisconnect(getClient());
try
{
notifyFriends(L2FriendStatus.MODE_OFFLINE);
@ -11119,6 +11118,14 @@ public final class L2PcInstance extends L2Playable
{
_log.log(Level.WARNING, "Exception on deleteMe() notifyFriends: " + e.getMessage(), e);
}
// Stop all passives and augment options
getEffectList().stopAllPassives(false, false);
getEffectList().stopAllOptions(false, false);
stopAutoSaveTask();
return super.deleteMe();
}
public int getInventoryLimit()

View File

@ -26,6 +26,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.Disconnection;
/**
* Task that handles illegal player actions.
@ -86,7 +87,7 @@ public final class IllegalPlayerActionTask implements Runnable
}
case KICK:
{
_actor.logout(false);
Disconnection.of(_actor).defaultSequence(false);
break;
}
case KICKBAN:

View File

@ -0,0 +1,189 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.network;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
/**
* @author NB4L1
*/
public final class Disconnection
{
private static final Logger LOGGER = Logger.getLogger(Disconnection.class.getName());
public static L2GameClient getClient(L2GameClient client, L2PcInstance activeChar)
{
if (client != null)
{
return client;
}
if (activeChar != null)
{
return activeChar.getClient();
}
return null;
}
public static L2PcInstance getActiveChar(L2GameClient client, L2PcInstance activeChar)
{
if (activeChar != null)
{
return activeChar;
}
if (client != null)
{
return client.getActiveChar();
}
return null;
}
private final L2GameClient _client;
private final L2PcInstance _activeChar;
private Disconnection(L2GameClient client)
{
this(client, null);
}
public static Disconnection of(L2GameClient client)
{
return new Disconnection(client);
}
private Disconnection(L2PcInstance activeChar)
{
this(null, activeChar);
}
public static Disconnection of(L2PcInstance activeChar)
{
return new Disconnection(activeChar);
}
private Disconnection(L2GameClient client, L2PcInstance activeChar)
{
_client = getClient(client, activeChar);
_activeChar = getActiveChar(client, activeChar);
if (_client != null)
{
_client.setActiveChar(null);
}
if (_activeChar != null)
{
_activeChar.setClient(null);
}
}
public static Disconnection of(L2GameClient client, L2PcInstance activeChar)
{
return new Disconnection(client, activeChar);
}
public Disconnection storeMe()
{
try
{
if (_activeChar != null)
{
_activeChar.storeMe();
}
}
catch (RuntimeException e)
{
LOGGER.warning(e.getMessage());
}
return this;
}
public Disconnection deleteMe()
{
try
{
if (_activeChar != null)
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerLogout(_activeChar), _activeChar);
_activeChar.deleteMe();
}
}
catch (RuntimeException e)
{
LOGGER.warning(e.getMessage());
}
return this;
}
public Disconnection close(boolean toLoginScreen)
{
if (_client != null)
{
_client.close(toLoginScreen);
}
return this;
}
public Disconnection close(IClientOutgoingPacket packet)
{
if (_client != null)
{
_client.close(packet);
}
return this;
}
public void defaultSequence(boolean toLoginScreen)
{
defaultSequence();
close(toLoginScreen);
}
public void defaultSequence(IClientOutgoingPacket packet)
{
defaultSequence();
close(packet);
}
private void defaultSequence()
{
storeMe();
deleteMe();
}
public void onDisconnection()
{
if (_activeChar != null)
{
ThreadPoolManager.schedule(() -> defaultSequence(), _activeChar.canLogout() ? 0 : AttackStanceTaskManager.COMBAT_TIME);
}
}
}

View File

@ -21,9 +21,6 @@ import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -33,36 +30,28 @@ import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.network.ChannelInboundHandler;
import com.l2jmobius.commons.network.ICrypt;
import com.l2jmobius.commons.network.IIncomingPacket;
import com.l2jmobius.commons.network.IOutgoingPacket;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.LoginServerThread.SessionKey;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.data.xml.impl.SecondaryAuthData;
import com.l2jmobius.gameserver.enums.CharacterDeleteFailType;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.AntiFeedManager;
import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
import com.l2jmobius.gameserver.model.CharSelectInfoPackage;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.L2Event;
import com.l2jmobius.gameserver.model.holders.ClientHardwareInfoHolder;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.LeaveWorld;
import com.l2jmobius.gameserver.network.serverpackets.ServerClose;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.security.SecondaryPasswordAuth;
import com.l2jmobius.gameserver.util.FloodProtectors;
import com.l2jmobius.gameserver.util.Util;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
@ -74,7 +63,7 @@ import io.netty.channel.ChannelHandlerContext;
public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
protected static final Logger LOGGER = Logger.getLogger(L2GameClient.class.getName());
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
private final int _objectId;
@ -88,20 +77,15 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
private SecondaryPasswordAuth _secondaryAuth;
private ClientHardwareInfoHolder _hardwareInfo;
private boolean _isAuthedGG;
private final long _connectionStartTime = System.currentTimeMillis();
private CharSelectInfoPackage[] _charSlotMapping = null;
// flood protectors
private final FloodProtectors _floodProtectors = new FloodProtectors(this);
// Task
protected final ScheduledFuture<?> _autoSaveInDB;
protected ScheduledFuture<?> _cleanupTask = null;
// Crypt
private final Crypt _crypt;
private boolean _isDetached = false;
private volatile boolean _isDetached = false;
private boolean _protocol;
@ -111,14 +95,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
_objectId = IdFactory.getInstance().getNextId();
_crypt = new Crypt(this);
if (Config.CHAR_DATA_STORE_INTERVAL > 0)
{
_autoSaveInDB = ThreadPoolManager.scheduleAtFixedRate(new AutoSaveTask(), 300000L, Config.CHAR_DATA_STORE_INTERVAL);
}
else
{
_autoSaveInDB = null;
}
}
public int getObjectId()
@ -135,23 +111,18 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
final InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
_addr = address.getAddress();
_channel = ctx.channel();
LOGGER.finer("Client Connected: " + ctx.channel());
LOG_ACCOUNTING.finer("Client Connected: " + ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx)
{
LOGGER.finer("Client Disconnected: " + ctx.channel());
LOG_ACCOUNTING.finer("Client Disconnected: " + ctx.channel());
// no long running tasks here, do it async
try
{
ThreadPoolManager.execute(new DisconnectTask());
}
catch (RejectedExecutionException e)
{
// server is closing
}
LoginServerThread.getInstance().sendLogout(getAccountName());
IdFactory.getInstance().releaseId(getObjectId());
Disconnection.of(this).onDisconnection();
}
@Override
@ -172,6 +143,25 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
{
}
public void closeNow()
{
if (_channel != null)
{
_channel.close();
}
}
public void close(IClientOutgoingPacket packet)
{
sendPacket(packet);
closeNow();
}
public void close(boolean toLoginScreen)
{
close(toLoginScreen ? ServerClose.STATIC_PACKET : LeaveWorld.STATIC_PACKET);
}
public Channel getChannel()
{
return _channel;
@ -193,19 +183,14 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _addr;
}
public long getConnectionStartTime()
{
return _connectionStartTime;
}
public L2PcInstance getActiveChar()
{
return _activeChar;
}
public void setActiveChar(L2PcInstance pActiveChar)
public void setActiveChar(L2PcInstance activeChar)
{
_activeChar = pActiveChar;
_activeChar = activeChar;
}
public ReentrantLock getActiveCharLock()
@ -228,9 +213,9 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _isAuthedGG;
}
public void setAccountName(String pAccountName)
public void setAccountName(String activeChar)
{
_accountName = pAccountName;
_accountName = activeChar;
if (SecondaryAuthData.getInstance().isEnabled())
{
@ -287,16 +272,16 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
/**
* Method to handle character deletion
* @param charslot
* @param characterSlot
* @return a byte:
* <li>-1: Error: No char was found for such charslot, caught exception, etc...
* <li>0: character is not member of any clan, proceed with deletion
* <li>1: character is member of a clan, but not clan leader
* <li>2: character is clan leader
*/
public CharacterDeleteFailType markToDeleteChar(int charslot)
public CharacterDeleteFailType markToDeleteChar(int characterSlot)
{
final int objectId = getObjectIdForSlot(charslot);
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return CharacterDeleteFailType.UNKNOWN;
@ -354,38 +339,14 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
_logAccounting.info("Delete, " + objectId + ", " + this);
LOG_ACCOUNTING.info("Delete, " + objectId + ", " + this);
return CharacterDeleteFailType.NONE;
}
/**
* Save the L2PcInstance to the database.
*/
public void saveCharToDisk()
public void restore(int characterSlot)
{
try
{
if (getActiveChar() != null)
{
getActiveChar().storeMe();
getActiveChar().storeRecommendations();
if (Config.UPDATE_ITEMS_ON_CHAR_STORE)
{
getActiveChar().getInventory().updateDatabase();
getActiveChar().getWarehouse().updateDatabase();
}
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Error saving character..", e);
}
}
public void markRestoredChar(int charslot)
{
final int objid = getObjectIdForSlot(charslot);
if (objid < 0)
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return;
}
@ -393,7 +354,7 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE characters SET deletetime=0 WHERE charId=?"))
{
statement.setInt(1, objid);
statement.setInt(1, objectId);
statement.execute();
}
catch (Exception e)
@ -401,7 +362,7 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
LOGGER.log(Level.SEVERE, "Error restoring character.", e);
}
_logAccounting.info("Restore, " + objid + ", " + this);
LOG_ACCOUNTING.info("Restore, " + objectId + ", " + this);
}
public static void deleteCharByObjId(int objid)
@ -555,38 +516,30 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
public L2PcInstance loadCharFromDisk(int charslot)
public L2PcInstance load(int characterSlot)
{
final int objId = getObjectIdForSlot(charslot);
if (objId < 0)
final int objectId = getObjectIdForSlot(characterSlot);
if (objectId < 0)
{
return null;
}
L2PcInstance character = L2World.getInstance().getPlayer(objId);
if (character != null)
L2PcInstance player = L2World.getInstance().getPlayer(objectId);
if (player != null)
{
// exploit prevention, should not happens in normal way
LOGGER.severe("Attempt of double login: " + character.getName() + "(" + objId + ") " + getAccountName());
if (character.getClient() != null)
{
character.getClient().closeNow();
}
else
{
character.deleteMe();
}
LOGGER.severe("Attempt of double login: " + player.getName() + "(" + objectId + ") " + getAccountName());
Disconnection.of(player).defaultSequence(false);
return null;
}
character = L2PcInstance.load(objId);
if (character == null)
player = L2PcInstance.load(objectId);
if (player == null)
{
LOGGER.severe("could not restore in slot: " + charslot);
LOGGER.severe("Could not restore in slot: " + characterSlot);
}
// setCharacter(character);
return character;
return player;
}
/**
@ -611,47 +564,21 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return _secondaryAuth;
}
public void close(IOutgoingPacket packet)
{
if (packet != null)
{
_channel.writeAndFlush(packet);
}
_channel.close();
}
/**
* @param charslot
* @param characterSlot
* @return
*/
private int getObjectIdForSlot(int charslot)
private int getObjectIdForSlot(int characterSlot)
{
final CharSelectInfoPackage info = getCharSelection(charslot);
final CharSelectInfoPackage info = getCharSelection(characterSlot);
if (info == null)
{
LOGGER.warning(toString() + " tried to delete Character in slot " + charslot + " but no characters exits at that slot.");
LOGGER.warning(toString() + " tried to delete Character in slot " + characterSlot + " but no characters exits at that slot.");
return -1;
}
return info.getObjectId();
}
/**
* Close client connection with {@link ServerClose} packet
*/
public void closeNow()
{
_isDetached = true; // prevents more packets execution
close(ServerClose.STATIC_PACKET);
synchronized (this)
{
if (_cleanupTask != null)
{
cancelCleanup();
}
_cleanupTask = ThreadPoolManager.schedule(new CleanupTask(), 0); // instant
}
}
/**
* Produces the best possible string representation of this client.
*/
@ -688,209 +615,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
}
}
protected class DisconnectTask implements Runnable
{
@Override
public void run()
{
boolean fast = true;
try
{
if ((getActiveChar() != null) && !isDetached())
{
setDetached(true);
if (offlineMode(getActiveChar()))
{
getActiveChar().leaveParty();
OlympiadManager.getInstance().unRegisterNoble(getActiveChar());
// If the L2PcInstance has Pet, unsummon it
L2Summon pet = getActiveChar().getPet();
if (pet != null)
{
pet.setRestoreSummon(true);
pet.unSummon(getActiveChar());
pet = getActiveChar().getPet();
// Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
if (pet != null)
{
pet.broadcastNpcInfo(0);
}
}
getActiveChar().getServitors().values().forEach(s ->
{
s.setRestoreSummon(true);
s.unSummon(getActiveChar());
});
if (Config.OFFLINE_SET_NAME_COLOR)
{
getActiveChar().getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
getActiveChar().broadcastUserInfo();
}
if (getActiveChar().getOfflineStartTime() == 0)
{
getActiveChar().setOfflineStartTime(System.currentTimeMillis());
}
// Store trade on exit, if realtime saving is enabled.
if (Config.STORE_OFFLINE_TRADE_IN_REALTIME)
{
OfflineTradersTable.onTransaction(getActiveChar(), false, true);
}
_logAccounting.info("Entering offline mode, " + L2GameClient.this);
return;
}
fast = !getActiveChar().isInCombat() && !getActiveChar().isLocked();
}
cleanMe(fast);
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error while disconnecting client.", e1);
}
IdFactory.getInstance().releaseId(getObjectId());
}
}
/**
* @param player the player to be check.
* @return {@code true} if the player is allowed to remain as off-line shop.
*/
protected boolean offlineMode(L2PcInstance player)
{
if (player.isInOlympiadMode() || player.isBlockedFromExit() || player.isJailed() || (player.getVehicle() != null))
{
return false;
}
boolean canSetShop = false;
switch (player.getPrivateStoreType())
{
case SELL:
case PACKAGE_SELL:
case BUY:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
case MANUFACTURE:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
default:
{
canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isInCraftMode();
break;
}
}
if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
{
canSetShop = false;
}
return canSetShop;
}
public void cleanMe(boolean fast)
{
try
{
synchronized (this)
{
if (_cleanupTask == null)
{
_cleanupTask = ThreadPoolManager.schedule(new CleanupTask(), fast ? 5 : 15000L);
}
}
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error during cleanup.", e1);
}
}
protected class CleanupTask implements Runnable
{
@Override
public void run()
{
try
{
// we are going to manually save the char bellow thus we can force the cancel
if (_autoSaveInDB != null)
{
_autoSaveInDB.cancel(true);
// ThreadPoolManager.getInstance().removeGeneral((Runnable) _autoSaveInDB);
}
if (getActiveChar() != null) // this should only happen on connection loss
{
if (getActiveChar().isLocked())
{
LOGGER.warning("Player " + getActiveChar().getName() + " still performing subclass actions during disconnect.");
}
// we store all data from players who are disconnected while in an event in order to restore it in the next login
if (L2Event.isParticipant(getActiveChar()))
{
L2Event.savePlayerEventStatus(getActiveChar());
}
if (getActiveChar().isOnline())
{
getActiveChar().deleteMe();
AntiFeedManager.getInstance().onDisconnect(L2GameClient.this);
}
// prevent closing again
getActiveChar().setClient(null);
}
setActiveChar(null);
}
catch (Exception e1)
{
LOGGER.log(Level.WARNING, "Error while cleanup client.", e1);
}
finally
{
LoginServerThread.getInstance().sendLogout(getAccountName());
}
}
}
protected class AutoSaveTask implements Runnable
{
@Override
public void run()
{
try
{
final L2PcInstance player = getActiveChar();
if ((player != null) && player.isOnline()) // safety precaution
{
saveCharToDisk();
final L2Summon pet = player.getPet();
if (pet != null)
{
pet.storeMe();
}
player.getServitors().values().forEach(L2Summon::storeMe);
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Error on AutoSaveTask.", e);
}
}
}
public boolean isProtocolOk()
{
return _protocol;
@ -901,20 +625,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
_protocol = b;
}
public boolean handleCheat(String punishment)
{
if (_activeChar != null)
{
Util.handleIllegalPlayerAction(_activeChar, toString() + ": " + punishment, Config.DEFAULT_PUNISH);
return true;
}
final Logger logAudit = Logger.getLogger("audit");
logAudit.info("AUDIT: Client " + toString() + " kicked for reason: " + punishment);
closeNow();
return false;
}
public void setClientTracert(int[][] tracert)
{
trace = tracert;
@ -925,17 +635,6 @@ public final class L2GameClient extends ChannelInboundHandler<L2GameClient>
return trace;
}
private boolean cancelCleanup()
{
final Future<?> task = _cleanupTask;
if (task != null)
{
_cleanupTask = null;
return task.cancel(true);
}
return false;
}
public void sendActionFailed()
{
sendPacket(ActionFailed.STATIC_PACKET);

View File

@ -54,7 +54,7 @@ public final class AuthLogin implements IClientIncomingPacket
{
if (_loginName.isEmpty() || !client.isProtocolOk())
{
client.close(null);
client.closeNow();
return;
}

View File

@ -41,6 +41,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerCreate;
import com.l2jmobius.gameserver.model.items.PcItemTemplate;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.CharCreateFail;
import com.l2jmobius.gameserver.network.serverpackets.CharCreateOk;
@ -333,7 +334,7 @@ public final class CharacterCreate implements IClientIncomingPacket
{
newChar.getVariables().set("intro_god_video", true);
}
newChar.deleteMe();
Disconnection.of(client, newChar).storeMe().deleteMe();
final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1);
client.setCharSelection(cl.getCharInfo());

View File

@ -47,7 +47,7 @@ public final class CharacterRestore implements IClientIncomingPacket
return;
}
client.markRestoredChar(_charSlot);
client.restore(_charSlot);
final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1, 0);
client.sendPacket(cl);
client.setCharSelection(cl.getCharInfo());

View File

@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.CharSelected;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
@ -146,7 +147,7 @@ public class CharacterSelect implements IClientIncomingPacket
}
// load up character from disk
final L2PcInstance cha = client.loadCharFromDisk(_charSlot);
final L2PcInstance cha = client.load(_charSlot);
if (cha == null)
{
return; // handled in L2GameClient
@ -161,7 +162,7 @@ public class CharacterSelect implements IClientIncomingPacket
final TerminateReturn terminate = EventDispatcher.getInstance().notifyEvent(new OnPlayerSelect(cha, cha.getObjectId(), cha.getName(), client), Containers.Players(), TerminateReturn.class);
if ((terminate != null) && terminate.terminate())
{
cha.deleteMe();
Disconnection.of(cha).defaultSequence(false);
return;
}

View File

@ -58,6 +58,7 @@ import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
@ -142,7 +143,7 @@ public class EnterWorld implements IClientIncomingPacket
if (activeChar == null)
{
_log.warning("EnterWorld failed! activeChar returned 'null'.");
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
@ -681,7 +682,7 @@ public class EnterWorld implements IClientIncomingPacket
{
if (client.getHardwareInfo() == null)
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
}, 5000);

View File

@ -18,14 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.L2Event;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jmobius.gameserver.util.OfflineTradeUtil;
/**
* This class ...
@ -33,7 +31,7 @@ import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
*/
public final class Logout implements IClientIncomingPacket
{
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
@Override
public boolean read(L2GameClient client, PacketReader packet)
@ -47,42 +45,21 @@ public final class Logout implements IClientIncomingPacket
final L2PcInstance player = client.getActiveChar();
if (player == null)
{
client.closeNow();
return;
}
if (player.hasItemRequest())
if (!player.canLogout())
{
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
if (player.isLocked())
LOG_ACCOUNTING.info("Logged out, " + client);
if (!OfflineTradeUtil.enteredOfflineMode(player))
{
_log.warning("Player " + player.getName() + " tried to logout during class change.");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
Disconnection.of(client, player).defaultSequence(false);
}
// Don't allow leaving if player is fighting
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player))
{
if (!player.isGM() || (player.isGM() && !Config.GM_RESTART_FIGHTING))
{
player.sendPacket(SystemMessageId.YOU_CANNOT_EXIT_THE_GAME_WHILE_IN_COMBAT);
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
if (L2Event.isParticipant(player))
{
player.sendMessage("A superior power doesn't allow you to leave the event.");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
_logAccounting.info("Disconnected, " + client);
player.logout();
}
}

View File

@ -47,7 +47,7 @@ public final class ProtocolVersion implements IClientIncomingPacket
if (_version == -2)
{
// this is just a ping attempt from the new C2 client
client.close(null);
client.closeNow();
}
else if (!Config.PROTOCOL_LIST.contains(_version))
{

View File

@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnNpcMenuSelect;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerBypass;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
@ -86,7 +87,7 @@ public final class RequestBypassToServer implements IClientIncomingPacket
if (_command.isEmpty())
{
_log.warning("Player " + activeChar.getName() + " sent empty bypass!");
activeChar.logout();
Disconnection.of(client, activeChar).defaultSequence(false);
return;
}

View File

@ -21,6 +21,7 @@ import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.ClientHardwareInfoHolder;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -93,7 +94,7 @@ public final class RequestHardWareInfo implements IClientIncomingPacket
}
if (count >= Config.MAX_PLAYERS_PER_HWID)
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
return;
}
}

View File

@ -18,16 +18,15 @@ package com.l2jmobius.gameserver.network.clientpackets;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.instancemanager.AntiFeedManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.CharSelectionInfo;
import com.l2jmobius.gameserver.network.serverpackets.RestartResponse;
import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
import com.l2jmobius.gameserver.util.OfflineTradeUtil;
/**
* This class ...
@ -35,7 +34,7 @@ import com.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
*/
public final class RequestRestart implements IClientIncomingPacket
{
protected static final Logger _logAccounting = Logger.getLogger("accounting");
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
@Override
public boolean read(L2GameClient client, PacketReader packet)
@ -52,43 +51,20 @@ public final class RequestRestart implements IClientIncomingPacket
return;
}
if (player.hasItemRequest())
if (!player.canLogout())
{
client.sendPacket(RestartResponse.FALSE);
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
if (player.isLocked())
LOG_ACCOUNTING.info("Logged out, " + client);
if (!OfflineTradeUtil.enteredOfflineMode(player))
{
_log.warning("Player " + player.getName() + " tried to restart during class change.");
client.sendPacket(RestartResponse.FALSE);
return;
Disconnection.of(client, player).storeMe().deleteMe();
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(player) && !(player.isGM() && Config.GM_RESTART_FIGHTING))
{
player.sendPacket(SystemMessageId.YOU_CANNOT_RESTART_WHILE_IN_COMBAT);
client.sendPacket(RestartResponse.FALSE);
return;
}
if (player.isBlockedFromExit())
{
client.sendPacket(RestartResponse.FALSE);
return;
}
_logAccounting.info("Logged out, " + client);
player.deleteMe();
client.setActiveChar(null);
// detach the client from the char so that the connection isnt closed in the deleteMe
player.setClient(null);
AntiFeedManager.getInstance().onDisconnect(client);
// return the client to the authed status
client.setConnectionState(ConnectionState.AUTHENTICATED);

View File

@ -31,6 +31,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerChat;
import com.l2jmobius.gameserver.model.events.returns.ChatFilterReturn;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
@ -110,7 +111,7 @@ public final class Say2 implements IClientIncomingPacket
{
_log.warning("Say2: Invalid type: " + _type + " Player : " + activeChar.getName() + " text: " + _text);
activeChar.sendPacket(ActionFailed.STATIC_PACKET);
activeChar.logout();
Disconnection.of(activeChar).defaultSequence(false);
return;
}
@ -118,7 +119,7 @@ public final class Say2 implements IClientIncomingPacket
{
_log.warning(activeChar.getName() + ": sending empty text. Possible packet hack!");
activeChar.sendPacket(ActionFailed.STATIC_PACKET);
activeChar.logout();
Disconnection.of(activeChar).defaultSequence(false);
return;
}

View File

@ -29,6 +29,7 @@ import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.LoginServerThread;
import com.l2jmobius.gameserver.data.xml.impl.SecondaryAuthData;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.Ex2ndPasswordAck;
import com.l2jmobius.gameserver.network.serverpackets.Ex2ndPasswordCheck;
@ -104,7 +105,7 @@ public class SecondaryPasswordAuth
if (passwordExist())
{
_log.warning("[SecondaryPasswordAuth]" + _activeClient.getAccountName() + " forced savePassword");
_activeClient.closeNow();
Disconnection.of(_activeClient).defaultSequence(false);
return false;
}
@ -157,7 +158,7 @@ public class SecondaryPasswordAuth
if (!passwordExist())
{
_log.warning("[SecondaryPasswordAuth]" + _activeClient.getAccountName() + " forced changePassword");
_activeClient.closeNow();
Disconnection.of(_activeClient).defaultSequence(false);
return false;
}

View File

@ -38,6 +38,8 @@ public class AttackStanceTaskManager
protected static final Map<L2Character, Long> _attackStanceTasks = new ConcurrentHashMap<>();
public static final long COMBAT_TIME = 15_000;
/**
* Instantiates a new attack stance task manager.
*/
@ -106,7 +108,7 @@ public class AttackStanceTaskManager
while (iter.hasNext())
{
e = iter.next();
if ((current - e.getValue()) > 15000)
if ((current - e.getValue()) > COMBAT_TIME)
{
actor = e.getKey();
if (actor != null)

View File

@ -28,6 +28,7 @@ import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.ConnectionState;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -142,14 +143,7 @@ public final class FloodProtectorAction
*/
private void kickPlayer()
{
if (_client.getActiveChar() != null)
{
_client.getActiveChar().logout(false);
}
else
{
_client.closeNow();
}
Disconnection.of(_client).defaultSequence(false);
if (_log.getLevel() == Level.WARNING)
{

View File

@ -0,0 +1,151 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.util;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
* @author lord_rex
*/
public final class OfflineTradeUtil
{
protected static final Logger LOG_ACCOUNTING = Logger.getLogger("accounting");
private OfflineTradeUtil()
{
// utility class
}
/**
* Check whether player is able to enter offline mode.
* @param player the player to be check.
* @return {@code true} if the player is allowed to remain as off-line shop.
*/
private static boolean offlineMode(L2PcInstance player)
{
if ((player == null) || player.isInOlympiadMode() || player.isBlockedFromExit() || player.isJailed() || (player.getVehicle() != null))
{
return false;
}
boolean canSetShop = false;
switch (player.getPrivateStoreType())
{
case SELL:
case PACKAGE_SELL:
case BUY:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
case MANUFACTURE:
{
canSetShop = Config.OFFLINE_TRADE_ENABLE;
break;
}
default:
{
canSetShop = Config.OFFLINE_CRAFT_ENABLE && player.isInCraftMode();
break;
}
}
if (Config.OFFLINE_MODE_IN_PEACE_ZONE && !player.isInsideZone(ZoneId.PEACE))
{
canSetShop = false;
}
// Check whether client is null or player is already in offline mode.
final L2GameClient client = player.getClient();
if ((client == null) || client.isDetached())
{
return false;
}
return canSetShop;
}
/**
* Manages the disconnection process of offline traders.
* @param player
* @return {@code true} when player entered offline mode, otherwise {@code false}
*/
public static boolean enteredOfflineMode(L2PcInstance player)
{
if (!OfflineTradeUtil.offlineMode(player))
{
return false;
}
final L2GameClient client = player.getClient();
client.setDetached(true);
player.leaveParty();
OlympiadManager.getInstance().unRegisterNoble(player);
// If the L2PcInstance has Pet, unsummon it
L2Summon pet = player.getPet();
if (pet != null)
{
pet.setRestoreSummon(true);
pet.unSummon(player);
pet = player.getPet();
// Dead pet wasn't unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
if (pet != null)
{
pet.broadcastNpcInfo(0);
}
}
player.getServitors().values().forEach(s ->
{
s.setRestoreSummon(true);
s.unSummon(player);
});
if (Config.OFFLINE_SET_NAME_COLOR)
{
player.getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
player.broadcastUserInfo();
}
if (player.getOfflineStartTime() == 0)
{
player.setOfflineStartTime(System.currentTimeMillis());
}
// Store trade on exit, if realtime saving is enabled.
if (Config.STORE_OFFLINE_TRADE_IN_REALTIME)
{
OfflineTradersTable.onTransaction(player, false, true);
}
Disconnection.of(player).storeMe().close(false);
LOG_ACCOUNTING.info("Entering offline mode, " + client);
return true;
}
}

View File

@ -26,6 +26,7 @@ import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2AccessLevel;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -129,7 +130,7 @@ public final class AdminChangeAccessLevel implements IAdminCommandHandler
{
player.setAccessLevel(lvl, false, true);
player.sendMessage("Your character has been banned. Bye.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -19,6 +19,7 @@ package handlers.admincommandhandlers;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
/**
* This class handles following admin commands: - character_disconnect = disconnects target player
@ -68,7 +69,7 @@ public class AdminDisconnect implements IAdminCommandHandler
{
activeChar.sendMessage("Character " + player.getName() + " disconnected from server.");
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
}

View File

@ -18,10 +18,10 @@ package handlers.admincommandhandlers;
import java.util.StringTokenizer;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
public class AdminKick implements IAdminCommandHandler
{
@ -44,11 +44,7 @@ public class AdminKick implements IAdminCommandHandler
final L2PcInstance plyr = L2World.getInstance().getPlayer(player);
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
activeChar.sendMessage("You kicked " + plyr.getName() + " from the game.");
}
}
@ -61,7 +57,7 @@ public class AdminKick implements IAdminCommandHandler
if (!player.isGM())
{
counter++;
player.logout();
Disconnection.of(player).defaultSequence(false);
}
}
activeChar.sendMessage("Kicked " + counter + " players.");

View File

@ -21,7 +21,6 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.sql.impl.OfflineTradersTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.handler.AdminCommandHandler;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
@ -31,6 +30,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
@ -170,11 +170,7 @@ public class AdminMenu implements IAdminCommandHandler
String text;
if (plyr != null)
{
if (plyr.getOfflineStartTime() > 0)
{
OfflineTradersTable.removeTrader(plyr.getObjectId());
}
plyr.logout();
Disconnection.of(plyr).defaultSequence(false);
text = "You kicked " + plyr.getName() + " from the game.";
}
else

View File

@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.L2GameClient;
/**
@ -58,7 +59,7 @@ public class BanHandler implements IPunishmentHandler
}
else
{
client.closeNow();
Disconnection.of(client).defaultSequence(false);
}
}
break;
@ -90,7 +91,7 @@ public class BanHandler implements IPunishmentHandler
*/
private static void applyToPlayer(L2PcInstance player)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
}
@Override

View File

@ -18,6 +18,7 @@ package handlers.telnethandlers.player;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.Disconnection;
import com.l2jmobius.gameserver.network.telnet.ITelnetCommand;
import io.netty.channel.ChannelHandlerContext;
@ -49,7 +50,7 @@ public class Kick implements ITelnetCommand
final L2PcInstance player = L2World.getInstance().getPlayer(args[0]);
if (player != null)
{
player.logout();
Disconnection.of(player).defaultSequence(false);
return "Player has been successfully kicked.";
}
return "Couldn't find player with such name.";

View File

@ -565,15 +565,8 @@ public class LoginServerThread extends Thread
final L2GameClient client = _accountsInGameServer.get(account);
if (client != null)
{
if (client.isDetached())
{
client.getActiveChar().logout();
}
else
{
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
ACCOUNTING_LOGGER.info(getClass().getSimpleName() + ": Kicked by login, " + client);
ACCOUNTING_LOGGER.info("Kicked by login, " + client);
client.close(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_LOGGED_IN_TO_TWO_PLACES_IF_YOU_SUSPECT_ACCOUNT_THEFT_WE_RECOMMEND_CHANGING_YOUR_PASSWORD_SCANNING_YOUR_COMPUTER_FOR_VIRUSES_AND_USING_AN_ANTI_VIRUS_SOFTWARE));
}
}

Some files were not shown because too many files have changed in this diff Show More