package com.aionemu.gameserver.services.player;
import java.sql.Timestamp;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.aionemu.gameserver.configs.main.AutoGroupConfig;
import com.aionemu.gameserver.dao.*;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.dataholders.PlayerInitialData.LocationData;
import com.aionemu.gameserver.model.TaskId;
import com.aionemu.gameserver.model.gameobjects.Summon;
import com.aionemu.gameserver.model.gameobjects.player.BindPointPosition;
import com.aionemu.gameserver.model.gameobjects.player.FriendList;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.summons.SummonMode;
import com.aionemu.gameserver.model.summons.UnsummonType;
import com.aionemu.gameserver.model.team.alliance.PlayerAllianceService;
import com.aionemu.gameserver.model.team.group.PlayerGroupService;
import com.aionemu.gameserver.network.aion.AionConnection;
import com.aionemu.gameserver.network.aion.clientpackets.CM_QUIT;
import com.aionemu.gameserver.network.chatserver.ChatServer;
import com.aionemu.gameserver.questEngine.QuestEngine;
import com.aionemu.gameserver.questEngine.model.QuestEnv;
import com.aionemu.gameserver.services.*;
import com.aionemu.gameserver.services.conquerorAndProtectorSystem.ConquerorAndProtectorService;
import com.aionemu.gameserver.services.findgroup.FindGroupService;
import com.aionemu.gameserver.services.instance.InstanceService;
import com.aionemu.gameserver.services.summons.SummonsService;
import com.aionemu.gameserver.taskmanager.tasks.ExpireTimerTask;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.utils.audit.GMService;
import com.aionemu.gameserver.world.World;
import com.aionemu.gameserver.world.WorldPosition;
/**
* @author ATracer, Neon
*/
public class PlayerLeaveWorldService {
private static final Logger log = LoggerFactory.getLogger(PlayerLeaveWorldService.class);
/**
* This method is called when a player loses client connection, e.g. when killing the process, or due to bad network connectivity.<br>
* <br>
* <b><font color='red'>NOTICE:</font> This method must only be called from {@link AionConnection#onDisconnect()} and not from anywhere else</b>
*
* @see #leaveWorld(Player)
*/
public static void leaveWorldDelayed(Player player, long delayInMillis) {
Future<?> leaveWorldTask = ThreadPoolManager.getInstance().schedule(() -> leaveWorld(player), delayInMillis);
player.getController().addTask(TaskId.DESPAWN, leaveWorldTask);
}
/**
* This method saves a player and removes him from the world. It is called when a player leaves the game, which includes just two cases: either
* he goes back to char selection screen or is leaving the game (closing client).<br>
* <br>
* <b><font color='red'>NOTICE:</font> This method is called only from {@link CM_QUIT} and must not be called from anywhere else</b>
*/
public static void leaveWorld(Player player) {
AionConnection con = player.getClientConnection();
player.setClientConnection(null); // this sets the player semi-offline, PacketSendUtility will not send packets anymore
WorldPosition pos = player.getPosition();
if (pos == null || pos.getMapRegion() == null) { // ensure safe logout
log.warn(player + " had invalid position: " + pos + " so he was reset to bind point");
BindPointPosition bp = player.getBindPoint();
if (bp != null)
pos = World.getInstance().createPosition(bp.getMapId(), bp.getX(), bp.getY(), bp.getZ(), bp.getHeading(), 1);
else {
LocationData ld = DataManager.PLAYER_INITIAL_DATA.getSpawnLocation(player.getRace());
pos = World.getInstance().createPosition(ld.getMapId(), ld.getX(), ld.getY(), ld.getZ(), ld.getHeading(), 1);
}
player.setPosition(pos);
}
FindGroupService.getInstance().onLogout(player);
player.getResponseRequester().denyAll();
player.getFriendList().setStatus(FriendList.Status.OFFLINE, player.getCommonData());
BrokerService.getInstance().removePlayerCache(player);
ExchangeService.getInstance().cancelExchange(player);
RepurchaseService.getInstance().removeRepurchaseItems(player);
if (AutoGroupConfig.AUTO_GROUP_ENABLE)
AutoGroupService.getInstance().onLogout(player);
ConquerorAndProtectorService.getInstance().onLeaveMap(player);
MultiClientingService.onLeaveWorld(player);
InstanceService.onLogout(player);
GMService.getInstance().onPlayerLogout(player);
KiskService.getInstance().onLogout(player);
if (player.isDead()) {
if (player.isInInstance() || player.getWorldId() == 400030000)
PlayerReviveService.instanceRevive(player);
else
PlayerReviveService.bindRevive(player);
} else if (DuelService.getInstance().isDueling(player)) {
DuelService.getInstance().loseDuel(player);
}
player.getEffectController().removeNonStorableEffectsForLogout();
PlayerEffectsDAO.storePlayerEffects(player);
PlayerCooldownsDAO.storePlayerCooldowns(player);
ItemCooldownsDAO.storeItemCooldowns(player);
PlayerLifeStatsDAO.updatePlayerLifeStat(player);
PlayerGroupService.onPlayerLogout(player);
PlayerAllianceService.onPlayerLogout(player);
// fix legion warehouse exploits
LegionService.getInstance().LegionWhUpdate(player);
player.getEffectController().removeAllEffects(true);
player.getLifeStats().cancelAllTasks();
Summon summon = player.getSummon();
if (summon != null)
SummonsService.doMode(SummonMode.RELEASE, summon, UnsummonType.LOGOUT);
if (player.getPet() != null)
player.getPet().getController().delete();
if (player.getPostman() != null)
player.getPostman().getController().delete();
ExpireTimerTask.getInstance().unregisterExpirables(player);
if (player.getCraftingTask() != null)
player.getCraftingTask().stop();
if (player.isLegionMember())
LegionService.getInstance().onLogout(player);
QuestEngine.getInstance().onLogOut(new QuestEnv(null, player, 0));
Timestamp lastOnline = new Timestamp(System.currentTimeMillis());
player.getController().delete();
player.getCommonData().setOnline(false);
player.getCommonData().setLastOnline(lastOnline);
player.getCommonData().setX(player.getX());
player.getCommonData().setY(player.getY());
player.getCommonData().setZ(player.getZ());
player.getCommonData().setHeading(player.getHeading());
ChatServer.getInstance().sendPlayerLogout(player);
PlayerService.storePlayer(player);
player.getInventory().setOwner(null);
player.getWarehouse().setOwner(null);
player.getAccount().getAccountWarehouse().setOwner(null);
PlayerDAO.storeOldCharacterLevel(player.getObjectId(), player.getLevel());
PlayerDAO.storeLastOnlineTime(player.getObjectId(), lastOnline);
PlayerDAO.onlinePlayer(player, false); // marks that player was fully saved and may enter world again
con.setActivePlayer(null);
}
}