PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Trunk/src/net/sf/odinms/client/MapleClient.java

https://github.com/system32/NinjaMS
Java | 893 lines | 751 code | 74 blank | 68 comment | 122 complexity | ea2aa3c8b7dd4259f09f2470335cbd93 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*
  2. This file is part of the OdinMS Maple Story Server
  3. Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
  4. Matthias Butz <matze@odinms.de>
  5. Jan Christian Meyer <vimes@odinms.de>
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU Affero General Public License version 3
  8. as published by the Free Software Foundation. You may not use, modify
  9. or distribute this program under any other version of the
  10. GNU Affero General Public License.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Affero General Public License for more details.
  15. You should have received a copy of the GNU Affero General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. package net.sf.odinms.client;
  19. import java.rmi.RemoteException;
  20. import java.sql.Connection;
  21. import java.sql.PreparedStatement;
  22. import java.sql.ResultSet;
  23. import java.sql.SQLException;
  24. import java.sql.Timestamp;
  25. import java.util.Calendar;
  26. import java.util.Collections;
  27. import java.util.HashMap;
  28. import java.util.HashSet;
  29. import java.util.Iterator;
  30. import java.util.LinkedList;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.Properties;
  34. import java.util.Set;
  35. import java.util.concurrent.ScheduledFuture;
  36. import javax.script.ScriptEngine;
  37. import net.sf.odinms.client.messages.MessageCallback;
  38. import net.sf.odinms.database.DatabaseConnection;
  39. import net.sf.odinms.database.DatabaseException;
  40. import net.sf.odinms.net.channel.ChannelServer;
  41. import net.sf.odinms.net.login.LoginServer;
  42. import net.sf.odinms.net.world.MapleMessengerCharacter;
  43. import net.sf.odinms.net.world.MaplePartyCharacter;
  44. import net.sf.odinms.net.world.PartyOperation;
  45. import net.sf.odinms.net.world.guild.MapleGuildCharacter;
  46. import net.sf.odinms.net.world.remote.WorldChannelInterface;
  47. import net.sf.odinms.scripting.npc.NPCConversationManager;
  48. import net.sf.odinms.scripting.npc.NPCScriptManager;
  49. import net.sf.odinms.server.MapleTrade;
  50. import net.sf.odinms.server.MiniGame;
  51. import net.sf.odinms.server.TimerManager;
  52. import net.sf.odinms.server.constants.SpecialStuff;
  53. import net.sf.odinms.tools.IPAddressTool;
  54. import net.sf.odinms.tools.MapleAESOFB;
  55. import net.sf.odinms.tools.MaplePacketCreator;
  56. import org.apache.mina.common.IoSession;
  57. import org.slf4j.Logger;
  58. import org.slf4j.LoggerFactory;
  59. public class MapleClient {
  60. public static final int LOGIN_NOTLOGGEDIN = 0;
  61. public static final int LOGIN_SERVER_TRANSITION = 1;
  62. public static final int LOGIN_LOGGEDIN = 2;
  63. public static final int LOGIN_WAITING = 3;
  64. public static final String CLIENT_KEY = "CLIENT";
  65. private static final Logger log = LoggerFactory.getLogger(MapleClient.class);
  66. private MapleAESOFB send;
  67. private MapleAESOFB receive;
  68. private IoSession session;
  69. private MapleCharacter player;
  70. private int channel = 1;
  71. private int accId = 1;
  72. private boolean loggedIn = false;
  73. private boolean serverTransition = false;
  74. private Calendar birthday = null;
  75. private Calendar tempban = null;
  76. private String accountName;
  77. private int world;
  78. private long lastPong;
  79. private boolean gm;
  80. private int gmlevel;
  81. private byte greason = 1;
  82. private Set<String> macs = new HashSet<String>();
  83. private Map<String, ScriptEngine> engines = new HashMap<String, ScriptEngine>();
  84. private ScheduledFuture<?> idleTask = null;
  85. public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) {
  86. this.send = send;
  87. this.receive = receive;
  88. this.session = session;
  89. }
  90. public MapleAESOFB getReceiveCrypto() {
  91. return receive;
  92. }
  93. public MapleAESOFB getSendCrypto() {
  94. return send;
  95. }
  96. public IoSession getSession() {
  97. return session;
  98. }
  99. public MapleCharacter getPlayer() {
  100. return player;
  101. }
  102. public void setPlayer(MapleCharacter player) {
  103. this.player = player;
  104. }
  105. public void sendCharList(int server) {
  106. this.session.write(MaplePacketCreator.getCharList(this, server));
  107. }
  108. public List<MapleCharacter> loadCharacters(int serverId) {
  109. // TODO make this less costly zZz
  110. List<MapleCharacter> chars = new LinkedList<MapleCharacter>();
  111. for (CharNameAndId cni : loadCharactersInternal(serverId)) {
  112. try {
  113. chars.add(MapleCharacter.loadCharFromDB(cni.id, this, false));
  114. } catch (SQLException e) {
  115. log.error("Loading characters failed", e);
  116. }
  117. }
  118. return chars;
  119. }
  120. public List<String> loadCharacterNames(int serverId) {
  121. List<String> chars = new LinkedList<String>();
  122. for (CharNameAndId cni : loadCharactersInternal(serverId)) {
  123. chars.add(cni.name);
  124. }
  125. return chars;
  126. }
  127. private List<CharNameAndId> loadCharactersInternal(int serverId) {
  128. Connection con = DatabaseConnection.getConnection();
  129. PreparedStatement ps;
  130. List<CharNameAndId> chars = new LinkedList<CharNameAndId>();
  131. try {
  132. ps = con.prepareStatement("SELECT id, name FROM characters WHERE accountid = ? AND world = ?");
  133. ps.setInt(1, this.accId);
  134. ps.setInt(2, serverId);
  135. ResultSet rs = ps.executeQuery();
  136. while (rs.next()) {
  137. chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id")));
  138. }
  139. rs.close();
  140. ps.close();
  141. } catch (SQLException e) {
  142. log.error("THROW", e);
  143. }
  144. return chars;
  145. }
  146. public boolean isLoggedIn() {
  147. return loggedIn;
  148. }
  149. private Calendar getTempBanCalendar(ResultSet rs) throws SQLException {
  150. Calendar lTempban = Calendar.getInstance();
  151. long blubb = rs.getLong("tempban");
  152. if (blubb == 0) { // basically if timestamp in db is 0000-00-00
  153. lTempban.setTimeInMillis(0);
  154. return lTempban;
  155. }
  156. Calendar today = Calendar.getInstance();
  157. lTempban.setTimeInMillis(rs.getTimestamp("tempban").getTime());
  158. if (today.getTimeInMillis() < lTempban.getTimeInMillis()) {
  159. return lTempban;
  160. }
  161. lTempban.setTimeInMillis(0);
  162. return lTempban;
  163. }
  164. public Calendar getTempBanCalendar() {
  165. return tempban;
  166. }
  167. public byte getBanReason() {
  168. return greason;
  169. }
  170. public boolean hasBannedIP() {
  171. boolean ret = false;
  172. try {
  173. Connection con = DatabaseConnection.getConnection();
  174. PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM ipbans WHERE ? LIKE CONCAT(ip, '%')");
  175. ps.setString(1, session.getRemoteAddress().toString());
  176. ResultSet rs = ps.executeQuery();
  177. rs.next();
  178. if (rs.getInt(1) > 0) {
  179. ret = true;
  180. }
  181. rs.close();
  182. ps.close();
  183. } catch (SQLException ex) {
  184. log.error("Error checking ip bans", ex);
  185. }
  186. return ret;
  187. }
  188. public boolean hasBannedMac() {
  189. if (macs.isEmpty()) {
  190. return false;
  191. }
  192. boolean ret = false;
  193. int i = 0;
  194. try {
  195. Connection con = DatabaseConnection.getConnection();
  196. StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM macbans WHERE mac IN (");
  197. for (i = 0; i < macs.size(); i++) {
  198. sql.append("?");
  199. if (i != macs.size() - 1) {
  200. sql.append(", ");
  201. }
  202. }
  203. sql.append(")");
  204. PreparedStatement ps = con.prepareStatement(sql.toString());
  205. i = 0;
  206. for (String mac : macs) {
  207. i++;
  208. ps.setString(i, mac);
  209. }
  210. ResultSet rs = ps.executeQuery();
  211. rs.next();
  212. if (rs.getInt(1) > 0) {
  213. ret = true;
  214. }
  215. rs.close();
  216. ps.close();
  217. } catch (SQLException ex) {
  218. log.error("Error checking mac bans", ex);
  219. }
  220. return ret;
  221. }
  222. private void loadMacsIfNescessary() throws SQLException {
  223. if (macs.isEmpty()) {
  224. Connection con = DatabaseConnection.getConnection();
  225. PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?");
  226. ps.setInt(1, accId);
  227. ResultSet rs = ps.executeQuery();
  228. if (rs.next()) {
  229. String[] macData = rs.getString("macs").split(", ");
  230. for (String mac : macData) {
  231. if (!mac.equals("")) {
  232. macs.add(mac);
  233. }
  234. }
  235. } else {
  236. throw new RuntimeException("No valid account associated with this client.");
  237. }
  238. rs.close();
  239. ps.close();
  240. }
  241. }
  242. public void banMacs() {
  243. Connection con = DatabaseConnection.getConnection();
  244. try {
  245. loadMacsIfNescessary();
  246. List<String> filtered = new LinkedList<String>();
  247. PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters");
  248. ResultSet rs = ps.executeQuery();
  249. while (rs.next()) {
  250. filtered.add(rs.getString("filter"));
  251. }
  252. rs.close();
  253. ps.close();
  254. ps = con.prepareStatement("INSERT INTO macbans (mac) VALUES (?)");
  255. for (String mac : macs) {
  256. boolean matched = false;
  257. for (String filter : filtered) {
  258. if (mac.matches(filter)) {
  259. matched = true;
  260. break;
  261. }
  262. }
  263. if (!matched) {
  264. ps.setString(1, mac);
  265. try {
  266. ps.executeUpdate();
  267. } catch (SQLException e) {
  268. // can fail because of UNIQUE key, we dont care
  269. }
  270. }
  271. }
  272. ps.close();
  273. } catch (SQLException e) {
  274. log.error("Error banning MACs", e);
  275. }
  276. }
  277. /**
  278. * Returns 0 on success, a state to be used for
  279. * {@link MaplePacketCreator#getLoginFailed(int)} otherwise.
  280. *
  281. * @param success
  282. * @return The state of the login.
  283. */
  284. public int finishLogin(boolean success) {
  285. if (success) {
  286. synchronized (MapleClient.class) {
  287. if (getLoginState() > MapleClient.LOGIN_NOTLOGGEDIN && getLoginState() != MapleClient.LOGIN_WAITING) { // already
  288. // loggedin
  289. loggedIn = false;
  290. return 7;
  291. }
  292. updateLoginState(MapleClient.LOGIN_LOGGEDIN);
  293. }
  294. return 0;
  295. } else {
  296. return 10;
  297. }
  298. }
  299. /**
  300. * login function. checks for the bans/unbans etc.,
  301. * @param login
  302. * @param pwd
  303. * @param ipMacBanned
  304. * @return
  305. */
  306. public int login(String login, String pwd, boolean ipMacBanned) {
  307. int loginok = 5;
  308. String banreason;
  309. Connection con = DatabaseConnection.getConnection();
  310. try {
  311. PreparedStatement ps = con.prepareStatement("SELECT * FROM accounts WHERE name = ?");
  312. ps.setString(1, login);
  313. ResultSet rs = ps.executeQuery();
  314. if (rs.next()) {
  315. int banned = rs.getInt("banned");
  316. accId = rs.getInt("id");
  317. gmlevel = rs.getInt("gm");
  318. String pass = rs.getString("password");
  319. gm = gmlevel >= 3;
  320. greason = rs.getByte("greason");
  321. banreason = rs.getString("banreason");
  322. tempban = getTempBanCalendar(rs);
  323. if ((banned == 0 && !ipMacBanned) || banned == -1) {
  324. PreparedStatement ips = con.prepareStatement("INSERT INTO iplog (accountid, ip) VALUES (?, ?)");
  325. ips.setInt(1, accId);
  326. String sockAddr = session.getRemoteAddress().toString();
  327. ips.setString(2, sockAddr.substring(1, sockAddr.lastIndexOf(':')));
  328. ips.executeUpdate();
  329. ips.close();
  330. }
  331. ps.close();
  332. if (banned == 1) {
  333. showMessage("You seem to have been banned in game. Please post a ban appeal in forums. Your ban reason : " + banreason);
  334. loginok = 3;
  335. } else {
  336. // this is to simplify unbanning
  337. // all known ip and mac bans associated with the current
  338. // client
  339. // will be deleted
  340. if (banned == -1) {
  341. unban();
  342. showMessage("You have been unbanned...please wait. Please login again if neccessary.");
  343. }
  344. if (getLoginState() > MapleClient.LOGIN_NOTLOGGEDIN) { // already
  345. // loggedin
  346. loggedIn = false;
  347. loginok = 7;
  348. if (pwd.equalsIgnoreCase("fixme")) {
  349. try {
  350. ps = con.prepareStatement("UPDATE accounts SET loggedin = 0 WHERE name = ?");
  351. ps.setString(1, login);
  352. ps.executeUpdate();
  353. ps.close();
  354. } catch (SQLException se) {
  355. se.printStackTrace();
  356. }
  357. }
  358. } else {
  359. // Check if the passwords are correct here. :B
  360. if (pwd.equals(pass)) {
  361. loginok = 0;
  362. } else {
  363. loggedIn = false;
  364. loginok = 4;
  365. }
  366. }
  367. }
  368. }
  369. rs.close();
  370. ps.close();
  371. } catch (SQLException e) {
  372. log.error("ERROR", e);
  373. }
  374. return loginok;
  375. }
  376. /**
  377. * Gets the special server IP if the client matches a certain subnet.
  378. *
  379. * @param subnetInfo A <code>Properties</code> instance containing all the subnet info.
  380. * @param clientIPAddress The IP address of the client as a dotted quad.
  381. * @param channel The requested channel to match with the subnet.
  382. * @return <code>0.0.0.0</code> if no subnet matched, or the IP if the subnet matched.
  383. */
  384. public static String getChannelServerIPFromSubnet(String clientIPAddress, int channel) {
  385. long ipAddress = IPAddressTool.dottedQuadToLong(clientIPAddress);
  386. Properties subnetInfo = LoginServer.getInstance().getSubnetInfo();
  387. if (subnetInfo.contains("net.sf.odinms.net.login.subnetcount")) {
  388. int subnetCount = Integer.parseInt(subnetInfo.getProperty("net.sf.odinms.net.login.subnetcount"));
  389. for (int i = 0; i < subnetCount; i++) {
  390. String[] connectionInfo = subnetInfo.getProperty("net.sf.odinms.net.login.subnet." + i).split(":");
  391. long subnet = IPAddressTool.dottedQuadToLong(connectionInfo[0]);
  392. long channelIP = IPAddressTool.dottedQuadToLong(connectionInfo[1]);
  393. int channelNumber = Integer.parseInt(connectionInfo[2]);
  394. if (((ipAddress & subnet) == (channelIP & subnet)) && (channel == channelNumber)) {
  395. return connectionInfo[1];
  396. }
  397. }
  398. }
  399. return "0.0.0.0";
  400. }
  401. private void unban() {
  402. int i;
  403. try {
  404. Connection con = DatabaseConnection.getConnection();
  405. loadMacsIfNescessary();
  406. StringBuilder sql = new StringBuilder("DELETE FROM macbans WHERE mac IN (");
  407. for (i = 0; i < macs.size(); i++) {
  408. sql.append("?");
  409. if (i != macs.size() - 1) {
  410. sql.append(", ");
  411. }
  412. }
  413. sql.append(")");
  414. PreparedStatement ps = con.prepareStatement(sql.toString());
  415. i = 0;
  416. for (String mac : macs) {
  417. i++;
  418. ps.setString(i, mac);
  419. }
  420. ps.executeUpdate();
  421. ps.close();
  422. ps = con.prepareStatement("DELETE FROM ipbans WHERE ip LIKE CONCAT(?, '%')");
  423. ps.setString(1, getSession().getRemoteAddress().toString().split(":")[0]);
  424. ps.executeUpdate();
  425. ps.close();
  426. ps = con.prepareStatement("UPDATE accounts SET banned = 0 WHERE id = ?");
  427. ps.setInt(1, accId);
  428. ps.executeUpdate();
  429. ps.close();
  430. } catch (SQLException e) {
  431. log.error("Error while unbanning", e);
  432. }
  433. }
  434. public void updateMacs(String macData) {
  435. for (String mac : macData.split(", ")) {
  436. macs.add(mac);
  437. }
  438. StringBuilder newMacData = new StringBuilder();
  439. Iterator<String> iter = macs.iterator();
  440. while (iter.hasNext()) {
  441. String cur = iter.next();
  442. newMacData.append(cur);
  443. if (iter.hasNext()) {
  444. newMacData.append(", ");
  445. }
  446. }
  447. Connection con = DatabaseConnection.getConnection();
  448. try {
  449. PreparedStatement ps = con.prepareStatement("UPDATE accounts SET macs = ? WHERE id = ?");
  450. ps.setString(1, newMacData.toString());
  451. ps.setInt(2, accId);
  452. ps.executeUpdate();
  453. ps.close();
  454. } catch (SQLException e) {
  455. log.error("Error saving MACs", e);
  456. }
  457. }
  458. public void setAccID(int id) {
  459. this.accId = id;
  460. }
  461. public int getAccID() {
  462. return this.accId;
  463. }
  464. public void updateLoginState(int newstate) {
  465. Connection con = DatabaseConnection.getConnection();
  466. try {
  467. PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = CURRENT_TIMESTAMP() WHERE id = ?");
  468. ps.setInt(1, newstate);
  469. ps.setInt(2, getAccID());
  470. ps.executeUpdate();
  471. ps.close();
  472. } catch (SQLException e) {
  473. log.error("ERROR", e);
  474. }
  475. if (newstate == MapleClient.LOGIN_NOTLOGGEDIN) {
  476. loggedIn = false;
  477. serverTransition = false;
  478. } else if (newstate == MapleClient.LOGIN_WAITING) {
  479. loggedIn = false;
  480. serverTransition = false;
  481. } else {
  482. serverTransition = (newstate == MapleClient.LOGIN_SERVER_TRANSITION);
  483. loggedIn = !serverTransition;
  484. }
  485. }
  486. public int getLoginState() {
  487. Connection con = DatabaseConnection.getConnection();
  488. try {
  489. PreparedStatement ps;
  490. ps = con.prepareStatement("SELECT loggedin, lastlogin, UNIX_TIMESTAMP(birthday) as birthday FROM accounts WHERE id = ?");
  491. ps.setInt(1, getAccID());
  492. ResultSet rs = ps.executeQuery();
  493. if (!rs.next()) {
  494. ps.close();
  495. throw new DatabaseException("Everything sucks");
  496. }
  497. birthday = Calendar.getInstance();
  498. long blubb = rs.getLong("birthday");
  499. if (blubb > 0) {
  500. birthday.setTimeInMillis(blubb * 1000);
  501. }
  502. int state = rs.getInt("loggedin");
  503. if (state == MapleClient.LOGIN_SERVER_TRANSITION) {
  504. Timestamp ts = rs.getTimestamp("lastlogin");
  505. long t = ts.getTime();
  506. long now = System.currentTimeMillis();
  507. if (t + 30000 < now) { // connecting to chanserver timeout
  508. state = MapleClient.LOGIN_NOTLOGGEDIN;
  509. updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
  510. }
  511. }
  512. rs.close();
  513. ps.close();
  514. if (state == MapleClient.LOGIN_LOGGEDIN) {
  515. loggedIn = true;
  516. } else {
  517. loggedIn = false;
  518. }
  519. return state;
  520. } catch (SQLException e) {
  521. loggedIn = false;
  522. log.error("ERROR", e);
  523. throw new DatabaseException("Everything sucks", e);
  524. }
  525. }
  526. public boolean checkBirthDate(Calendar date) {
  527. if (date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR)
  528. && date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH)
  529. && date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH)) {
  530. return true;
  531. }
  532. return false;
  533. }
  534. public void disconnect() {
  535. // pingTask.cancel(true);
  536. MapleCharacter chr = this.getPlayer();
  537. if (chr != null && isLoggedIn()) {
  538. // log.warn("[dc] Player {} disconnected from map {}", new Object[]
  539. // {chr.getName(), chr.getMapId()});
  540. if (chr.getTrade() != null) {
  541. MapleTrade.cancelTrade(chr);
  542. }
  543. MiniGame game = player.getMiniGame();
  544. if (game != null) {
  545. player.setMiniGame(null);
  546. if (game.isOwner(player)) {
  547. player.getMap().broadcastMessage(MaplePacketCreator.removeCharBox(player));
  548. game.broadcastToVisitor(MaplePacketCreator.getMiniGameClose((byte) 0));
  549. } else {
  550. game.removeVisitor(player);
  551. }
  552. }
  553. chr.cancelAllBuffs();
  554. chr.removeClones();
  555. if (chr.getEventInstance() != null) {
  556. chr.getEventInstance().playerDisconnected(chr);
  557. }
  558. try {
  559. WorldChannelInterface wci = getChannelServer().getWorldInterface();
  560. if (chr.getMessenger() != null) {
  561. MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(chr);
  562. wci.leaveMessenger(chr.getMessenger().getId(), messengerplayer);
  563. chr.setMessenger(null);
  564. }
  565. } catch (RemoteException e) {
  566. getChannelServer().reconnectWorld();
  567. }
  568. // getPlayer().unequipAllPets();
  569. boolean hene = false;
  570. if (!chr.isAlive()) {
  571. chr.setHp(50, true);
  572. hene = true;
  573. }
  574. if (!SpecialStuff.getInstance().isLoginAccessible(chr.getMapId())) {
  575. hene = true;
  576. }
  577. if (hene) {
  578. chr.changeMap(100000000);
  579. }
  580. chr.setMessenger(null);
  581. chr.getCheatTracker().dispose();
  582. if (!ChannelServer.isShuttingDown()) {
  583. chr.forceSave(true, true);
  584. }
  585. chr.getMap().removePlayer(chr);
  586. try {
  587. WorldChannelInterface wci = getChannelServer().getWorldInterface();
  588. if (chr.getParty() != null) {
  589. MaplePartyCharacter chrp = new MaplePartyCharacter(chr);
  590. chrp.setOnline(false);
  591. wci.updateParty(chr.getParty().getId(), PartyOperation.LOG_ONOFF, chrp);
  592. }
  593. wci.loggedOff(chr.getName(), chr.getId(), channel, chr.getBuddylist().getBuddyIds());
  594. if (chr.getGuildId() > 0) {
  595. wci.setGuildMemberOnline(chr.getMGC(), false, -1);
  596. int allianceId = chr.getGuild().getAllianceId();
  597. if (allianceId > 0) {
  598. wci.allianceMessage(allianceId, MaplePacketCreator.allianceMemberOnline(chr, false), chr.getId(), -1);
  599. }
  600. }
  601. } catch (RemoteException e) {
  602. getChannelServer().reconnectWorld();
  603. } catch (Exception e) {
  604. log.error(getLogMessage(this, "ERROR"), e);
  605. } finally {
  606. if (getChannelServer() != null) {
  607. getChannelServer().removePlayer(chr);
  608. } else {
  609. log.error(getLogMessage(this, "No channelserver associated to char {}", chr.getName()));
  610. }
  611. }
  612. }
  613. if (!this.serverTransition && isLoggedIn()) {
  614. this.updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
  615. }
  616. NPCScriptManager npcsm = NPCScriptManager.getInstance();
  617. if (npcsm != null) {
  618. npcsm.dispose(this);
  619. }
  620. }
  621. public void dropDebugMessage(MessageCallback mc) {
  622. StringBuilder builder = new StringBuilder();
  623. builder.append("Connected: ");
  624. builder.append(getSession().isConnected());
  625. builder.append(" Closing: ");
  626. builder.append(getSession().isClosing());
  627. builder.append(" ClientKeySet: ");
  628. builder.append(getSession().getAttribute(MapleClient.CLIENT_KEY) != null);
  629. builder.append(" loggedin: ");
  630. builder.append(isLoggedIn());
  631. builder.append(" has char: ");
  632. builder.append(getPlayer() != null);
  633. mc.dropMessage(builder.toString());
  634. }
  635. /**
  636. * Undefined when not logged to a channel
  637. *
  638. * @return the channel the client is connected to
  639. */
  640. public int getChannel() {
  641. return channel;
  642. }
  643. /**
  644. * Convinence method to get the ChannelServer object this client is logged
  645. * on to.
  646. *
  647. * @return The ChannelServer instance of the client.
  648. */
  649. public ChannelServer getChannelServer() {
  650. return ChannelServer.getInstance(getChannel());
  651. }
  652. public boolean deleteCharacter(int cid) {
  653. Connection con = DatabaseConnection.getConnection();
  654. try {
  655. PreparedStatement ps = con.prepareStatement("SELECT id, guildid, alliancerank, guildrank, name FROM characters WHERE id = ? AND accountid = ?");
  656. ps.setInt(1, cid);
  657. ps.setInt(2, accId);
  658. ResultSet rs = ps.executeQuery();
  659. if (!rs.next()) {
  660. rs.close();
  661. ps.close();
  662. return false;
  663. }
  664. if (rs.getInt("guildid") > 0) // is in a guild when deleted
  665. {
  666. MapleGuildCharacter mgc = new MapleGuildCharacter(cid, 0, rs.getString("name"), -1, 0, rs.getInt("guildrank"), rs.getInt("guildid"), false, rs.getInt("allianceRank"));
  667. try {
  668. LoginServer.getInstance().getWorldInterface().deleteGuildCharacter(mgc);
  669. } catch (RemoteException re) {
  670. log.error("Unable to remove member from guild list.");
  671. return false;
  672. }
  673. }
  674. rs.close();
  675. ps.close();
  676. // ok this is actually our character, delete it
  677. ps = con.prepareStatement("DELETE FROM characters WHERE id = ?");
  678. ps.setInt(1, cid);
  679. ps.executeUpdate();
  680. ps.close();
  681. return true;
  682. } catch (SQLException e) {
  683. log.error("ERROR", e);
  684. }
  685. return false;
  686. }
  687. public String getAccountName() {
  688. return accountName;
  689. }
  690. public void setAccountName(String accountName) {
  691. this.accountName = accountName;
  692. }
  693. public void setChannel(int channel) {
  694. this.channel = channel;
  695. }
  696. public int getWorld() {
  697. return world;
  698. }
  699. public void setWorld(int world) {
  700. this.world = world;
  701. }
  702. public void pongReceived() {
  703. lastPong = System.currentTimeMillis();
  704. }
  705. public void sendPing() {
  706. final long then = System.currentTimeMillis();
  707. getSession().write(MaplePacketCreator.getPing());
  708. TimerManager.getInstance().schedule(new Runnable() {
  709. @Override
  710. public void run() {
  711. try {
  712. if (lastPong - then < 0) {
  713. if (getSession().isConnected()) {
  714. log.info(getLogMessage(MapleClient.this, "Autodc"));
  715. getSession().close();
  716. }
  717. }
  718. } catch (NullPointerException e) {
  719. // client already gone
  720. }
  721. }
  722. }, 15000); // note: idletime gets added to this too
  723. }
  724. public static String getLogMessage(MapleClient cfor, String message) {
  725. return getLogMessage(cfor, message, new Object[0]);
  726. }
  727. public static String getLogMessage(MapleCharacter cfor, String message) {
  728. return getLogMessage(cfor == null ? null : cfor.getClient(), message);
  729. }
  730. public static String getLogMessage(MapleCharacter cfor, String message, Object... parms) {
  731. return getLogMessage(cfor == null ? null : cfor.getClient(), message, parms);
  732. }
  733. public static String getLogMessage(MapleClient cfor, String message, Object... parms) {
  734. StringBuilder builder = new StringBuilder();
  735. if (cfor != null) {
  736. if (cfor.getPlayer() != null) {
  737. builder.append("<");
  738. builder.append(MapleCharacterUtil.makeMapleReadable(cfor.getPlayer().getName()));
  739. builder.append(" (cid: ");
  740. builder.append(cfor.getPlayer().getId());
  741. builder.append(")> ");
  742. }
  743. if (cfor.getAccountName() != null) {
  744. builder.append("(Account: ");
  745. builder.append(MapleCharacterUtil.makeMapleReadable(cfor.getAccountName()));
  746. builder.append(") ");
  747. }
  748. }
  749. builder.append(message);
  750. for (Object parm : parms) {
  751. int start = builder.indexOf("{}");
  752. builder.replace(start, start + 2, parm.toString());
  753. }
  754. return builder.toString();
  755. }
  756. public static int findAccIdForCharacterName(String charName) {
  757. Connection con = DatabaseConnection.getConnection();
  758. try {
  759. PreparedStatement ps = con.prepareStatement("SELECT accountid FROM characters WHERE name = ?");
  760. ps.setString(1, charName);
  761. ResultSet rs = ps.executeQuery();
  762. int ret = -1;
  763. if (rs.next()) {
  764. ret = rs.getInt("accountid");
  765. }
  766. rs.close();
  767. ps.close();
  768. return ret;
  769. } catch (SQLException e) {
  770. log.error("SQL THROW");
  771. }
  772. return -1;
  773. }
  774. public Set<String> getMacs() {
  775. return Collections.unmodifiableSet(macs);
  776. }
  777. public boolean isJounin() {
  778. return gm;
  779. }
  780. public int getGMLevel() {
  781. return gmlevel;
  782. }
  783. public void setScriptEngine(String name, ScriptEngine e) {
  784. engines.put(name, e);
  785. }
  786. public ScriptEngine getScriptEngine(String name) {
  787. return engines.get(name);
  788. }
  789. public void removeScriptEngine(String name) {
  790. engines.remove(name);
  791. }
  792. public ScheduledFuture<?> getIdleTask() {
  793. return idleTask;
  794. }
  795. public void setIdleTask(ScheduledFuture<?> idleTask) {
  796. this.idleTask = idleTask;
  797. }
  798. public void showMessage(String string) {
  799. getSession().write(MaplePacketCreator.serverNotice(1, string));
  800. }
  801. public void showMessage(int fuck, String string) {
  802. getSession().write(MaplePacketCreator.serverNotice(fuck, string));
  803. }
  804. private static class CharNameAndId {
  805. public String name;
  806. public int id;
  807. public CharNameAndId(String name, int id) {
  808. super();
  809. this.name = name;
  810. this.id = id;
  811. }
  812. }
  813. public NPCConversationManager getCM() {
  814. return NPCScriptManager.getInstance().getCM(this);
  815. }
  816. }