Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package com.l2jserver.gameserver.ext.manager;
- import com.l2jserver.Config;
- import com.l2jserver.gameserver.GameServer;
- import com.l2jserver.gameserver.ThreadPoolManager;
- import com.l2jserver.gameserver.model.actor.L2Character;
- import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
- import com.l2jserver.gameserver.network.serverpackets.CharInfo;
- import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
- import com.l2jserver.gameserver.network.serverpackets.RelationChanged;
- import com.l2jserver.gameserver.network.serverpackets.StopRotation;
- import javolution.util.FastList;
- import java.util.Collection;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- /**
- * ==============================================<br>
- * <b>PacketBroadcaster</b> - This manager, handles all server-client communication. <br>
- * Be cautious, that if you are sending to not send some packets in incorrect order<br>
- * (eg. always send AbstractNpcInfo before MoveToLocation, if sending in burst).<br>
- * ==============================================<br>
- * @author Szponiasty(deedlit@lineage2-4fun.cc)
- * @version 1.31.3
- */
- public class PacketBroadcaster
- {
- private static final Logger _log = Logger.getLogger(PacketBroadcaster.class.getName());
- private PacketBroadcaster()
- {
- //init
- _log.log(Level.INFO, "PacketBroadcaster: initialization.");
- // initialize packet queue broadcasting info
- initPacketBroadcasterQueueInfo();
- }
- // TODO: finish packet queueing support
- private void initPacketBroadcasterQueueInfo()
- {
- _log.log(Level.INFO, "PacketBroadcaster: configuring queue support.");
- }
- // TODO: finish packet queueing support
- public boolean addPacketTypeQueueInfo(String packetClassName, int minDelayBetweenSendingPackets, int maxPacketsPerPackage, int delayBetweenSendingPackages)
- {
- /*
- Packet queuing:
- ------------------
- 1) Instead of sending certain packets imediately, collect them in packet, and send in bursts specified by packet parameters.
- 2) Allow sending packets with min. delay, to avoid client flood and packet skipping
- 3) Allow determining how many packets can burst send contain, and min. delay between sending bursts
- ------------------
- 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).
- The best would be, when each packet would contain queueing information within.
- */
- return true;
- }
- /**
- * Send packet(s)
- *
- * @param to packets receiver
- * @param packets list of packets(s) to be sent.
- */
- public void sendPackets(L2Character to, L2GameServerPacket... packets)
- {
- sendPackets(to, to, packets);
- }
- /**
- * Send packet(s)
- *
- * @param from sender
- * @param to packets receiver
- * @param packets list of packets(s) to be sent.
- */
- public void sendPackets(L2Character from, L2Character to, L2GameServerPacket... packets)
- {
- scheduleSendPackets(from, to, 0, packets);
- }
- /**
- * Schedule packet(s) to send.
- *
- * @param to packets receiver
- * @param delayMs delay (ms) for sending, or <=0 for no delay
- * @param packets list of packets(s) to be sent.
- */
- public void scheduleSendPackets(L2Character to, int delayMs, L2GameServerPacket... packets)
- {
- scheduleSendPackets(to, to, delayMs, packets);
- }
- /**
- * Schedule packet(s) to send.
- *
- * @param from sender
- * @param to packets receiver
- * @param delayMs delay (ms) for sending, or <=0 for no delay
- * @param packets list of packets(s) to be sent.
- */
- public void scheduleSendPackets(L2Character from, L2Character to, int delayMs, L2GameServerPacket... packets)
- {
- // if server is booting up, or shutting down, abort
- if (GameServer.serverStartingUp || GameServer.serverShuttingDown)
- return;
- sendPacketTask sp = null;
- // Note: I do not recommend using thread pool manager, to execute not scheduled packet tasks (some my small tests showed
- // it might make all look better and eg movement smoother and more precise, but it utilizes 10x more CPU power, than running task
- // without thread pool manager)
- if (delayMs > 0 || Config.PACKET_PACKAGE_SENDING_USE_TASK)
- {
- sp = new sendPacketTask(from, to, delayMs > 0, packets);
- if (delayMs > 0)
- ThreadPoolManager.getInstance().scheduleGeneral(sp, delayMs);
- }
- // Packets are not scheduled to send later. Send them imediately.
- if (delayMs <= 0)
- {
- if (sp != null)
- ThreadPoolManager.getInstance().executeTask(sp);
- else
- {
- for (final L2GameServerPacket p : packets)
- {
- if (p != null && to != null)
- {
- p.setSendToClientScheduled(false); // mark packet, when it was broadcasted/send by schedule, so we can react to it accordingly
- if (p.getFrom() == null) // if packet doesn't have origin set, set origin to provided one
- p.setFrom(from);
- to.sendPacket(p);
- }
- }
- }
- }
- }
- /**
- * Broadcast packet(s).
- *
- * @param from broadcast origin
- * @param mov list of packets to be broadcasted
- */
- public final void broadcastPackets(L2Character from, L2GameServerPacket... mov)
- {
- broadcastPackets(from, -1, mov);
- }
- /**
- * Broadcast packet(s).
- *
- * @param from broadcast origin
- * @param force true to force all packets to be sent, even if broadcaster is locked for sending them
- * @param mov list of packets to be broadcasted
- */
- public final void broadcastPackets(L2Character from, boolean force, L2GameServerPacket... mov)
- {
- broadcastPackets(from, -1, force, mov);
- }
- /**
- * Broadcast packet(s).
- *
- * @param from broadcast origin
- * @param radius broadcast radius or -1 to broadcast to all known players
- * @param mov list of packets to be broadcasted
- */
- public final void broadcastPackets(L2Character from, int radius, L2GameServerPacket... mov)
- {
- broadcastPackets(from, radius, false, mov);
- }
- /**
- * Broadcast packet(s).
- *
- * @param from broadcast origin
- * @param radius broadcast radius or -1 to broadcast to all known players
- * @param force true to force all packets to be sent, even if broadcaster is locked for sending them
- * @param mov list of packets to be broadcasted
- */
- public final void broadcastPackets(L2Character from, int radius, boolean force, L2GameServerPacket... mov)
- {
- scheduleBroadcastPackets(from, 0, radius, force, mov);
- }
- /**
- * Schedule broadcast of packet(s).
- *
- * @param from broadcast origin
- * @param delayMs broadcast delay (ms), or <=0 for broadcast without delay
- * @param mov list of packets to be broadcasted
- */
- public final void scheduleBroadcastPackets(L2Character from, int delayMs, L2GameServerPacket... mov)
- {
- scheduleBroadcastPackets(from, delayMs, -1, false, mov);
- }
- /**
- * Schedule broadcast of packet(s).
- *
- * @param from broadcast origin
- * @param delayMs broadcast delay (ms), or <=0 for broadcast without delay
- * @param radius broadcast radius or -1 to broadcast to all known players
- * @param force true to force all packets to be sent, even if broadcaster is locked for sending them
- * @param mov list of packets to be broadcasted
- */
- public final void scheduleBroadcastPackets(L2Character from, int delayMs, int radius, boolean force, L2GameServerPacket... mov)
- {
- if (GameServer.serverStartingUp || GameServer.serverShuttingDown)
- return;
- final Collection<L2GameServerPacket> _toMyself = new FastList<L2GameServerPacket>(); // this is collection of packets that will be sent to broadcaster
- final L2GameServerPacket[] copy = mov;
- /* First we deal with sending packets, to ourselves (broadcaster). This prevents many client side sync problems (especially for movement).
- Then we broadcast to known characters within range or to whole knownlist. */
- if (from.isPlayable())
- {
- // self
- for (final L2GameServerPacket m : copy)
- {
- if (m == null)
- continue;
- 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
- m.setFrom(from);
- if (from.isPlayable() && from.getActingPlayer() != null)
- {
- m.setInvisible(from.getActingPlayer().getAppearance().getInvisible());
- // fix for fantasy island bench sitting workaround (without it, chars stand up and rotate in place, from time to time)
- if (m instanceof StopRotation && ((StopRotation) m).getObjId() == from.getObjectId() && from.getActingPlayer().isSitting())
- continue;
- }
- // 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
- // thrown up, and is atm flying (to prevent breaking fly animation and "teleporting" character)
- if (from.isPacketBroadcastLocked() && (!force || from.isThrowedAndFlying()) && !m.isAlwaysForced())
- continue;
- // If CharInfo packet or packet marked as not sendable to broadcaster, skip.
- if (!(m instanceof CharInfo) && m.canBeSendToMyself())
- _toMyself.add(m);
- }
- // List of packets to send back to broadcaster ready? Then do it.
- if (!_toMyself.isEmpty())
- scheduleSendPackets(from, from, delayMs, _toMyself.toArray(new L2GameServerPacket[_toMyself.size()]));
- }
- final Collection<L2PcInstance> plrs = from.getKnownList().getKnownPlayersInRadius(radius);
- for (final L2PcInstance player : plrs)
- {
- // Skip sending to self (we did that already), skip sending to not online clients.
- if (player == null || player == from || player.isOnlineInt() != 1 /*|| player.isEnteringWorld()*/)
- continue;
- final FastList<L2GameServerPacket> _p = new FastList<L2GameServerPacket>();
- for (final L2GameServerPacket m : copy)
- {
- if (m == null)
- continue;
- if (from.isPlayer() && from.getActingPlayer() != null)
- {
- // Fantasy island bench sitting workaround fix.
- if (m instanceof StopRotation && ((StopRotation) m).getObjId() == from.getObjectId() && from.getActingPlayer().isSitting())
- continue;
- }
- // If broadcasting locked, or char is flying, skip.
- if (from.isPacketBroadcastLocked() && (!force || from.isThrowedAndFlying()) && !m.isAlwaysForced())
- continue;
- _p.add(m);
- // If packet is CharInfo packet, then add RelationChanged packets to broadcast list, too.
- if (m instanceof CharInfo && from.isPlayer() && from.getActingPlayer() != null)
- {
- int relation = from.getActingPlayer().getRelation(player);
- final Integer oldrelation = from.getKnownList().getKnownRelations().get(player.getObjectId());
- if (oldrelation != null && oldrelation != relation)
- {
- final L2GameServerPacket r1 = new RelationChanged(from.getActingPlayer(), relation, from.isAutoAttackable(player));
- 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
- r1.setFrom(m.getFrom());
- r1.setInvisible(m.isInvisible());
- _p.add(r1);
- if (from.getActingPlayer().getPet() != null)
- {
- final L2GameServerPacket r2 = new RelationChanged(from.getActingPlayer().getPet(), relation, from.isAutoAttackable(player));
- 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
- r2.setFrom(m.getFrom());
- r2.setInvisible(m.isInvisible());
- _p.add(r2);
- }
- }
- }
- }
- // If there are packets to be sent, do it.
- if (!_p.isEmpty())
- scheduleSendPackets(from, player, delayMs, _p.toArray(new L2GameServerPacket[_p.size()]));
- }
- }
- /**
- * Packet send task.
- */
- private class sendPacketTask implements Runnable
- {
- private final L2Character _to, _from;
- private final L2GameServerPacket[] _packets;
- private final boolean _sync, _force, _scheduled;
- public sendPacketTask(L2Character from, L2Character to, boolean scheduled, L2GameServerPacket... packets)
- {
- this(from, to, scheduled, false, false, packets);
- }
- public sendPacketTask(L2Character from, L2Character to, boolean scheduled, boolean sync, boolean force, L2GameServerPacket... packets)
- {
- _from = from;
- _to = to;
- _packets = packets;
- _sync = sync;
- _force = force;
- _scheduled = scheduled;
- }
- @Override
- public void run()
- {
- if (_to != null && _packets != null && _packets.length > 0)
- {
- for (final L2GameServerPacket p : _packets)
- {
- if (p != null && _to != null)
- {
- p.setSendToClientScheduled(_scheduled); // mark packet, when it was broadcasted/send by schedule, so we can react to it accordingly
- if (p.getFrom() == null) // if packet doesn't have origin set, set origin to provided one
- p.setFrom(_from);
- _to.sendPacket(p);
- }
- }
- }
- }
- }
- private static PacketBroadcaster _PacketBroadcaster = new PacketBroadcaster();
- public static PacketBroadcaster getInstance()
- {
- return _PacketBroadcaster;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement