/*
* This file is part of aion-emu <aion-emu.com>.
*
* aion-emu 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.
*
* aion-emu 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 aion-emu. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aionemu.gameserver.services;
import java.sql.Timestamp;
import java.util.List;
import org.apache.log4j.Logger;
import com.aionemu.commons.database.dao.DAOManager;
import com.aionemu.gameserver.configs.main.CacheConfig;
import com.aionemu.gameserver.configs.main.GSConfig;
import com.aionemu.gameserver.controllers.FlyController;
import com.aionemu.gameserver.controllers.SummonController.UnsummonType;
import com.aionemu.gameserver.controllers.effect.PlayerEffectController;
import com.aionemu.gameserver.controllers.factory.ObjectControllerFactory;
import com.aionemu.gameserver.dao.AbyssRankDAO;
import com.aionemu.gameserver.dao.BlockListDAO;
import com.aionemu.gameserver.dao.FriendListDAO;
import com.aionemu.gameserver.dao.InventoryDAO;
import com.aionemu.gameserver.dao.ItemStoneListDAO;
import com.aionemu.gameserver.dao.MailDAO;
import com.aionemu.gameserver.dao.PlayerAppearanceDAO;
import com.aionemu.gameserver.dao.PlayerDAO;
import com.aionemu.gameserver.dao.PlayerMacrossesDAO;
import com.aionemu.gameserver.dao.PlayerPunishmentsDAO;
import com.aionemu.gameserver.dao.PlayerQuestListDAO;
import com.aionemu.gameserver.dao.PlayerRecipesDAO;
import com.aionemu.gameserver.dao.PlayerSettingsDAO;
import com.aionemu.gameserver.dao.PlayerSkillListDAO;
import com.aionemu.gameserver.dao.PlayerTitleListDAO;
import com.aionemu.gameserver.dataholders.PlayerInitialData;
import com.aionemu.gameserver.dataholders.PlayerStatsData;
import com.aionemu.gameserver.dataholders.PlayerInitialData.LocationData;
import com.aionemu.gameserver.dataholders.PlayerInitialData.PlayerCreationData;
import com.aionemu.gameserver.dataholders.PlayerInitialData.PlayerCreationData.ItemType;
import com.aionemu.gameserver.model.account.Account;
import com.aionemu.gameserver.model.account.PlayerAccountData;
import com.aionemu.gameserver.model.gameobjects.Item;
import com.aionemu.gameserver.model.gameobjects.PersistentState;
import com.aionemu.gameserver.model.gameobjects.player.Equipment;
import com.aionemu.gameserver.model.gameobjects.player.MacroList;
import com.aionemu.gameserver.model.gameobjects.player.Mailbox;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.player.PlayerAppearance;
import com.aionemu.gameserver.model.gameobjects.player.PlayerCommonData;
import com.aionemu.gameserver.model.gameobjects.player.Storage;
import com.aionemu.gameserver.model.gameobjects.player.StorageType;
import com.aionemu.gameserver.model.gameobjects.stats.PlayerGameStats;
import com.aionemu.gameserver.model.gameobjects.stats.PlayerLifeStats;
import com.aionemu.gameserver.model.gameobjects.stats.listeners.TitleChangeListener;
import com.aionemu.gameserver.model.items.ItemSlot;
import com.aionemu.gameserver.model.legion.LegionMember;
import com.aionemu.gameserver.model.templates.item.ItemTemplate;
import com.aionemu.gameserver.network.aion.AionConnection;
import com.aionemu.gameserver.network.aion.clientpackets.CM_ENTER_WORLD;
import com.aionemu.gameserver.network.aion.clientpackets.CM_QUIT;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.utils.collections.cachemap.CacheMap;
import com.aionemu.gameserver.utils.collections.cachemap.CacheMapFactory;
import com.aionemu.gameserver.world.KnownList;
import com.aionemu.gameserver.world.World;
import com.aionemu.gameserver.world.WorldPosition;
import com.google.inject.Inject;
/**
*
* This class is designed to do all the work related with loading/storing players.<br>
* Same with storing, {@link #storePlayer(com.aionemu.gameserver.model.gameobjects.player.Player)} stores all player
* data like appearance, items, etc...
*
* @author SoulKeeper, Saelya
*/
public class PlayerService
{
private static final Logger log = Logger.getLogger(PlayerService.class);
private CacheMap<Integer, Player> playerCache = CacheMapFactory.createSoftCacheMap("Player", "player");
private World world;
private ItemService itemService;
private LegionService legionService;
private TeleportService teleportService;
private ObjectControllerFactory controllerFactory;
private SkillLearnService skillLearnService;
private GroupService groupService;
private PunishmentService punishmentService;
private DuelService duelService;
private PlayerStatsData playerStatsData;
private PlayerInitialData playerInitialData;
private InstanceService instanceService;
@Inject
public PlayerService(World world, ItemService itemService,
LegionService legionService, TeleportService teleportService, ObjectControllerFactory controllerFactory,
SkillLearnService skillLearnService, GroupService groupService, PunishmentService punishmentService,
DuelService duelService, PlayerStatsData playerStatsData, PlayerInitialData playerInitialData,
InstanceService instanceService)
{
this.world = world;
this.itemService = itemService;
this.legionService = legionService;
this.teleportService = teleportService;
this.controllerFactory = controllerFactory;
this.skillLearnService = skillLearnService;
this.groupService = groupService;
this.punishmentService = punishmentService;
this.duelService = duelService;
this.playerStatsData = playerStatsData;
this.playerInitialData = playerInitialData;
this.instanceService = instanceService;
}
/**
* Checks if name is already taken or not
*
* @param name
* character name
* @return true if is free, false in other case
*/
public boolean isFreeName(String name)
{
return !DAOManager.getDAO(PlayerDAO.class).isNameUsed(name);
}
/**
* Checks if a name is valid. It should contain only english letters
*
* @param name
* character name
* @return true if name is valid, false overwise
*/
public boolean isValidName(String name)
{
return GSConfig.CHAR_NAME_PATTERN.matcher(name).matches();
}
/**
* Stores newly created player
*
* @param player
* player to store
* @return true if character was successful saved.
*/
public boolean storeNewPlayer(Player player, String accountName, int accountId)
{
return DAOManager.getDAO(PlayerDAO.class).saveNewPlayer(player.getCommonData(), accountId, accountName)
&& DAOManager.getDAO(PlayerAppearanceDAO.class).store(player)
&& DAOManager.getDAO(PlayerSkillListDAO.class).storeSkills(player)
&& DAOManager.getDAO(InventoryDAO.class).store(player)
&& DAOManager.getDAO(PlayerTitleListDAO.class).storeTitles(player);
}
/**
* Stores player data into db
*
* @param player
*/
public void storePlayer(Player player)
{
DAOManager.getDAO(PlayerDAO.class).storePlayer(player);
DAOManager.getDAO(PlayerSkillListDAO.class).storeSkills(player);
DAOManager.getDAO(PlayerSettingsDAO.class).saveSettings(player);
DAOManager.getDAO(PlayerQuestListDAO.class).store(player);
DAOManager.getDAO(PlayerTitleListDAO.class).storeTitles(player);
DAOManager.getDAO(AbyssRankDAO.class).storeAbyssRank(player);
DAOManager.getDAO(PlayerPunishmentsDAO.class).storePlayerPunishments(player);
DAOManager.getDAO(InventoryDAO.class).store(player);
DAOManager.getDAO(ItemStoneListDAO.class).save(player);
DAOManager.getDAO(MailDAO.class).storeMailbox(player);
}
/**
* Returns the player with given objId (if such player exists)
*
* @param playerObjId
* @param account
* @return Player
*/
public Player getPlayer(int playerObjId, Account account)
{
Player player = playerCache.get(playerObjId);
if(player != null)
return player;
/**
* Player common data and appearance should be already loaded in account
*/
PlayerAccountData playerAccountData = account.getPlayerAccountData(playerObjId);
PlayerCommonData pcd = playerAccountData.getPlayerCommonData();
PlayerAppearance appearance = playerAccountData.getAppereance();
player = new Player(controllerFactory.playerController(), pcd, appearance);
LegionMember legionMember = legionService.getLegionMember(player.getObjectId());
if(legionMember != null)
player.setLegionMember(legionMember);
if(groupService.isGroupMember(playerObjId))
groupService.setGroup(player);
MacroList macroses = DAOManager.getDAO(PlayerMacrossesDAO.class).restoreMacrosses(playerObjId);
player.setMacroList(macroses);
player.setSkillList(DAOManager.getDAO(PlayerSkillListDAO.class).loadSkillList(playerObjId));
player.setKnownlist(new KnownList(player));
player.setFriendList(DAOManager.getDAO(FriendListDAO.class).load(player, world, playerInitialData));
player.setBlockList(DAOManager.getDAO(BlockListDAO.class).load(player, world, playerInitialData));
player.setTitleList(DAOManager.getDAO(PlayerTitleListDAO.class).loadTitleList(playerObjId));
DAOManager.getDAO(PlayerSettingsDAO.class).loadSettings(player);
DAOManager.getDAO(AbyssRankDAO.class).loadAbyssRank(player);
player.setPlayerStatsTemplate(playerStatsData.getTemplate(player));
player.setGameStats(new PlayerGameStats(playerStatsData, player));
player.setLifeStats(new PlayerLifeStats(player, player.getPlayerStatsTemplate().getMaxHp(), player
.getPlayerStatsTemplate().getMaxMp()));
player.setEffectController(new PlayerEffectController(player));
player.setFlyController(new FlyController(player));
player.setQuestStateList(DAOManager.getDAO(PlayerQuestListDAO.class).load(player));
player.setRecipeList(DAOManager.getDAO(PlayerRecipesDAO.class).load(player.getObjectId()));
/**
* Equipment should be already loaded in account
*/
Equipment equipment = playerAccountData.getEquipment();
equipment.setOwner(player);
player.setEquipment(equipment);
/**
* Account warehouse should be already loaded in account
*/
Storage accWarehouse = account.getAccountWarehouse();
player.setStorage(accWarehouse, StorageType.ACCOUNT_WAREHOUSE);
/**
* Check CUBE storage in account and if missing - load
*/
Storage inventory = playerAccountData.getInventory();
if(inventory == null)
{
inventory = DAOManager.getDAO(InventoryDAO.class).loadStorage(player, StorageType.CUBE);
itemService.loadItemStones(inventory.getStorageItems());
}
player.setStorage(inventory, StorageType.CUBE);
/**
* Check WAREHOUSE storage in account and if missing - load
*/
Storage warehouse = playerAccountData.getWarehouse();
if(warehouse == null)
{
warehouse = DAOManager.getDAO(InventoryDAO.class).loadStorage(player, StorageType.REGULAR_WAREHOUSE);
itemService.loadItemStones(warehouse.getStorageItems());
}
player.setStorage(warehouse, StorageType.REGULAR_WAREHOUSE);
/**
* Apply equipment stats (items and manastones were loaded in account)
*/
player.getEquipment().onLoadApplyEquipmentStats();
DAOManager.getDAO(PlayerPunishmentsDAO.class).loadPlayerPunishments(player);
itemService.restoreKinah(player);
// update passive stats after effect controller, stats and equipment are initialized
player.getController().updatePassiveStats();
if(player.getCommonData().getTitleId() > 0)
{
TitleChangeListener.onTitleChange(player.getGameStats(), player.getCommonData().getTitleId(), true);
}
//analyze current instance
instanceService.onPlayerLogin(player);
if(CacheConfig.CACHE_PLAYERS)
playerCache.put(playerObjId, player);
return player;
}
/**
* This method is used for creating new players
*
* @param playerCommonData
* @param playerAppearance
* @return Player
*/
public Player newPlayer(PlayerCommonData playerCommonData, PlayerAppearance playerAppearance)
{
LocationData ld = playerInitialData.getSpawnLocation(playerCommonData.getRace());
WorldPosition position = world.createPosition(ld.getMapId(), ld.getX(), ld.getY(), ld.getZ(), ld.getHeading());
playerCommonData.setPosition(position);
Player newPlayer = new Player(controllerFactory.playerController(), playerCommonData, playerAppearance);
// Starting skills
skillLearnService.addNewSkills(newPlayer, true);
// Starting items
PlayerCreationData playerCreationData = playerInitialData.getPlayerCreationData(playerCommonData
.getPlayerClass());
List<ItemType> items = playerCreationData.getItems();
Storage playerInventory = new Storage(newPlayer, StorageType.CUBE);
Storage regularWarehouse = new Storage(newPlayer, StorageType.REGULAR_WAREHOUSE);
Storage accountWarehouse = new Storage(newPlayer, StorageType.ACCOUNT_WAREHOUSE);
Equipment equipment = new Equipment(newPlayer);
newPlayer.setStorage(playerInventory, StorageType.CUBE);
newPlayer.setStorage(regularWarehouse, StorageType.REGULAR_WAREHOUSE);
newPlayer.setStorage(accountWarehouse, StorageType.ACCOUNT_WAREHOUSE);
newPlayer.setEquipment(equipment);
newPlayer.setMailbox(new Mailbox());
for(ItemType itemType : items)
{
int itemId = itemType.getTemplate().getTemplateId();
Item item = itemService.newItem(itemId, itemType.getCount());
if(item == null)
continue;
// When creating new player - all equipment that has slot values will be equipped
// Make sure you will not put into xml file more items than possible to equip.
ItemTemplate itemTemplate = item.getItemTemplate();
if(itemTemplate.isArmor() || itemTemplate.isWeapon())
{
item.setEquipped(true);
List<ItemSlot> itemSlots = ItemSlot.getSlotsFor(itemTemplate.getItemSlot());
item.setEquipmentSlot(itemSlots.get(0).getSlotIdMask());
equipment.onLoadHandler(item);
}
else
playerInventory.onLoadHandler(item);
}
equipment.onLoadApplyEquipmentStats();
/**
* Mark inventory and equipment as UPDATE_REQUIRED to be saved during
* character creation
*/
playerInventory.setPersistentState(PersistentState.UPDATE_REQUIRED);
equipment.setPersistentState(PersistentState.UPDATE_REQUIRED);
return newPlayer;
}
/**
* This method is called just after player logged in to the game.<br>
* <br>
* <b><font color='red'>NOTICE: </font> This method called only from {@link CM_ENTER_WORLD} and must not be called
* from anywhere else.</b>
*
* @param player
*/
public void playerLoggedIn(Player player)
{
log.info("Player logged in: " + player.getName() + " Account: " + player.getClientConnection().getAccount().getName());
player.getCommonData().setOnline(true);
DAOManager.getDAO(PlayerDAO.class).onlinePlayer(player, true);
player.onLoggedIn();
}
/**
* This method is called when player leaves the game, which includes just two cases: either player goes back to char
* selection screen or it's leaving the game [closing client].<br>
* <br>
*
* <b><font color='red'>NOTICE: </font> This method is called only from {@link AionConnection} and {@link CM_QUIT}
* and must not be called from anywhere else</b>
*
* @param player
*/
public void playerLoggedOut(final Player player)
{
log.info("Player logged out: " + player.getName());
if(player.getClientConnection() == null)
{
log.warn("CHECKPOINT: Player already logged out " + player.getName());
return;
}
player.onLoggedOut();
player.getEffectController().removeAllEffects();
player.getLifeStats().cancelAllTasks();
if(player.getLifeStats().isAlreadyDead())
teleportService.moveToBindLocation(player, false);
if(duelService.isDueling(player.getObjectId()))
duelService.loseDuel(player);
//temp
if(player.getSummon() != null)
player.getSummon().getController().release(UnsummonType.LOGOUT);
punishmentService.stopPrisonTask(player, true);
player.getCommonData().setOnline(false);
player.getCommonData().setLastOnline(new Timestamp(System.currentTimeMillis()));
/**
* Store regular warehouse and cube storages in account data
*/
PlayerAccountData playerAccountData = player.getClientConnection().getAccount().getPlayerAccountData(player.getObjectId());
playerAccountData.setWarehouse(player.getWarehouse());
playerAccountData.setInventory(player.getInventory());
player.setClientConnection(null);
if(player.isLegionMember())
legionService.onLogout(player);
if(player.isInGroup())
groupService.scheduleRemove(player);
player.getController().delete();
DAOManager.getDAO(PlayerDAO.class).onlinePlayer(player, false);
storePlayer(player);
}
public void playerLoggedOutDelay(final Player player, int delay)
{
// force stop movement of player
player.getController().stopMoving();
ThreadPoolManager.getInstance().scheduleTaskManager(new Runnable(){
@Override
public void run()
{
playerLoggedOut(player);
}
}, delay);
}
/**
* Cancel Player deletion process if its possible.
*
* @param accData
* PlayerAccountData
*
* @return True if deletion was successful canceled.
*/
public boolean cancelPlayerDeletion(PlayerAccountData accData)
{
if(accData.getDeletionDate() == null)
return true;
if(accData.getDeletionDate().getTime() > System.currentTimeMillis())
{
accData.setDeletionDate(null);
storeDeletionTime(accData);
return true;
}
return false;
}
/**
* Starts player deletion process if its possible. If deletion is possible character should be deleted after 5
* minutes.
*
* @param accData
* PlayerAccountData
*/
public void deletePlayer(PlayerAccountData accData)
{
if(accData.getDeletionDate() != null)
return;
accData.setDeletionDate(new Timestamp(System.currentTimeMillis() + 5 * 60 * 1000));
storeDeletionTime(accData);
}
/**
* Completely removes player from database
*
* @param playerId
* id of player to delete from db
*/
void deletePlayerFromDB(int playerId)
{
DAOManager.getDAO(PlayerDAO.class).deletePlayer(playerId);
DAOManager.getDAO(InventoryDAO.class).deletePlayerItems(playerId);
}
/**
* Updates deletion time in database
*
* @param accData
* PlayerAccountData
*/
private void storeDeletionTime(PlayerAccountData accData)
{
DAOManager.getDAO(PlayerDAO.class).updateDeletionTime(accData.getPlayerCommonData().getPlayerObjId(),
accData.getDeletionDate());
}
/**
*
* @param objectId
* @param creationDate
*/
public void storeCreationTime(int objectId, Timestamp creationDate)
{
DAOManager.getDAO(PlayerDAO.class).storeCreationTime(objectId, creationDate);
}
/**
* Add macro for player
*
* @param player
* Player
* @param macroOrder
* Macro order
* @param macroXML
* Macro XML
*/
public void addMacro(Player player, int macroOrder, String macroXML)
{
if(player.getMacroList().addMacro(macroOrder, macroXML))
{
DAOManager.getDAO(PlayerMacrossesDAO.class).addMacro(player.getObjectId(), macroOrder, macroXML);
}
}
/**
* Remove macro with specified index from specified player
*
* @param player
* Player
* @param macroOrder
* Macro order index
*/
public void removeMacro(Player player, int macroOrder)
{
if(player.getMacroList().removeMacro(macroOrder))
{
DAOManager.getDAO(PlayerMacrossesDAO.class).deleteMacro(player.getObjectId(), macroOrder);
}
}
/**
* Gets a player ONLY if he is in the cache
*
* @return Player or null if not cached
*/
public Player getCachedPlayer(int playerObjectId)
{
return playerCache.get(playerObjectId);
}
/**
* @return the playerStatsData
*/
public PlayerStatsData getPlayerStatsData()
{
return playerStatsData;
}
/**
* @return the playerInitialData
*/
public PlayerInitialData getPlayerInitialData()
{
return playerInitialData;
}
}