package client;
import client.messages.PlayerGMRank;
import constants.ServerConstants;
import database.DatabaseConnection;
import database.DatabaseException;
import handling.cashshop.CashShopServer;
import handling.channel.ChannelServer;
import handling.login.LoginServer;
import handling.world.PartyOperation;
import handling.world.WorldBuddyService;
import handling.world.WorldFindService;
import handling.world.WorldGuildService;
import handling.world.WorldMessengerService;
import handling.world.WorldSidekickService;
import handling.world.WrodlPartyService;
import handling.world.guild.MapleGuildCharacter;
import handling.world.messenger.MapleMessengerCharacter;
import handling.world.party.MapleParty;
import handling.world.party.MaplePartyCharacter;
import handling.world.sidekick.MapleSidekick;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.script.ScriptEngine;
import org.apache.log4j.Logger;
import org.apache.mina.core.session.IoSession;
import scripting.item.ItemActionManager;
import scripting.item.ItemScriptManager;
import scripting.npc.NPCConversationManager;
import scripting.npc.NPCScriptManager;
import scripting.quest.QuestActionManager;
import scripting.quest.QuestScriptManager;
import server.Timer.PingTimer;
import server.maps.MapleMap;
import server.quest.MapleQuest;
import server.shops.IMaplePlayerShop;
import tools.FileoutputUtil;
import tools.MapleAESOFB;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.packet.LoginPacket;
public class MapleClient implements Serializable {
private static final Logger log = Logger.getLogger(MapleClient.class);
private static final long serialVersionUID = 9179541993413738569L;
public static final byte LOGIN_NOTLOGGEDIN = 0;
public static final byte LOGIN_SERVER_TRANSITION = 1;
public static final byte LOGIN_LOGGEDIN = 2;
public static final byte CHANGE_CHANNEL = 3;
public static final byte ENTERING_PIN = 4; // 需要设置性别
public static final byte PIN_CORRECT = 5;
public static final int DEFAULT_CHARSLOT = LoginServer.getMaxCharacters();
public static final String CLIENT_KEY = "CLIENT";
private final transient MapleAESOFB send, receive;
private final transient IoSession session;
private long sessionId;
private MapleCharacter player;
private int channel = 1;
private int accId = -1;
private int world;
private int birthday;
private int charslots = DEFAULT_CHARSLOT;
private int cardslots = 3;
private boolean loggedIn = false;
private boolean serverTransition = false;
private transient Calendar tempban = null;
private String accountName;
private transient long lastPong = 0L;
private transient long lastPing = 0L;
private boolean monitored = false;
private boolean receiving = true;
private int gmLevel;
private byte greason = 1;
private byte gender = -1;
public transient short loginAttempt = 0;
private final transient List<Integer> allowedChar = new LinkedList();
private transient String mac = "00-00-00-00-00-00";
private final transient List<String> maclist = new LinkedList();
private final transient Map<String, ScriptEngine> engines = new HashMap();
private transient ScheduledFuture<?> idleTask = null;
private transient String secondPassword;
private transient String salt2;
private transient String tempIP = "";
private final transient Lock mutex = new ReentrantLock(true);
private final transient Lock npc_mutex = new ReentrantLock();
private long lastNpcClick = 0L;
private static final Lock login_mutex = new ReentrantLock(true);
private final byte loginattempt = 0;
private DebugWindow debugWindow;
private final Map<Integer, Pair<Short, Short>> charInfo = new LinkedHashMap();
public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) {
this.send = send;
this.receive = receive;
this.session = session;
}
public final MapleAESOFB getReceiveCrypto() {
return receive;
}
public final MapleAESOFB getSendCrypto() {
return send;
}
public final IoSession getSession() {
return session;
}
public long getSessionId() {
return this.sessionId;
}
public void setSessionId(long sessionId) {
this.sessionId = sessionId;
}
public void StartWindow() {
if (this.debugWindow != null) {
this.debugWindow.setVisible(false);
this.debugWindow = null;
}
this.debugWindow = new DebugWindow();
this.debugWindow.setVisible(true);
this.debugWindow.setC(this);
}
public Lock getLock() {
return this.mutex;
}
public Lock getNPCLock() {
return this.npc_mutex;
}
public MapleCharacter getPlayer() {
return this.player;
}
public void setPlayer(MapleCharacter player) {
this.player = player;
}
public void createdChar(int id) {
this.allowedChar.add(id);
}
public boolean login_Auth(int id) {
return this.allowedChar.contains(id);
}
public List<MapleCharacter> loadCharacters(int serverId) {
List chars = new LinkedList();
MapleCharacter chr;
for (CharNameAndId cni : loadCharactersInternal(serverId)) {
chr = MapleCharacter.loadCharFromDB(cni.id, this, false);
chars.add(chr);
charInfo.put(chr.getId(), new Pair(chr.getLevel(), chr.getJob()));
if (!login_Auth(chr.getId())) {
allowedChar.add(chr.getId());
}
}
return chars;
}
public boolean canMakeCharacter(int serverId) {
return loadCharactersSize(serverId) < getAccCharSlots();
}
public List<String> loadCharacterNames(int serverId) {
List chars = new LinkedList();
for (CharNameAndId cni : loadCharactersInternal(serverId)) {
chars.add(cni.name);
}
return chars;
}
private List<CharNameAndId> loadCharactersInternal(int serverId) {
List chars = new LinkedList();
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT id, name, gm FROM characters WHERE accountid = ? AND world = ?")) {
ps.setInt(1, this.accId);
ps.setInt(2, serverId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id")));
LoginServer.getLoginAuth(rs.getInt("id"));
}
}
ps.close();
} catch (SQLException e) {
log.error("error loading characters internal", e);
}
return chars;
}
private int loadCharactersSize(int serverId) {
int chars = 0;
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT count(*) FROM characters WHERE accountid = ? AND world = ?")) {
ps.setInt(1, this.accId);
ps.setInt(2, serverId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
chars = rs.getInt(1);
}
}
ps.close();
} catch (SQLException e) {
log.error("error loading characters internal", e);
}
return chars;
}
public boolean isLoggedIn() {
return loggedIn && accId > 0;
}
private Calendar getTempBanCalendar(ResultSet rs) throws SQLException {
Calendar lTempban = Calendar.getInstance();
if (rs.getLong("tempban") == 0L) {
lTempban.setTimeInMillis(0L);
return lTempban;
}
Calendar today = Calendar.getInstance();
lTempban.setTimeInMillis(rs.getTimestamp("tempban").getTime());
if (today.getTimeInMillis() < lTempban.getTimeInMillis()) {
return lTempban;
}
lTempban.setTimeInMillis(0L);
return lTempban;
}
public Calendar getTempBanCalendar() {
return this.tempban;
}
public byte getBanReason() {
return this.greason;
}
public boolean hasBannedMac() {
if ((this.mac.equalsIgnoreCase("00-00-00-00-00-00")) || (this.mac.length() != 17)) {
return false;
}
boolean ret = false;
return ret;
}
public int finishLogin() {
login_mutex.lock();
try {
if (getLoginState() > 0) {
this.loggedIn = false;
return 7;
}
updateLoginState(MapleClient.LOGIN_LOGGEDIN, getSessionIPAddress());
} finally {
login_mutex.unlock();
}
return 0;
}
public void clearInformation() {
accountName = null;
accId = -1;
secondPassword = null;
gmLevel = 0;
loggedIn = false;
mac = "00-00-00-00-00-00";
maclist.clear();
}
public int changePassword(String oldpwd, String newpwd) {
int ret = -1;
try {
Connection con = DatabaseConnection.getConnection();
ResultSet rs;
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM accounts WHERE name = ?")) {
ps.setString(1, getAccountName());
rs = ps.executeQuery();
if (rs.next()) {
boolean updatePassword = false;
String passhash = rs.getString("password");
String salt = rs.getString("salt");
if ((passhash == null) || (passhash.isEmpty())) {
ret = -1;
} else if ((LoginCryptoLegacy.isLegacyPassword(passhash)) && (LoginCryptoLegacy.checkPassword(oldpwd, passhash))) {
ret = 0;
updatePassword = true;
} else if (oldpwd.equals(passhash)) {
ret = 0;
updatePassword = true;
} else if ((salt == null) && (LoginCrypto.checkSha1Hash(passhash, oldpwd))) {
ret = 0;
updatePassword = true;
} else if (LoginCrypto.checkSaltedSha512Hash(passhash, oldpwd, salt)) {
ret = 0;
updatePassword = true;
} else {
ret = -1;
}
if (updatePassword) {
try (PreparedStatement pss = con.prepareStatement("UPDATE `accounts` SET `password` = ?, `salt` = ? WHERE id = ?")) {
String newSalt = LoginCrypto.makeSalt();
pss.setString(1, LoginCrypto.makeSaltedSha512Hash(newpwd, newSalt));
pss.setString(2, newSalt);
pss.setInt(3, this.accId);
pss.executeUpdate();
}
}
}
ps.close();
}
rs.close();
} catch (SQLException e) {
log.error("修改密码出错\r\n", e);
}
return ret;
}
/**
* 验证帐号密码
* @param login
* @param pwd
* @param ipMacBanned
* @return
*/
public int login(String login, String pwd) {
int loginok = 5;
pwd = LoginCrypto.hexSha1(pwd); // 用最简单的sha1
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM accounts WHERE name = ?")) {
ps.setString(1, login);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
final int banned = rs.getInt("banned");
final String passhash = rs.getString("password");
final String oldSession = rs.getString("SessionIP");
accountName = login;
accId = rs.getInt("id");
gmLevel = rs.getInt("gm");
greason = rs.getByte("greason");
tempban = getTempBanCalendar(rs);
gender = rs.getByte("gender");
if (banned > 0 && gmLevel < 6) {
loginok = 3;
} else {
if (banned == -1) {
unban();
}
// Check if the passwords are correct here. :B
if (passhash == null || passhash.isEmpty()) {
//match by sessionIP
if (oldSession != null && !oldSession.isEmpty()) {
loggedIn = getSessionIPAddress().equals(oldSession);
loginok = loggedIn ? 0 : 4;
} else {
loginok = 4;
loggedIn = false;
}
} else if (pwd.equals(passhash)) {
loginok = 0;
} else {
loggedIn = false;
loginok = 4;
}
if (getLoginState() > MapleClient.LOGIN_NOTLOGGEDIN) { // already loggedin
if (loginok != 0) {
loggedIn = false;
loginok = 7;
} else {//解卡处理
解卡账号();
}
}
}
}
}
ps.close();
}
} catch (SQLException e) {
System.err.println("登录出错:" + e);
}
return loginok;
}
public void 解卡账号() {
boolean 解卡在线 = false;
for (ChannelServer cserv : ChannelServer.getAllInstances()) {
for (final MapleCharacter mch : cserv.getPlayerStorage().getAllCharacters()) {
if (mch.getAccountID() == accId) {
try {
mch.getClient().getSession().write(MaplePacketCreator.serverMessagePopUp("当前账号在别的地方登录了\r\n若不是你本人操作请及时更改密码。"));
mch.getClient().disconnect(true, mch.getClient().getChannel() == -10);
Thread closeSession = new Thread() {
@Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException ex) {
}
mch.getClient().getSession().close(true);
}
};
closeSession.start();
} catch (Exception ex) {
}
解卡在线 = true;
}
}
}
if (!解卡在线) {
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = 0 WHERE name = ?")) {
ps.setString(1, accountName);
ps.executeUpdate();
ps.close();
}
} catch (SQLException se) {
}
}
}
private void unban() {
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("UPDATE accounts SET banned = 0, banreason = '' WHERE id = ?")) {
ps.setInt(1, this.accId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
log.error("Error while unbanning", e);
}
}
public static byte unban(String charname) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT accountid from characters where name = ?");
ps.setString(1, charname);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return -1;
}
int accid = rs.getInt(1);
rs.close();
ps.close();
ps = con.prepareStatement("UPDATE accounts SET banned = 0, banreason = '' WHERE id = ?");
ps.setInt(1, accid);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
log.error("Error while unbanning", e);
return -2;
}
return 0;
}
public void setAccID(int id) {
this.accId = id;
}
public int getAccID() {
return this.accId;
}
public void updateLoginState(int newstate) {
updateLoginState(newstate, getSessionIPAddress());
}
public void updateLoginState(int newstate, String SessionID) {
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("UPDATE accounts SET loggedin = ?, SessionIP = ?, lastlogin = CURRENT_TIMESTAMP() WHERE id = ?")) {
ps.setInt(1, newstate);
ps.setString(2, SessionID);
ps.setInt(3, getAccID());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
log.error("Error updating login state", e);
}
if (newstate == 0) {
this.loggedIn = false;
this.serverTransition = false;
} else {
this.serverTransition = ((newstate == 1) || (newstate == 3));
this.loggedIn = (!this.serverTransition);
}
}
public void updateSecondPassword() {
try {
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("UPDATE `accounts` SET `2ndpassword` = ?, `salt2` = ? WHERE id = ?")) {
String newSalt = LoginCrypto.makeSalt();
ps.setString(1, LoginCrypto.rand_s(LoginCrypto.makeSaltedSha512Hash(this.secondPassword, newSalt)));
ps.setString(2, newSalt);
ps.setInt(3, this.accId);
ps.executeUpdate();
ps.close();
}
} catch (SQLException e) {
log.error("Error updating login state", e);
}
}
public byte getLoginState() {
Connection con = DatabaseConnection.getConnection();
try {
byte state;
try (PreparedStatement ps = con.prepareStatement("SELECT loggedin, lastlogin, banned, gm, `birthday` + 0 AS `bday` FROM accounts WHERE id = ?")) {
ps.setInt(1, getAccID());
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next() || (rs.getInt("banned") > 0 && rs.getInt("gm") < 6)) {
ps.close();
rs.close();
session.close(true);
throw new DatabaseException("Account doesn't exist or is banned");
}
birthday = rs.getInt("bday");
state = rs.getByte("loggedin");
if ((state == MapleClient.LOGIN_SERVER_TRANSITION || state == MapleClient.CHANGE_CHANNEL) && (rs.getTimestamp("lastlogin").getTime() + 20000L < System.currentTimeMillis())) {
state = MapleClient.LOGIN_NOTLOGGEDIN;
updateLoginState(state, getSessionIPAddress());
}
}
ps.close();
}
loggedIn = state == MapleClient.LOGIN_LOGGEDIN;
return state;
} catch (SQLException e) {
loggedIn = false;
throw new DatabaseException("error getting login state", e);
}
}
public boolean checkBirthDate(int date) {
return this.birthday == date;
}
public void removalTask(boolean shutdown) {
try {
this.player.cancelAllBuffs_();
this.player.cancelAllDebuffs();
if (this.player.getMarriageId() > 0) {
MapleQuestStatus stat1 = this.player.getQuestNoAdd(MapleQuest.getInstance(160001));
MapleQuestStatus stat2 = this.player.getQuestNoAdd(MapleQuest.getInstance(160002));
if ((stat1 != null) && (stat1.getCustomData() != null) && ((stat1.getCustomData().equals("2_")) || (stat1.getCustomData().equals("2")))) {
if ((stat2 != null) && (stat2.getCustomData() != null)) {
stat2.setCustomData("0");
}
stat1.setCustomData("3");
}
}
if ((this.player.getMapId() == 180000001) && (!this.player.isIntern())) {
MapleQuestStatus stat1 = this.player.getQuestNAdd(MapleQuest.getInstance(123455));
MapleQuestStatus stat2 = this.player.getQuestNAdd(MapleQuest.getInstance(123456));
if (stat1.getCustomData() == null) {
stat1.setCustomData(String.valueOf(System.currentTimeMillis()));
} else if (stat2.getCustomData() == null) {
stat2.setCustomData("0");
} else {
int seconds = Integer.parseInt(stat2.getCustomData()) - (int) ((System.currentTimeMillis() - Long.parseLong(stat1.getCustomData())) / 1000L);
if (seconds < 0) {
seconds = 0;
}
stat2.setCustomData(String.valueOf(seconds));
}
}
this.player.changeRemoval(true);
if (this.player.getEventInstance() != null) {
this.player.getEventInstance().playerDisconnected(this.player, this.player.getId());
}
IMaplePlayerShop shop = this.player.getPlayerShop();
if (shop != null) {
shop.removeVisitor(this.player);
if (shop.isOwner(this.player)) {
if ((shop.getShopType() == 1) && (shop.isAvailable()) && (!shutdown)) {
shop.setOpen(true);
} else {
shop.closeShop(true, !shutdown);
}
}
}
this.player.setMessenger(null);
if (this.player.getMap() != null) {
if ((shutdown) || ((getChannelServer() != null) && (getChannelServer().isShutdown()))) {
int questID = -1;
switch (this.player.getMapId()) {
case 240060200:
questID = 160100;
break;
case 240060201:
questID = 160103;
break;
case 280030000:
case 280030100:
questID = 160101;
break;
case 280030001:
questID = 160102;
break;
case 270050100:
questID = 160104;
break;
case 105100300:
case 105100400:
questID = 160106;
break;
case 211070000:
case 211070100:
case 211070101:
case 211070110:
questID = 160107;
break;
case 551030200:
questID = 160108;
break;
case 271040100:
questID = 160109;
}
if (questID > 0) {
this.player.getQuestNAdd(MapleQuest.getInstance(questID)).setCustomData("0");
}
} else if (this.player.isAlive()) {
switch (this.player.getMapId()) {
case 220080001:
case 541010100:
case 541020800:
this.player.getMap().addDisconnected(this.player.getId());
}
}
this.player.getMap().removePlayer(this.player);
}
} catch (NumberFormatException e) {
FileoutputUtil.outputFileError(FileoutputUtil.Acc_Stuck, e);
}
}
public void disconnect(boolean RemoveInChannelServer, boolean fromCS) {
disconnect(RemoveInChannelServer, fromCS, false);
}
public void disconnect(boolean RemoveInChannelServer, boolean fromCS, boolean shutdown) {
if (this.debugWindow != null) {
this.debugWindow.setVisible(false);
this.debugWindow = null;
}
if (this.player != null) {
MapleMap map = player.getMap();
MapleParty party = player.getParty();
String namez = player.getName();
int idz = player.getId();
int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId();
int gid = player.getGuildId();
BuddyList bl = player.getBuddylist();
MaplePartyCharacter chrp = new MaplePartyCharacter(player);
MapleMessengerCharacter chrm = new MapleMessengerCharacter(player);
MapleGuildCharacter chrg = player.getMGC();
removalTask(shutdown);
LoginServer.getLoginAuth(player.getId());
player.saveToDB(true, fromCS);
if (shutdown) {
player = null;
receiving = false;
return;
}
if (!fromCS) {
ChannelServer ch = ChannelServer.getInstance(map == null ? channel : map.getChannel());
int chz = WorldFindService.getInstance().findChannel(idz);
if (chz < -1) {
disconnect(RemoveInChannelServer, true);
return;
}
try {
if ((chz == -1) || (ch == null) || (ch.isShutdown())) {
player = null;
return;
}
if (messengerid > 0) {
WorldMessengerService.getInstance().leaveMessenger(messengerid, chrm);
}
if (party != null) {
party.cancelAllPartyBuffsByChr(player.getId());
chrp.setOnline(false);
WrodlPartyService.getInstance().updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp);
if ((map != null) && (party.getLeader().getId() == idz)) {
MaplePartyCharacter lchr = null;
for (MaplePartyCharacter pchr : party.getMembers()) {
if ((pchr != null) && (map.getCharacterById(pchr.getId()) != null) && ((lchr == null) || (lchr.getLevel() < pchr.getLevel()))) {
lchr = pchr;
}
}
if (lchr != null) {
WrodlPartyService.getInstance().updateParty(party.getId(), PartyOperation.CHANGE_LEADER_DC, lchr);
}
}
}
if (bl != null) {
if (!serverTransition) {
WorldBuddyService.getInstance().loggedOff(namez, idz, channel, bl.getBuddyIds());
} else {
WorldBuddyService.getInstance().loggedOn(namez, idz, channel, bl.getBuddyIds());
}
}
if ((gid > 0) && (chrg != null)) {
WorldGuildService.getInstance().setGuildMemberOnline(chrg, false, -1);
}
} catch (Exception e) {
FileoutputUtil.outputFileError(FileoutputUtil.Acc_Stuck, e);
log.error(new StringBuilder().append(getLogMessage(this, "ERROR")).append(e).toString());
} finally {
if ((RemoveInChannelServer) && (ch != null)) {
ch.removePlayer(player);
}
player = null;
}
} else {
int ch = WorldFindService.getInstance().findChannel(idz);
if (ch > 0) {
disconnect(RemoveInChannelServer, false);
return;
}
try {
if (party != null) {
chrp.setOnline(false);
WrodlPartyService.getInstance().updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp);
}
if (!serverTransition) {
WorldBuddyService.getInstance().loggedOff(namez, idz, this.channel, bl.getBuddyIds());
} else {
WorldBuddyService.getInstance().loggedOn(namez, idz, this.channel, bl.getBuddyIds());
}
if ((gid > 0) && (chrg != null)) {
WorldGuildService.getInstance().setGuildMemberOnline(chrg, false, -1);
}
if (player != null) {
player.setMessenger(null);
}
} catch (Exception e) {
FileoutputUtil.outputFileError(FileoutputUtil.Acc_Stuck, e);
log.error(new StringBuilder().append(getLogMessage(this, "ERROR")).append(e).toString());
} finally {
if ((RemoveInChannelServer) && (ch > 0)) {
CashShopServer.getPlayerStorage().deregisterPlayer(player);
}
player = null;
}
}
}
if ((!this.serverTransition) && (isLoggedIn())) {
updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN, getLastIPAddress());
}
this.engines.clear();
}
public String getSessionIPAddress() {
return this.session.getRemoteAddress().toString().split(":")[0];
}
public boolean CheckIPAddress() {
if (this.accId < 0) {
return false;
}
try {
boolean canlogin;
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT SessionIP, banned FROM accounts WHERE id = ?")) {
ps.setInt(1, this.accId);
try (ResultSet rs = ps.executeQuery()) {
canlogin = false;
if (rs.next()) {
String sessionIP = rs.getString("SessionIP");
if (sessionIP != null) {
canlogin = getSessionIPAddress().equals(sessionIP.split(":")[0]);
}
if (rs.getInt("banned") > 0) {
canlogin = false;
}
}
}
ps.close();
}
return canlogin;
} catch (SQLException e) {
log.error("Failed in checking IP address for client.", e);
}
return true;
}
public String getLastIPAddress() {
String LastIP = "/0:0:0:0";
if (this.accId < 0) {
return LastIP;
}
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT SessionIP, banned FROM accounts WHERE id = ?")) {
ps.setInt(1, this.accId);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
LastIP = rs.getString("SessionIP");
}
}
ps.close();
return LastIP;
} catch (SQLException e) {
log.error("获取登录IP出错.", e);
}
return LastIP;
}
public void DebugMessage(StringBuilder sb) {
sb.append("IP: ");
sb.append(getSession().getRemoteAddress());
sb.append(" || 连接状态: ");
sb.append(getSession().isConnected());
sb.append(" || 正在关闭: ");
sb.append(getSession().isClosing());
sb.append(" || CLIENT: ");
sb.append(getSession().getAttribute("CLIENT") != null);
sb.append(" || 是否已登陆: ");
sb.append(isLoggedIn());
sb.append(" || 角色上线: ");
sb.append(getPlayer() != null);
}
public int getChannel() {
return this.channel;
}
public ChannelServer getChannelServer() {
return ChannelServer.getInstance(this.channel);
}
public int deleteCharacter(int cid) {
if (this.getPlayer() != null && this.getPlayer().getId() == cid) {
return 2;
}
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT guildid, guildrank, familyid, name FROM characters WHERE id = ? AND accountid = ?")) {
ps.setInt(1, cid);
ps.setInt(2, this.accId);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) {
rs.close();
ps.close();
return 1;
}
if (rs.getInt("guildid") > 0) {
if (rs.getInt("guildrank") == 1) {
rs.close();
ps.close();
return 1;
}
WorldGuildService.getInstance().deleteGuildCharacter(rs.getInt("guildid"), cid);
}
MapleSidekick sidekick = WorldSidekickService.getInstance().getSidekickByChr(cid);
if (sidekick != null) {
sidekick.eraseToDB();
}
}
ps.close();
}
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM characters WHERE id = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "UPDATE pokemon SET active = 0 WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM hiredmerch WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM mountdata WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM inventoryitems WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM famelog WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM famelog WHERE characterid_to = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM wishlist WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM buddies WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM buddies WHERE buddyid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM savedlocations WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM skills WHERE teachId = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM familiars WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM mountdata WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM queststatus WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM inventoryslot WHERE characterid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM bank WHERE charid = ?", cid);
MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM pqlog WHERE characterid = ?", cid);
return 0;
} catch (SQLException e) {
FileoutputUtil.outputFileError(FileoutputUtil.SQL_Ex_Log, e);
log.error("删除角色错误.", e);
}
return 1;
}
public byte getGender() {
return this.gender;
}
public void setGender(byte gender) {
this.gender = gender;
}
public void changeGender(byte gender) {
this.gender = gender;
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET gender = ? WHERE id = ?")) {
ps.setByte(1, gender);
ps.setInt(2, this.accId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
log.error("设置性别出错", e);
}
}
public String getSecondPassword() {
return this.secondPassword;
}
public void setSecondPassword(String secondPassword) {
this.secondPassword = secondPassword;
}
public String getAccountName() {
return this.accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public void setChannel(int channel) {
this.channel = channel;
}
public int getWorld() {
return this.world;
}
public void setWorld(int world) {
this.world = world;
}
public int getLatency() {
return (int) (this.lastPong - this.lastPing);
}
public long getLastPong() {
return this.lastPong;
}
public long getLastPing() {
return this.lastPing;
}
public void pongReceived() {
this.lastPong = System.currentTimeMillis();
}
public void sendPing() {
this.lastPing = System.currentTimeMillis();
getSession().write(LoginPacket.getPing());
PingTimer.getInstance().schedule(new Runnable() {
@Override
public void run() {
if (getLatency() < 0) {
disconnect(true, false);
if (getSession().isConnected()) {
FileoutputUtil.log(MapleClient.getLogMessage(MapleClient.this, "PING超时."));
getSession().close(true);
}
}
}
}, 15000L);
}
public static String getLogMessage(MapleClient cfor, String message) {
return getLogMessage(cfor, message, new Object[0]);
}
public static String getLogMessage(MapleCharacter cfor, String message) {
return getLogMessage(cfor == null ? null : cfor.getClient(), message);
}
public static String getLogMessage(MapleCharacter cfor, String message, Object[] parms) {
return getLogMessage(cfor == null ? null : cfor.getClient(), message, parms);
}
public static String getLogMessage(MapleClient cfor, String message, Object[] parms) {
StringBuilder builder = new StringBuilder();
if (cfor != null) {
if (cfor.getPlayer() != null) {
builder.append("<");
builder.append(MapleCharacterUtil.makeMapleReadable(cfor.getPlayer().getName()));
builder.append(" (角色ID: ");
builder.append(cfor.getPlayer().getId());
builder.append(")> ");
}
if (cfor.getAccountName() != null) {
builder.append("(账号: ");
builder.append(cfor.getAccountName());
builder.append(") ");
}
}
builder.append(message);
for (Object parm : parms) {
int start = builder.indexOf("{}");
builder.replace(start, start + 2, parm.toString());
}
return builder.toString();
}
public static int findAccIdForCharacterName(String charName) {
try {
Connection con = DatabaseConnection.getConnection();
int ret;
try (PreparedStatement ps = con.prepareStatement("SELECT accountid FROM characters WHERE name = ?")) {
ps.setString(1, charName);
try (ResultSet rs = ps.executeQuery()) {
ret = -1;
if (rs.next()) {
ret = rs.getInt("accountid");
}
}
ps.close();
}
return ret;
} catch (SQLException e) {
log.error("findAccIdForCharacterName SQL error", e);
}
return -1;
}
public boolean isSuperGM() {
return this.gmLevel >= PlayerGMRank.SUPERGM.getLevel();
}
public boolean isIntern() {
return this.gmLevel >= PlayerGMRank.INTERN.getLevel();
}
public boolean isGm() {
return this.gmLevel >= PlayerGMRank.GM.getLevel();
}
public boolean isAdmin() {
return this.gmLevel >= PlayerGMRank.ADMIN.getLevel();
}
public int getGmLevel() {
return gmLevel;
}
public final void setGm(int gmLevel) {
this.gmLevel = gmLevel;
}
public ScheduledFuture<?> getIdleTask() {
return this.idleTask;
}
public void setIdleTask(ScheduledFuture<?> idleTask) {
this.idleTask = idleTask;
}
public int getAccCharSlots() {
if (isGm()) {
return 30;
}
if (this.charslots != DEFAULT_CHARSLOT) {
return this.charslots;
}
int theworld = world;
if (player != null) {
theworld = this.player.getWorld();
}
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM character_slots WHERE accid = ? AND worldid = ?")) {
ps.setInt(1, this.accId);
ps.setInt(2, theworld);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
this.charslots = rs.getInt("charslots");
} else {
try (PreparedStatement psu = con.prepareStatement("INSERT INTO character_slots (accid, worldid, charslots) VALUES (?, ?, ?)")) {
psu.setInt(1, this.accId);
psu.setInt(2, this.world);
psu.setInt(3, this.charslots);
psu.executeUpdate();
psu.close();
}
}
}
ps.close();
}
} catch (SQLException e) {
log.error("getAccCharSlots出错", e);
}
return this.charslots;
}
public boolean gainAccCharSlot() {
if (getAccCharSlots() >= 30) {
return false;
}
this.charslots++;
int theworld = world;
if (player != null) {
theworld = this.player.getWorld();
}
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE character_slots SET charslots = ? WHERE worldid = ? AND accid = ?")) {
ps.setInt(1, this.charslots);
ps.setInt(2, theworld);
ps.setInt(3, this.accId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
log.error("gainAccCharSlot出错", e);
return false;
}
return true;
}
public int getAccCardSlots() {
Connection con = DatabaseConnection.getConnection();
int theworld = world;
if (player != null) {
theworld = this.player.getWorld();
}
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM accounts_info WHERE accId = ? AND worldId = ?")) {
ps.setInt(1, this.accId);
ps.setInt(2, theworld);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
this.cardslots = rs.getInt("cardSlots");
} else {
try (PreparedStatement psu = con.prepareStatement("INSERT INTO accounts_info (accId, worldId, cardSlots) VALUES (?, ?, ?)")) {
psu.setInt(1, this.accId);
psu.setInt(2, this.world);
psu.setInt(3, this.cardslots);
psu.executeUpdate();
psu.close();
}
}
}
ps.close();
} catch (SQLException e) {
log.error("getAccCardSlots出错", e);
}
return this.cardslots;
}
public boolean gainAccCardSlot() {
if (getAccCardSlots() >= 9) {
return false;
}
this.cardslots++;
int theworld = world;
if (player != null) {
theworld = this.player.getWorld();
}
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts_info SET cardSlots = ? WHERE worldId = ? AND accId = ?")) {
ps.setInt(1, this.cardslots);
ps.setInt(2, theworld);
ps.setInt(3, this.accId);
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
log.error("gainAccCardSlot出错", e);
return false;
}
return true;
}
public static byte unbanIPMacs(String charname) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT accountid from characters where name = ?");
ps.setString(1, charname);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return -1;
}
int accid = rs.getInt(1);
rs.close();
ps.close();
ps = con.prepareStatement("SELECT * FROM accounts WHERE id = ?");
ps.setInt(1, accid);
rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return -1;
}
String sessionIP = rs.getString("sessionIP");
String macs = rs.getString("macs");
rs.close();
ps.close();
byte ret = 0;
return ret;
} catch (SQLException e) {
log.error("Error while unbanning", e);
}
return -2;
}
public static byte unHellban(String charname) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT accountid from characters where name = ?");
ps.setString(1, charname);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return -1;
}
int accid = rs.getInt(1);
rs.close();
ps.close();
ps = con.prepareStatement("SELECT * FROM accounts WHERE id = ?");
ps.setInt(1, accid);
rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return -1;
}
String sessionIP = rs.getString("sessionIP");
String email = rs.getString("email");
rs.close();
ps.close();
ps = con.prepareStatement(new StringBuilder().append("UPDATE accounts SET banned = 0, banreason = '' WHERE email = ?").append(sessionIP == null ? "" : " OR sessionIP = ?").toString());
ps.setString(1, email);
if (sessionIP != null) {
ps.setString(2, sessionIP);
}
ps.execute();
ps.close();
return 0;
} catch (SQLException e) {
log.error("Error while unbanning", e);
}
return -2;
}
public boolean isMonitored() {
return this.monitored;
}
public void setMonitored(boolean m) {
this.monitored = m;
}
public boolean isReceiving() {
return this.receiving;
}
public void setReceiving(boolean m) {
this.receiving = m;
}
public Timestamp getCreated() {
try {
Timestamp ret;
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT createdat FROM accounts WHERE id = ?")) {
ps.setInt(1, getAccID());
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) {
rs.close();
ps.close();
return null;
}
ret = rs.getTimestamp("createdat");
}
ps.close();
}
return ret;
} catch (SQLException e) {
throw new DatabaseException("error getting create", e);
}
}
public String getTempIP() {
return this.tempIP;
}
public void setTempIP(String s) {
this.tempIP = s;
}
public boolean isLocalhost() {
return (ServerConstants.USE_LOCALHOST) || (ServerConstants.isIPLocalhost(getSessionIPAddress()));
}
// public boolean hasCheck(int accid) {
// boolean ret = false;
// try {
// PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT * FROM accounts WHERE id = ?");
// ps.setInt(1, accid);
// ResultSet rs = ps.executeQuery();
// if (rs.next()) {
// ret = rs.getInt("check") > 0;
// }
// rs.close();
// ps.close();
// } catch (SQLException ex) {
// log.error("Error checking ip Check", ex);
// }
// return ret;
// }
public static String getAccInfo(String accname, boolean admin) {
StringBuilder ret = new StringBuilder(new StringBuilder().append("账号ID:").append(accname).append(" 信息-").toString());
try {
try (PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT * FROM accounts WHERE name = ?")) {
ps.setString(1, accname);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
int banned = rs.getInt("banned");
ret.append("封号状态:");
ret.append(banned > 0 ? "被封" : "没有被封");
ret.append("封号理由:");
ret.append(banned > 0 ? rs.getString("banreason") : "(没有封号)");
if (admin) {
ret.append("点券:");
ret.append(rs.getInt("ACash"));
ret.append("抵用券:");
ret.append(rs.getInt("mPoints"));
}
}
}
ps.close();
}
} catch (SQLException ex) {
log.error("获取玩家封号理由信息出错:", ex);
}
return ret.toString();
}
public static String getAccInfoByName(String charname, boolean admin) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT accountid from characters where name = ?");
ps.setString(1, charname);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return null;
}
int accid = rs.getInt(1);
rs.close();
ps.close();
ps = con.prepareStatement("SELECT * FROM accounts WHERE id = ?");
ps.setInt(1, accid);
rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return null;
}
StringBuilder ret = new StringBuilder("玩家 " + charname + " 的帐号信息 -");
int banned = rs.getInt("banned");
if (admin) {
ret.append(" 账号: ");
ret.append(rs.getString("name"));
}
ret.append(" 状态: ");
ret.append(banned > 0 ? "已封" : "正常");
ret.append(" 封号理由: ");
ret.append(banned > 0 ? rs.getString("banreason") : "(无描述)");
rs.close();
ps.close();
return ret.toString();
} catch (SQLException ex) {
log.error("获取玩家封号理由信息出错", ex);
}
return null;
}
public void setScriptEngine(String name, ScriptEngine e) {
this.engines.put(name, e);
}
public ScriptEngine getScriptEngine(String name) {
return (ScriptEngine) this.engines.get(name);
}
public void removeScriptEngine(String name) {
this.engines.remove(name);
}
public boolean canClickNPC() {
return this.lastNpcClick + 500L < System.currentTimeMillis();
}
public void setClickedNPC() {
this.lastNpcClick = System.currentTimeMillis();
}
public void removeClickedNPC() {
this.lastNpcClick = 0L;
}
public NPCConversationManager getCM() {
return NPCScriptManager.getInstance().getCM(this);
}
public QuestActionManager getQM() {
return QuestScriptManager.getInstance().getQM(this);
}
public ItemActionManager getIM() {
return ItemScriptManager.getInstance().getIM(this);
}
public boolean hasCheckMac(String macData) {
if ((macData.equalsIgnoreCase("00-00-00-00-00-00")) || (macData.length() != 17) || (this.maclist.isEmpty())) {
return false;
}
return this.maclist.contains(macData);
}
public boolean isAccountNameUsed(String accountName){
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT id from accounts where name = ?");
ps.setString(1, accountName);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return false;
}
} catch (SQLException ex) {
log.error("获取玩家封号理由信息出错", ex);
return true;
}
return true;
}
protected static class CharNameAndId {
public final String name;
public final int id;
public CharNameAndId(String name, int id) {
this.name = name;
this.id = id;
}
}
}