Code: Select all
Index: java/config/l2jmods.properties===================================================================--- java/config/l2jmods.properties (revision 4)+++ java/config/l2jmods.properties (working copy)@@ -132,3 +132,18 @@ # ex.: 1;2;3;4;5;6 # no ";" at the start or end TvTEventDoorsCloseOpenOnStartEnd =++# ============================================================+# OFFLINE TRADE & CRAFT+# ============================================================+# Enable or Disable Offline Trade & Craft+AllowOfflineTrade = true+AllowOfflineCraft = true++# This option sets the target color+# Use true/false to enable color+# Default: none+OfflineTargetColor = true++# Requires OfflineTargetColor, Trade/Craft Configs enabled+OfflineColor = FF00FF\ No newline at end of fileIndex: java/net/sf/l2j/Config.java===================================================================--- java/net/sf/l2j/Config.java (revision 4)+++ java/net/sf/l2j/Config.java (working copy)@@ -882,6 +882,11 @@ public static boolean L2JMOD_WEDDING_FORMALWEAR; public static int L2JMOD_WEDDING_DIVORCE_COSTS; + public static boolean ALLOW_OFFLINE_TRADE;+ public static boolean ALLOW_OFFLINE_CRAFT;+ public static boolean OFFLINE_TARGET_COLOR;+ public static int OFFLINE_COLOR;+ // Packet information /** Count the amount of packets per minute ? */ public static boolean COUNT_PACKETS = false;@@ -1859,6 +1864,11 @@ L2JMOD_WEDDING_FORMALWEAR = Boolean.parseBoolean(L2JModSettings.getProperty("WeddingFormalWear", "True")); L2JMOD_WEDDING_DIVORCE_COSTS = Integer.parseInt(L2JModSettings.getProperty("WeddingDivorceCosts", "20")); + ALLOW_OFFLINE_TRADE = Boolean.parseBoolean(L2JModSettings.getProperty("AllowOfflineTrade", "false"));+ ALLOW_OFFLINE_CRAFT = Boolean.parseBoolean(L2JModSettings.getProperty("AllowOfflineCraft", "false"));+ OFFLINE_TARGET_COLOR = Boolean.parseBoolean(L2JModSettings.getProperty("OfflineTargetColor", "false"));+ OFFLINE_COLOR = Integer.decode("0x" + L2JModSettings.getProperty("OfflineColor", "FFFFFF"));+ if (TVT_EVENT_PARTICIPATION_NPC_ID == 0) { TVT_EVENT_ENABLED = false;Index: java/net/sf/l2j/gameserver/clientpackets/Logout.java===================================================================--- java/net/sf/l2j/gameserver/clientpackets/Logout.java (revision 4)+++ java/net/sf/l2j/gameserver/clientpackets/Logout.java (working copy)@@ -106,6 +106,13 @@ } TvTEvent.onLogout(player);+ + if ((player.isInStoreMode() && Config.ALLOW_OFFLINE_TRADE) || (player.isInCraftMode() && Config.ALLOW_OFFLINE_CRAFT))+ {+ player.closeNetConnection();+ return;+ }+ RegionBBSManager.getInstance().changeCommunityBoard(); player.deleteMe();Index: java/net/sf/l2j/gameserver/clientpackets/RequestJoinParty.java===================================================================--- java/net/sf/l2j/gameserver/clientpackets/RequestJoinParty.java (revision 4)+++ java/net/sf/l2j/gameserver/clientpackets/RequestJoinParty.java (working copy)@@ -96,6 +96,12 @@ return; } + if (target.getClient().isDetached())+ {+ requestor.sendMessage("Player is in offline mode.");+ return;+ }+ if (target.isInOlympiadMode() || requestor.isInOlympiadMode()) return; Index: java/net/sf/l2j/gameserver/clientpackets/Say2.java===================================================================--- java/net/sf/l2j/gameserver/clientpackets/Say2.java (revision 4)+++ java/net/sf/l2j/gameserver/clientpackets/Say2.java (working copy)@@ -166,6 +166,13 @@ if (receiver != null && !BlockList.isBlocked(receiver, activeChar)) {+ + if (receiver.getClient().isDetached())+ {+ activeChar.sendMessage("Player is in offline mode.");+ return;+ }+ if (Config.JAIL_DISABLE_CHAT && receiver.isInJail()) { activeChar.sendMessage("Player is in jail.");Index: java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminEditChar.java===================================================================--- java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminEditChar.java (revision 4)+++ java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminEditChar.java (working copy)@@ -34,6 +34,7 @@ import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance; import net.sf.l2j.gameserver.model.actor.instance.L2PetInstance; import net.sf.l2j.gameserver.model.base.ClassId;+import net.sf.l2j.gameserver.network.L2GameClient; import net.sf.l2j.gameserver.network.SystemMessageId; import net.sf.l2j.gameserver.serverpackets.CharInfo; import net.sf.l2j.gameserver.serverpackets.NpcHtmlMessage;@@ -658,10 +659,26 @@ */ private void findCharactersPerIp(L2PcInstance activeChar, String IpAdress) throws IllegalArgumentException {- if (!IpAdress.matches("^(?:(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))$"))- throw new IllegalArgumentException("Malformed IPv4 number");+ //if (!IpAdress.matches("^(?:(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))$"))+ // throw new IllegalArgumentException("Malformed IPv4 number");+ + boolean findDisconnected = false;++ if (IpAdress.equals("disconnected"))+ {+ findDisconnected = true;+ }+ else+ {+ if (!IpAdress.matches("^(?:(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))$"))+ throw new IllegalArgumentException("Malformed IPv4 number");+ }+ Collection<L2PcInstance> allPlayers = L2World.getInstance().getAllPlayers(); L2PcInstance[] players = allPlayers.toArray(new L2PcInstance[allPlayers.size()]);+ + L2GameClient client;+ int CharactersFound = 0; String name,ip="0.0.0.0"; TextBuilder replyMSG = new TextBuilder();@@ -669,13 +686,35 @@ adminReply.setFile("data/html/admin/ipfind.htm"); for (int i = 0; i < players.length; i++) {- ip=players[i].getClient().getConnection().getSocketChannel().socket().getInetAddress().getHostAddress();- if (ip.equals(IpAdress))- {- name = players[i].getName();- CharactersFound = CharactersFound+1;- replyMSG.append("<tr><td width=80><a action=\"bypass -h admin_character_list "+name+"\">"+name+"</a></td><td width=110>" + players[i].getTemplate().className + "</td><td width=40>"+players[i].getLevel()+"</td></tr>");+ //ip=players[i].getClient().getConnection().getSocketChannel().socket().getInetAddress().getHostAddress();+ //if (ip.equals(IpAdress))+ client = activeChar.getClient();+ if (client.isDetached()){+ //name = players[i].getName();+ //CharactersFound = CharactersFound+1;+ //replyMSG.append("<tr><td width=80><a action=\"bypass -h admin_character_list "+name+"\">"+name+"</a></td><td width=110>" + players[i].getTemplate().className + "</td><td width=40>"+players[i].getLevel()+"</td></tr>");+ if (!findDisconnected)+ {+ continue;+ } }+ else+ {+ if (findDisconnected)+ {+ continue;+ }+ else+ {+ ip=players[i].getClient().getConnection().getSocketChannel().socket().getInetAddress().getHostAddress();+ if (!ip.equals(IpAdress))+ continue;+ }+ }+ name = activeChar.getName();+ CharactersFound = CharactersFound + 1;+ replyMSG.append("<tr><td width=80><a action=\"bypass -h admin_character_list " + name + "\">" + name + "</a></td><td width=110>" + activeChar.getTemplate().className + "</td><td width=40>" + activeChar.getLevel() + "</td></tr>");+ if (CharactersFound > 20) break; }Index: java/net/sf/l2j/gameserver/model/L2ClanMember.java===================================================================--- java/net/sf/l2j/gameserver/model/L2ClanMember.java (revision 4)+++ java/net/sf/l2j/gameserver/model/L2ClanMember.java (working copy)@@ -120,7 +120,16 @@ public boolean isOnline() {- return _player != null;+ //return _player != null;+ if (_player == null)+ return false;+ if (_player.getClient() == null)+ return false;+ if (_player.getClient().isDetached())+ return false;+ + return true;+ } /**Index: java/net/sf/l2j/gameserver/model/actor/instance/L2PcInstance.java===================================================================--- java/net/sf/l2j/gameserver/model/actor/instance/L2PcInstance.java (revision 4)+++ java/net/sf/l2j/gameserver/model/actor/instance/L2PcInstance.java (working copy)@@ -3342,7 +3342,18 @@ { if (_client != null) {- _client.close(new LeaveWorld());+ //_client.close(new LeaveWorld());+ if (_client.isDetached())+ {+ _client.cleanMe(true);+ }+ else+ {+ if (!_client.getConnection().isClosed())+ {+ _client.close(new LeaveWorld());+ }+ } } } Index: java/net/sf/l2j/gameserver/network/L2GameClient.java===================================================================--- java/net/sf/l2j/gameserver/network/L2GameClient.java (revision 4)+++ java/net/sf/l2j/gameserver/network/L2GameClient.java (working copy)@@ -39,6 +39,7 @@ import net.sf.l2j.gameserver.model.L2World; import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance; import net.sf.l2j.gameserver.model.entity.L2Event;+import net.sf.l2j.gameserver.model.entity.TvTEvent; import net.sf.l2j.gameserver.serverpackets.L2GameServerPacket; import net.sf.l2j.gameserver.serverpackets.UserInfo; import net.sf.l2j.util.EventData;@@ -77,13 +78,16 @@ // Task protected /*final*/ ScheduledFuture _autoSaveInDB;-+ protected ScheduledFuture<?> _cleanupTask = null;+ // Crypt public GameCrypt crypt; // Flood protection public byte packetsSentInSec = 0; public int packetsSentStartTick = 0;+ + private boolean _isDetached = false; public L2GameClient(MMOConnection<L2GameClient> con) {@@ -179,9 +183,21 @@ public void sendPacket(L2GameServerPacket gsp) {+ if (_isDetached) return;+ getConnection().sendPacket(gsp); gsp.runImpl(); }+ + public boolean isDetached()+ {+ return _isDetached;+ }+ + public void isDetached(boolean b)+ {+ _isDetached = b;+ } public L2PcInstance markToDeleteChar(int charslot) throws Exception {@@ -225,6 +241,13 @@ return null; } + @Override+ public void closeNow()+ {+ super.getConnection().close(null);+ cleanMe(true);+ }+ public L2PcInstance deleteChar(int charslot) throws Exception { //have to make sure active character must be nulled@@ -518,17 +541,82 @@ } } - class DisconnectTask implements Runnable- {+ class DisconnectTask implements Runnable+ { - /**- * @see java.lang.Runnable#run()- */- public void run()- {- try- {- // Update BBS+ /**+ * @see java.lang.Runnable#run()+ */+ public void run()+ {+ boolean fast = true;++ try+ {+ isDetached(true);++ L2PcInstance player = L2GameClient.this.getActiveChar();+ if (player != null)+ {+ if (!player.isInOlympiadMode() && player.isInsidePeaceZone(player) && !player.isInDuel() &&+ !player.getParty().isInDimensionalRift() && !player.isFestivalParticipant() &&+ !player.atEvent && !player.isInJail())+ {+ if ((player.isInStoreMode() && Config.ALLOW_OFFLINE_TRADE) || (player.isInCraftMode() && Config.ALLOW_OFFLINE_CRAFT))+ {+ player.leaveParty();+ if (Config.OFFLINE_TARGET_COLOR)+ {+ player.getAppearance().setNameColor(Config.OFFLINE_COLOR);+ player.broadcastUserInfo();+ }+ + return;+ }+ }+ if (player.isInCombat())+ {+ fast = false;+ }+ }+ cleanMe(fast);+ }+ catch (Exception e1)+ {+ _log.warning("Error while disconnecting client.");+ }+ }+ }++ public void cleanMe(boolean fast)+ {+ try+ {+ synchronized(this)+ {+ if (_cleanupTask == null)+ {+ _cleanupTask = ThreadPoolManager.getInstance().scheduleGeneral(new CleanupTask(), fast ? 5 : 15000L);+ }+ }+ }+ catch (Exception e1)+ {+ _log.warning("Error during cleanup.");+ }+ }+++ class CleanupTask implements Runnable+ {+ /**+ * @see java.lang.Runnable#run()+ */+ public void run()+ {+ try+ {+ // Update BBS try { RegionBBSManager.getInstance().changeCommunityBoard();@@ -555,8 +643,14 @@ { player.removeSkill(SkillTable.getInstance().getInfo(4289, 1)); }- // notify the world about our disconnect- player.deleteMe();+ + // to prevent call cleanMe() again+ + if(isDetached()){+ isDetached(false);+ }else+ // notify the world about our disconnect+ player.deleteMe(); try {Index: java/net/sf/l2j/gameserver/network/L2GamePacketHandler.java===================================================================--- java/net/sf/l2j/gameserver/network/L2GamePacketHandler.java (revision 4)+++ java/net/sf/l2j/gameserver/network/L2GamePacketHandler.java (working copy)@@ -49,6 +49,9 @@ // implementation public ReceivablePacket<L2GameClient> handlePacket(ByteBuffer buf, L2GameClient client) {+ if (client.isDetached())+ return null;+ int opcode = buf.get() & 0xFF; ReceivablePacket<L2GameClient> msg = null;