Advertisement
Deedlit

My packet broadcaster (L2J)

Aug 30th, 2013
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 13.83 KB | None | 0 0
  1. /*
  2.  * This program is free software: you can redistribute it and/or modify it under
  3.  * the terms of the GNU General Public License as published by the Free Software
  4.  * Foundation, either version 3 of the License, or (at your option) any later
  5.  * version.
  6.  *
  7.  * This program is distributed in the hope that it will be useful, but WITHOUT
  8.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9.  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10.  * details.
  11.  *
  12.  * You should have received a copy of the GNU General Public License along with
  13.  * this program. If not, see <http://www.gnu.org/licenses/>.
  14.  */
  15. package com.l2jserver.gameserver.ext.manager;
  16.  
  17. import com.l2jserver.Config;
  18. import com.l2jserver.gameserver.GameServer;
  19. import com.l2jserver.gameserver.ThreadPoolManager;
  20. import com.l2jserver.gameserver.model.actor.L2Character;
  21. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  22. import com.l2jserver.gameserver.network.serverpackets.CharInfo;
  23. import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
  24. import com.l2jserver.gameserver.network.serverpackets.RelationChanged;
  25. import com.l2jserver.gameserver.network.serverpackets.StopRotation;
  26. import javolution.util.FastList;
  27.  
  28. import java.util.Collection;
  29. import java.util.logging.Level;
  30. import java.util.logging.Logger;
  31.  
  32. /**
  33.  * ==============================================<br>
  34.  * <b>PacketBroadcaster</b> - This manager, handles all server-client communication. <br>
  35.  * Be cautious, that if you are sending  to not send some packets in incorrect order<br>
  36.  * (eg. always send AbstractNpcInfo before MoveToLocation, if sending in burst).<br>
  37.  * ==============================================<br>
  38.  * @author Szponiasty(deedlit@lineage2-4fun.cc)
  39.  * @version 1.31.3
  40.  */
  41. public class PacketBroadcaster
  42. {
  43.     private static final Logger _log = Logger.getLogger(PacketBroadcaster.class.getName());
  44.  
  45.     private PacketBroadcaster()
  46.     {
  47.         //init
  48.         _log.log(Level.INFO, "PacketBroadcaster: initialization.");
  49.         // initialize packet queue broadcasting info
  50.         initPacketBroadcasterQueueInfo();
  51.     }
  52.  
  53.     // TODO: finish packet queueing support
  54.     private void initPacketBroadcasterQueueInfo()
  55.     {
  56.         _log.log(Level.INFO, "PacketBroadcaster: configuring queue support.");
  57.     }
  58.  
  59.     // TODO: finish packet queueing support
  60.     public boolean addPacketTypeQueueInfo(String packetClassName, int minDelayBetweenSendingPackets, int maxPacketsPerPackage, int delayBetweenSendingPackages)
  61.     {
  62.         /*
  63.  
  64.             Packet queuing:
  65.             ------------------
  66.             1) Instead of sending certain packets imediately, collect them in packet, and send in bursts specified by packet parameters.
  67.             2) Allow sending packets with min. delay, to avoid client flood and packet skipping
  68.             3) Allow determining how many packets can burst send contain, and min. delay between sending bursts
  69.             ------------------
  70.             Use: situations like teleportation, when player's knownlist is cleaned, and sometimes this causes freeze, as server sends DeleteObject packet for all known objects (300 and more).
  71.             The best would be, when each packet would contain queueing information within.
  72.  
  73.          */
  74.         return true;
  75.     }
  76.  
  77.     /**
  78.      * Send packet(s)
  79.      *
  80.      * @param to    packets receiver
  81.      * @param packets    list of packets(s) to be sent.
  82.      */
  83.     public void sendPackets(L2Character to, L2GameServerPacket... packets)
  84.     {
  85.         sendPackets(to, to, packets);
  86.     }
  87.  
  88.     /**
  89.      * Send packet(s)
  90.      *
  91.      * @param from  sender
  92.      * @param to    packets receiver
  93.      * @param packets    list of packets(s) to be sent.
  94.      */
  95.     public void sendPackets(L2Character from, L2Character to, L2GameServerPacket... packets)
  96.     {
  97.         scheduleSendPackets(from, to, 0, packets);
  98.     }
  99.  
  100.     /**
  101.      * Schedule packet(s) to send.
  102.      *
  103.      * @param to    packets receiver
  104.      * @param delayMs    delay (ms) for sending, or <=0 for no delay
  105.      * @param packets    list of packets(s) to be sent.
  106.      */
  107.     public void scheduleSendPackets(L2Character to, int delayMs, L2GameServerPacket... packets)
  108.     {
  109.         scheduleSendPackets(to, to, delayMs, packets);
  110.     }
  111.  
  112.     /**
  113.      * Schedule packet(s) to send.
  114.      *
  115.      * @param from  sender
  116.      * @param to    packets receiver
  117.      * @param delayMs    delay (ms) for sending, or <=0 for no delay
  118.      * @param packets    list of packets(s) to be sent.
  119.      */
  120.     public void scheduleSendPackets(L2Character from, L2Character to, int delayMs, L2GameServerPacket... packets)
  121.     {
  122.         // if server is booting up, or shutting down, abort
  123.         if (GameServer.serverStartingUp || GameServer.serverShuttingDown)
  124.             return;
  125.  
  126.         sendPacketTask sp = null;
  127.         // Note: I do not recommend using thread pool manager, to execute not scheduled packet tasks (some my small tests showed
  128.         // it might make all look better and eg movement smoother and more precise, but it utilizes 10x more CPU power, than running task
  129.         // without thread pool manager)
  130.         if (delayMs > 0 || Config.PACKET_PACKAGE_SENDING_USE_TASK)
  131.         {
  132.             sp = new sendPacketTask(from, to, delayMs > 0, packets);
  133.             if (delayMs > 0)
  134.                 ThreadPoolManager.getInstance().scheduleGeneral(sp, delayMs);
  135.         }
  136.  
  137.         // Packets are not scheduled to send later. Send them imediately.
  138.         if (delayMs <= 0)
  139.         {
  140.             if (sp != null)
  141.                 ThreadPoolManager.getInstance().executeTask(sp);
  142.             else
  143.             {
  144.                 for (final L2GameServerPacket p : packets)
  145.                 {
  146.                     if (p != null && to != null)
  147.                     {
  148.                         p.setSendToClientScheduled(false); // mark packet, when it was broadcasted/send by schedule, so we can react to it accordingly
  149.                         if (p.getFrom() == null) // if packet doesn't have origin set, set origin to provided one
  150.                             p.setFrom(from);
  151.                         to.sendPacket(p);
  152.                     }
  153.                 }
  154.             }
  155.         }
  156.     }
  157.  
  158.     /**
  159.      * Broadcast packet(s).
  160.      *
  161.      * @param from  broadcast origin
  162.      * @param mov    list of packets to be broadcasted
  163.      */
  164.     public final void broadcastPackets(L2Character from, L2GameServerPacket... mov)
  165.     {
  166.         broadcastPackets(from, -1, mov);
  167.     }
  168.  
  169.     /**
  170.      * Broadcast packet(s).
  171.      *
  172.      * @param from  broadcast origin
  173.      * @param force    true to force all packets to be sent, even if broadcaster is locked for sending them
  174.      * @param mov    list of packets to be broadcasted
  175.      */
  176.     public final void broadcastPackets(L2Character from, boolean force, L2GameServerPacket... mov)
  177.     {
  178.         broadcastPackets(from, -1, force, mov);
  179.     }
  180.  
  181.     /**
  182.      * Broadcast packet(s).
  183.      *
  184.      * @param from  broadcast origin
  185.      * @param radius    broadcast radius or -1 to broadcast to all known players
  186.      * @param mov    list of packets to be broadcasted
  187.      */
  188.     public final void broadcastPackets(L2Character from, int radius, L2GameServerPacket... mov)
  189.     {
  190.         broadcastPackets(from, radius, false, mov);
  191.     }
  192.  
  193.     /**
  194.      * Broadcast packet(s).
  195.      *
  196.      * @param from  broadcast origin
  197.      * @param radius    broadcast radius or -1 to broadcast to all known players
  198.      * @param force    true to force all packets to be sent, even if broadcaster is locked for sending them
  199.      * @param mov    list of packets to be broadcasted
  200.      */
  201.     public final void broadcastPackets(L2Character from, int radius, boolean force, L2GameServerPacket... mov)
  202.     {
  203.         scheduleBroadcastPackets(from, 0, radius, force, mov);
  204.     }
  205.  
  206.     /**
  207.      * Schedule broadcast of packet(s).
  208.      *
  209.      * @param from  broadcast origin
  210.      * @param delayMs    broadcast delay (ms), or <=0 for broadcast without delay
  211.      * @param mov    list of packets to be broadcasted
  212.      */
  213.     public final void scheduleBroadcastPackets(L2Character from, int delayMs, L2GameServerPacket... mov)
  214.     {
  215.         scheduleBroadcastPackets(from, delayMs, -1, false, mov);
  216.     }
  217.  
  218.     /**
  219.      * Schedule broadcast of packet(s).
  220.      *
  221.      * @param from  broadcast origin
  222.      * @param delayMs    broadcast delay (ms), or <=0 for broadcast without delay
  223.      * @param radius    broadcast radius or -1 to broadcast to all known players
  224.      * @param force    true to force all packets to be sent, even if broadcaster is locked for sending them
  225.      * @param mov    list of packets to be broadcasted
  226.      */
  227.     public final void scheduleBroadcastPackets(L2Character from, int delayMs, int radius, boolean force, L2GameServerPacket... mov)
  228.     {
  229.         if (GameServer.serverStartingUp || GameServer.serverShuttingDown)
  230.             return;
  231.  
  232.         final Collection<L2GameServerPacket> _toMyself = new FastList<L2GameServerPacket>(); // this is collection of packets that will be sent to broadcaster
  233.         final L2GameServerPacket[] copy = mov;
  234.  
  235.         /* First we deal with sending packets, to ourselves (broadcaster). This prevents many client side sync problems (especially for movement).
  236.             Then we broadcast to known characters within range or to whole knownlist. */
  237.         if (from.isPlayable())
  238.         {
  239.             // self
  240.             for (final L2GameServerPacket m : copy)
  241.             {
  242.                 if (m == null)
  243.                     continue;
  244.  
  245.                 m.setBroadcastedGlobally(true); // to determine if it's a public packet (eg. when generating chat logs for ServerStatService) - public packets can be sniffed/processed by StatInterface
  246.                 m.setFrom(from);
  247.                 if (from.isPlayable() && from.getActingPlayer() != null)
  248.                 {
  249.                     m.setInvisible(from.getActingPlayer().getAppearance().getInvisible());
  250.  
  251.                     // fix for fantasy island bench sitting workaround (without it, chars stand up and rotate in place, from time to time)
  252.                     if (m instanceof StopRotation && ((StopRotation) m).getObjId() == from.getObjectId() && from.getActingPlayer().isSitting())
  253.                         continue;
  254.                 }
  255.  
  256.                 // Skip if packet broadcast is locked, and not forced to send (or packet is not marked as always forced). Also, skip if character has been
  257.                 // thrown up, and is atm flying (to prevent breaking fly animation and "teleporting" character)
  258.                 if (from.isPacketBroadcastLocked() && (!force || from.isThrowedAndFlying()) && !m.isAlwaysForced())
  259.                     continue;
  260.  
  261.                 // If CharInfo packet or packet marked as not sendable to broadcaster, skip.
  262.                 if (!(m instanceof CharInfo) && m.canBeSendToMyself())
  263.                     _toMyself.add(m);
  264.             }
  265.  
  266.             // List of packets to send back to broadcaster ready? Then do it.
  267.             if (!_toMyself.isEmpty())
  268.                 scheduleSendPackets(from, from, delayMs, _toMyself.toArray(new L2GameServerPacket[_toMyself.size()]));
  269.         }
  270.  
  271.         final Collection<L2PcInstance> plrs = from.getKnownList().getKnownPlayersInRadius(radius);
  272.         for (final L2PcInstance player : plrs)
  273.         {
  274.             // Skip sending to self (we did that already), skip sending to not online clients.
  275.             if (player == null || player == from || player.isOnlineInt() != 1 /*|| player.isEnteringWorld()*/)
  276.                 continue;
  277.  
  278.             final FastList<L2GameServerPacket> _p = new FastList<L2GameServerPacket>();
  279.             for (final L2GameServerPacket m : copy)
  280.             {
  281.                 if (m == null)
  282.                     continue;
  283.  
  284.                 if (from.isPlayer() && from.getActingPlayer() != null)
  285.                 {
  286.                     // Fantasy island bench sitting workaround fix.
  287.                     if (m instanceof StopRotation && ((StopRotation) m).getObjId() == from.getObjectId() && from.getActingPlayer().isSitting())
  288.                         continue;
  289.                 }
  290.  
  291.                 // If broadcasting locked, or char is flying, skip.
  292.                 if (from.isPacketBroadcastLocked() && (!force || from.isThrowedAndFlying()) && !m.isAlwaysForced())
  293.                     continue;
  294.  
  295.                 _p.add(m);
  296.                 // If packet is CharInfo packet, then add RelationChanged packets to broadcast list, too.
  297.                 if (m instanceof CharInfo && from.isPlayer() && from.getActingPlayer() != null)
  298.                 {
  299.                     int relation = from.getActingPlayer().getRelation(player);
  300.                     final Integer oldrelation = from.getKnownList().getKnownRelations().get(player.getObjectId());
  301.                     if (oldrelation != null && oldrelation != relation)
  302.                     {
  303.                         final L2GameServerPacket r1 = new RelationChanged(from.getActingPlayer(), relation, from.isAutoAttackable(player));
  304.                         r1.setBroadcastedGlobally(m.isBroadcastedGlobally()); // to determine if it's a public packet (eg. when generating chat logs for ServerStatService) - public packets can be sniffed/processed by StatInterface
  305.                         r1.setFrom(m.getFrom());
  306.                         r1.setInvisible(m.isInvisible());
  307.                         _p.add(r1);
  308.                         if (from.getActingPlayer().getPet() != null)
  309.                         {
  310.                             final L2GameServerPacket r2 = new RelationChanged(from.getActingPlayer().getPet(), relation, from.isAutoAttackable(player));
  311.                             r2.setBroadcastedGlobally(m.isBroadcastedGlobally()); // to determine if it's a public packet (eg. when generating chat logs for ServerStatService) - public packets can be sniffed/processed by StatInterface
  312.                             r2.setFrom(m.getFrom());
  313.                             r2.setInvisible(m.isInvisible());
  314.                             _p.add(r2);
  315.                         }
  316.                     }
  317.                 }
  318.             }
  319.             // If there are packets to be sent, do it.
  320.             if (!_p.isEmpty())
  321.                 scheduleSendPackets(from, player, delayMs, _p.toArray(new L2GameServerPacket[_p.size()]));
  322.         }
  323.     }
  324.  
  325.     /**
  326.      * Packet send task.
  327.      */
  328.     private class sendPacketTask implements Runnable
  329.     {
  330.         private final L2Character _to, _from;
  331.         private final L2GameServerPacket[] _packets;
  332.         private final boolean _sync, _force, _scheduled;
  333.  
  334.         public sendPacketTask(L2Character from, L2Character to, boolean scheduled, L2GameServerPacket... packets)
  335.         {
  336.             this(from, to, scheduled, false, false, packets);
  337.         }
  338.  
  339.         public sendPacketTask(L2Character from, L2Character to, boolean scheduled, boolean sync, boolean force, L2GameServerPacket... packets)
  340.         {
  341.             _from = from;
  342.             _to = to;
  343.             _packets = packets;
  344.             _sync = sync;
  345.             _force = force;
  346.             _scheduled = scheduled;
  347.         }
  348.  
  349.         @Override
  350.         public void run()
  351.         {
  352.             if (_to != null && _packets != null && _packets.length > 0)
  353.             {
  354.                 for (final L2GameServerPacket p : _packets)
  355.                 {
  356.                     if (p != null && _to != null)
  357.                     {
  358.                         p.setSendToClientScheduled(_scheduled); // mark packet, when it was broadcasted/send by schedule, so we can react to it accordingly
  359.                         if (p.getFrom() == null) // if packet doesn't have origin set, set origin to provided one
  360.                             p.setFrom(_from);
  361.                         _to.sendPacket(p);
  362.                     }
  363.                 }
  364.             }
  365.         }
  366.     }
  367.  
  368.     private static PacketBroadcaster _PacketBroadcaster = new PacketBroadcaster();
  369.  
  370.     public static PacketBroadcaster getInstance()
  371.     {
  372.         return _PacketBroadcaster;
  373.     }
  374. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement