1
0
mirror of https://github.com/Rogiel/l2jserver2 synced 2025-12-06 07:32:46 +00:00

BroadcastService implementation

Signed-off-by: Rogiel <rogiel@rogiel.com>
This commit is contained in:
2011-05-31 13:32:56 -03:00
parent 7d4d9114e5
commit d72bb75cb0
9 changed files with 267 additions and 132 deletions

View File

@@ -57,8 +57,14 @@ public class L2JGameServerMain {
serviceManager.start(BlowfishKeygenService.class); serviceManager.start(BlowfishKeygenService.class);
serviceManager.start(NetworkService.class); serviceManager.start(NetworkService.class);
// spawn // spawn everything
serviceManager.get(NPCService.class).spawnAll(); serviceManager.get(NPCService.class).spawnAll();
// final long free = Runtime.getRuntime().freeMemory();
// final long allocated = Runtime.getRuntime().totalMemory();
// final long maximum = Runtime.getRuntime().maxMemory();
// final long processors =
// Runtime.getRuntime().availableProcessors();
} catch (Exception e) { } catch (Exception e) {
System.out.println("GameServer could not be started!"); System.out.println("GameServer could not be started!");
e.printStackTrace(); e.printStackTrace();

View File

@@ -88,7 +88,7 @@ public class CM_PROTOCOL_VERSION extends AbstractClientPacket {
log.debug("Client protocol version: {}", version); log.debug("Client protocol version: {}", version);
conn.setVersion(version); conn.setVersion(version);
if (L2JConstant.SUPPORTED_PROTOCOL != version) { if (L2JConstant.SUPPORTED_PROTOCOL != version) {
log.info("Incorrect protocol version: {0}. Only {1} is supported.", log.info("Incorrect protocol version: {}. Only {} is supported.",
version, L2JConstant.SUPPORTED_PROTOCOL); version, L2JConstant.SUPPORTED_PROTOCOL);
// notify wrong protocol and close connection // notify wrong protocol and close connection
conn.write(new SM_KEY(inKey, false)).addListener( conn.write(new SM_KEY(inKey, false)).addListener(

View File

@@ -74,18 +74,18 @@ public class ServiceManager {
knownServices.add(service); knownServices.add(service);
try { try {
startDependencies(service.getDependencies()); startDependencies(service.getDependencies());
logger.info("{}: Starting service...", logger.debug("{}: Starting service...",
serviceClass.getCanonicalName()); serviceClass.getSimpleName());
service.start(); service.start();
logger.info("{}: Service started!", serviceClass.getCanonicalName()); logger.info("{} started", serviceClass.getSimpleName());
return service; return service;
} catch (ServiceStartException e) { } catch (ServiceStartException e) {
logger.error("{}: Error starting service: {}", logger.error("{}: Error starting service: {}",
serviceClass.getCanonicalName(), e); serviceClass.getSimpleName(), e);
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
logger.error("{}: Error starting service: {}", logger.error("{}: Error starting service: {}",
serviceClass.getCanonicalName(), e); serviceClass.getSimpleName(), e);
throw new ServiceStartException(e); throw new ServiceStartException(e);
} }
} }
@@ -110,15 +110,15 @@ public class ServiceManager {
return; return;
knownServices.add(service); knownServices.add(service);
try { try {
logger.info("{0}: Stopping service...", logger.debug("{0}: Stopping service...",
serviceClass.getCanonicalName()); serviceClass.getSimpleName());
stopDependencies(service); stopDependencies(service);
service.stop(); service.stop();
logger.info("{0}: Service stopped!", logger.info("{0}: Service stopped!",
serviceClass.getCanonicalName()); serviceClass.getSimpleName());
} catch (ServiceStopException e) { } catch (ServiceStopException e) {
logger.error("{0}: Error stopping service: {1}", logger.error("{0}: Error stopping service: {1}",
serviceClass.getCanonicalName(), e.getCause()); serviceClass.getSimpleName(), e.getCause());
throw e; throw e;
} }
} }
@@ -160,23 +160,23 @@ public class ServiceManager {
throw new ServiceStopException("Service is already stopped"); throw new ServiceStopException("Service is already stopped");
knownServices.add(service); knownServices.add(service);
try { try {
logger.info("{0}: Restaring service...", logger.debug("{0}: Restaring service...",
serviceClass.getCanonicalName()); serviceClass.getSimpleName());
service.restart(); service.restart();
logger.info("{0}: Service restarted!", logger.info("{0}: Service restarted!",
serviceClass.getCanonicalName()); serviceClass.getSimpleName());
return service; return service;
} catch (ServiceStartException e) { } catch (ServiceStartException e) {
logger.error("{0}: Error starting service: {1}", logger.error("{0}: Error starting service: {1}",
serviceClass.getCanonicalName(), e.getCause()); serviceClass.getSimpleName(), e.getCause());
throw e; throw e;
} catch (ServiceStopException e) { } catch (ServiceStopException e) {
logger.error("{0}: Error stopping service: {1}", logger.error("{0}: Error stopping service: {1}",
serviceClass.getCanonicalName(), e.getCause()); serviceClass.getSimpleName(), e.getCause());
throw e; throw e;
} catch (ServiceException e) { } catch (ServiceException e) {
logger.error("{0}: Error restarting service: {1}", logger.error("{0}: Error restarting service: {1}",
serviceClass.getCanonicalName(), e.getCause()); serviceClass.getSimpleName(), e.getCause());
throw e; throw e;
} }
} }

View File

@@ -55,6 +55,8 @@ import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.service.game.world.event.WorldEventDispatcherImpl; import com.l2jserver.service.game.world.event.WorldEventDispatcherImpl;
import com.l2jserver.service.network.NettyNetworkService; import com.l2jserver.service.network.NettyNetworkService;
import com.l2jserver.service.network.NetworkService; import com.l2jserver.service.network.NetworkService;
import com.l2jserver.service.network.broadcast.BroadcastService;
import com.l2jserver.service.network.broadcast.BroadcastServiceImpl;
import com.l2jserver.service.network.gameguard.GameGuardService; import com.l2jserver.service.network.gameguard.GameGuardService;
import com.l2jserver.service.network.gameguard.GameGuardServiceImpl; import com.l2jserver.service.network.gameguard.GameGuardServiceImpl;
import com.l2jserver.service.network.keygen.BlowfishKeygenService; import com.l2jserver.service.network.keygen.BlowfishKeygenService;
@@ -101,6 +103,8 @@ public class ServiceModule extends AbstractModule {
.in(Scopes.SINGLETON); .in(Scopes.SINGLETON);
bind(SpawnService.class).to(SpawnServiceImpl.class) bind(SpawnService.class).to(SpawnServiceImpl.class)
.in(Scopes.SINGLETON); .in(Scopes.SINGLETON);
bind(BroadcastService.class).to(BroadcastServiceImpl.class).in(
Scopes.SINGLETON);
bind(CharacterService.class).to(CharacterServiceImpl.class).in( bind(CharacterService.class).to(CharacterServiceImpl.class).in(
Scopes.SINGLETON); Scopes.SINGLETON);
bind(AttackService.class).to(AttackServiceImpl.class).in( bind(AttackService.class).to(AttackServiceImpl.class).in(

View File

@@ -81,13 +81,13 @@ public class ProxyConfigurationService extends AbstractService implements
if (cache.containsKey(config)) if (cache.containsKey(config))
return (C) cache.get(config); return (C) cache.get(config);
logger.info("Trying to create {} proxy", config); logger.debug("Trying to create {} proxy", config);
Properties properties; Properties properties;
try { try {
properties = findProperties(config); properties = findProperties(config);
} catch (IOException e) { } catch (IOException e) {
properties = new Properties(); properties = new Properties();
logger.info( logger.warn(
"Configuration file for {} not found, falling back to default values", "Configuration file for {} not found, falling back to default values",
config); config);
} }

View File

@@ -21,16 +21,12 @@ import com.google.inject.Inject;
import com.l2jserver.db.dao.ItemDAO; import com.l2jserver.db.dao.ItemDAO;
import com.l2jserver.game.net.Lineage2Connection; import com.l2jserver.game.net.Lineage2Connection;
import com.l2jserver.game.net.SystemMessage; import com.l2jserver.game.net.SystemMessage;
import com.l2jserver.game.net.packet.server.SM_ATTACK;
import com.l2jserver.game.net.packet.server.SM_CHAR_INFO; import com.l2jserver.game.net.packet.server.SM_CHAR_INFO;
import com.l2jserver.game.net.packet.server.SM_CHAR_INFO_BROADCAST;
import com.l2jserver.game.net.packet.server.SM_CHAR_INFO_EXTRA; import com.l2jserver.game.net.packet.server.SM_CHAR_INFO_EXTRA;
import com.l2jserver.game.net.packet.server.SM_CHAR_INVENTORY; import com.l2jserver.game.net.packet.server.SM_CHAR_INVENTORY;
import com.l2jserver.game.net.packet.server.SM_CHAT; import com.l2jserver.game.net.packet.server.SM_CHAT;
import com.l2jserver.game.net.packet.server.SM_MOVE; import com.l2jserver.game.net.packet.server.SM_MOVE;
import com.l2jserver.game.net.packet.server.SM_MOVE_TYPE; import com.l2jserver.game.net.packet.server.SM_MOVE_TYPE;
import com.l2jserver.game.net.packet.server.SM_NPC_INFO;
import com.l2jserver.game.net.packet.server.SM_OBJECT_REMOVE;
import com.l2jserver.game.net.packet.server.SM_TARGET; import com.l2jserver.game.net.packet.server.SM_TARGET;
import com.l2jserver.model.id.object.CharacterID; import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.world.Actor; import com.l2jserver.model.world.Actor;
@@ -38,9 +34,6 @@ import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.L2Character.CharacterMoveType; import com.l2jserver.model.world.L2Character.CharacterMoveType;
import com.l2jserver.model.world.L2Character.CharacterState; import com.l2jserver.model.world.L2Character.CharacterState;
import com.l2jserver.model.world.NPC; import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.PositionableObject;
import com.l2jserver.model.world.WorldObject;
import com.l2jserver.model.world.actor.event.ActorAttackHitEvent;
import com.l2jserver.model.world.character.event.CharacterEnterWorldEvent; import com.l2jserver.model.world.character.event.CharacterEnterWorldEvent;
import com.l2jserver.model.world.character.event.CharacterEvent; import com.l2jserver.model.world.character.event.CharacterEvent;
import com.l2jserver.model.world.character.event.CharacterLeaveWorldEvent; import com.l2jserver.model.world.character.event.CharacterLeaveWorldEvent;
@@ -50,9 +43,6 @@ import com.l2jserver.model.world.character.event.CharacterRunningEvent;
import com.l2jserver.model.world.character.event.CharacterTargetDeselectedEvent; import com.l2jserver.model.world.character.event.CharacterTargetDeselectedEvent;
import com.l2jserver.model.world.character.event.CharacterTargetSelectedEvent; import com.l2jserver.model.world.character.event.CharacterTargetSelectedEvent;
import com.l2jserver.model.world.character.event.CharacterWalkingEvent; import com.l2jserver.model.world.character.event.CharacterWalkingEvent;
import com.l2jserver.model.world.npc.event.NPCSpawnEvent;
import com.l2jserver.model.world.player.event.PlayerTeleportedEvent;
import com.l2jserver.model.world.player.event.PlayerTeleportingEvent;
import com.l2jserver.service.AbstractService; import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends; import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.game.AttackService; import com.l2jserver.service.game.AttackService;
@@ -67,14 +57,9 @@ import com.l2jserver.service.game.spawn.NotSpawnedServiceException;
import com.l2jserver.service.game.spawn.SpawnPointNotFoundServiceException; import com.l2jserver.service.game.spawn.SpawnPointNotFoundServiceException;
import com.l2jserver.service.game.spawn.SpawnService; import com.l2jserver.service.game.spawn.SpawnService;
import com.l2jserver.service.game.world.WorldService; import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.game.world.event.FilteredWorldListener;
import com.l2jserver.service.game.world.event.WorldEvent;
import com.l2jserver.service.game.world.event.WorldEventDispatcher; import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.service.game.world.event.WorldListener;
import com.l2jserver.service.game.world.filter.impl.IDFilter;
import com.l2jserver.service.game.world.filter.impl.KnownListFilter;
import com.l2jserver.service.game.world.filter.impl.KnownListUpdateFilter;
import com.l2jserver.service.network.NetworkService; import com.l2jserver.service.network.NetworkService;
import com.l2jserver.service.network.broadcast.BroadcastService;
import com.l2jserver.service.network.gameguard.GameGuardService; import com.l2jserver.service.network.gameguard.GameGuardService;
import com.l2jserver.util.geometry.Coordinate; import com.l2jserver.util.geometry.Coordinate;
import com.l2jserver.util.geometry.Point3D; import com.l2jserver.util.geometry.Point3D;
@@ -85,14 +70,15 @@ import com.l2jserver.util.geometry.Point3D;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
@Depends({ WorldService.class, ChatService.class, NetworkService.class, @Depends({ WorldService.class, ChatService.class, NetworkService.class,
SpawnService.class, AttackService.class, GameGuardService.class }) SpawnService.class, AttackService.class, GameGuardService.class,
BroadcastService.class })
public class CharacterServiceImpl extends AbstractService implements public class CharacterServiceImpl extends AbstractService implements
CharacterService { CharacterService {
/** /**
* The {@link WorldService} * The {@link BroadcastService}
*/ */
private final WorldService worldService; private final BroadcastService broadcastService;
/* /**
* The {@link WorldService} event dispatcher * The {@link WorldService} event dispatcher
*/ */
private final WorldEventDispatcher eventDispatcher; private final WorldEventDispatcher eventDispatcher;
@@ -127,11 +113,11 @@ public class CharacterServiceImpl extends AbstractService implements
// private final AIService aiService; // private final AIService aiService;
@Inject @Inject
public CharacterServiceImpl(WorldService worldService, public CharacterServiceImpl(BroadcastService broadcastService,
WorldEventDispatcher eventDispatcher, ChatService chatService, WorldEventDispatcher eventDispatcher, ChatService chatService,
NetworkService networkService, SpawnService spawnService, NetworkService networkService, SpawnService spawnService,
NPCService npcService, GameGuardService ggService, ItemDAO itemDao) { NPCService npcService, GameGuardService ggService, ItemDAO itemDao) {
this.worldService = worldService; this.broadcastService = broadcastService;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.chatService = chatService; this.chatService = chatService;
this.networkService = networkService; this.networkService = networkService;
@@ -154,7 +140,7 @@ public class CharacterServiceImpl extends AbstractService implements
itemDao.loadInventory(character); itemDao.loadInventory(character);
character.setOnline(true); character.setOnline(true);
// inventory interfere on calculators // inventory interfere on calculators
character.getStats().updateCalculator(); character.getStats().updateCalculator();
@@ -176,77 +162,8 @@ public class CharacterServiceImpl extends AbstractService implements
} }
}; };
// event broadcast listener // start broadcasting -- will broadcast all nearby objects
// this listener will be filtered so that only interesting events are broadcastService.broadcast(conn);
// dispatched, once a event arrives will be possible to check check if
// the given event will be broadcasted or not
// TODO this should not be here, it should be in world service or a
// newly created broadcast service.
final WorldListener neighboorListener = new FilteredWorldListener<PositionableObject>(
new KnownListFilter(character)) {
@Override
protected boolean dispatch(WorldEvent e, PositionableObject object) {
if (e instanceof NPCSpawnEvent) {
conn.write(new SM_NPC_INFO((NPC) object));
} else if (e instanceof CharacterMoveEvent) {
final CharacterMoveEvent evt = (CharacterMoveEvent) e;
conn.write(new SM_MOVE((L2Character) object, evt.getPoint()
.getCoordinate()));
} else if (e instanceof PlayerTeleportedEvent
|| e instanceof CharacterEnterWorldEvent) {
if (object instanceof NPC) {
conn.write(new SM_NPC_INFO((NPC) object));
} else if (object instanceof L2Character) {
conn.write(new SM_CHAR_INFO_BROADCAST(
(L2Character) object));
}
} else if (e instanceof PlayerTeleportingEvent
|| e instanceof CharacterLeaveWorldEvent) {
// object is not out of sight
conn.write(new SM_OBJECT_REMOVE(object));
} else if (e instanceof CharacterWalkingEvent) {
conn.write(new SM_MOVE_TYPE(((CharacterWalkingEvent) e)
.getCharacter()));
} else if (e instanceof CharacterRunningEvent) {
conn.write(new SM_MOVE_TYPE(((CharacterRunningEvent) e)
.getCharacter()));
}
// keep listener alive
return true;
}
};
eventDispatcher.addListener(neighboorListener);
final WorldListener sendPacketListener = new FilteredWorldListener<WorldObject>(
new IDFilter(character.getID())) {
@Override
protected boolean dispatch(WorldEvent e, WorldObject object) {
if (e instanceof CharacterMoveEvent) {
final CharacterMoveEvent evt = (CharacterMoveEvent) e;
// process update known list
for (final WorldObject o : worldService
.iterable(new KnownListUpdateFilter(character, evt
.getPoint()))) {
if (o instanceof NPC) {
conn.write(new SM_NPC_INFO((NPC) o));
} else if (o instanceof L2Character) {
conn.write(new SM_CHAR_INFO_BROADCAST(
(L2Character) o));
}
}
} else if (e instanceof PlayerTeleportedEvent
|| e instanceof CharacterEnterWorldEvent) {
broadcast(conn, character);
} else if (e instanceof ActorAttackHitEvent) {
conn.write(new SM_ATTACK(((ActorAttackHitEvent) e).getHit()));
conn.sendSystemMessage(SystemMessage.YOU_DID_S1_DMG,
(int) ((ActorAttackHitEvent) e).getHit()
.getDamage());
}
// keep listener alive
return true;
}
};
eventDispatcher.addListener(sendPacketListener);
// leave world event // leave world event
eventDispatcher.addListener(id, new CharacterListener() { eventDispatcher.addListener(id, new CharacterListener() {
@@ -261,9 +178,9 @@ public class CharacterServiceImpl extends AbstractService implements
chatService.getTradeChannel().removeChatChannelListener( chatService.getTradeChannel().removeChatChannelListener(
tradeChatListener); tradeChatListener);
// remove broadcast listener // // remove broadcast listener
eventDispatcher.removeListener(neighboorListener); // eventDispatcher.removeListener(neighboorListener);
eventDispatcher.removeListener(sendPacketListener); // eventDispatcher.removeListener(id, sendPacketListener);s
// we can kill this listener now // we can kill this listener now
return false; return false;
@@ -295,7 +212,7 @@ public class CharacterServiceImpl extends AbstractService implements
// we can ignore this one // we can ignore this one
} }
broadcast(conn, character); // broadcast(conn, character);
// spawn the player -- this will also dispatch a spawn event // spawn the player -- this will also dispatch a spawn event
// here the object is registered in the world // here the object is registered in the world
@@ -305,20 +222,6 @@ public class CharacterServiceImpl extends AbstractService implements
eventDispatcher.dispatch(new CharacterEnterWorldEvent(character)); eventDispatcher.dispatch(new CharacterEnterWorldEvent(character));
} }
// broadcast knownlist -- trashy implementation
// TODO should be moved to world service or a newly created broadcast
// service, whichever fits the purpose
private void broadcast(Lineage2Connection conn, L2Character character) {
for (final WorldObject o : worldService.iterable(new KnownListFilter(
character))) {
if (o instanceof NPC) {
conn.write(new SM_NPC_INFO((NPC) o));
} else if (o instanceof L2Character) {
conn.write(new SM_CHAR_INFO_BROADCAST((L2Character) o));
}
}
}
@Override @Override
public void leaveWorld(L2Character character) public void leaveWorld(L2Character character)
throws NotSpawnedServiceException { throws NotSpawnedServiceException {

View File

@@ -36,6 +36,7 @@ import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends; import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.core.threading.AsyncFuture; import com.l2jserver.service.core.threading.AsyncFuture;
import com.l2jserver.service.core.threading.ThreadService; import com.l2jserver.service.core.threading.ThreadService;
import com.l2jserver.service.database.DatabaseService;
import com.l2jserver.service.game.AttackService; import com.l2jserver.service.game.AttackService;
import com.l2jserver.service.game.character.CannotSetTargetServiceException; import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.character.CharacterService; import com.l2jserver.service.game.character.CharacterService;
@@ -53,7 +54,7 @@ import com.l2jserver.util.geometry.Point3D;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
@Depends({ SpawnService.class, NetworkService.class, CharacterService.class, @Depends({ SpawnService.class, NetworkService.class, CharacterService.class,
ThreadService.class, AttackService.class }) ThreadService.class, AttackService.class, DatabaseService.class })
public class NPCServiceImpl extends AbstractService implements NPCService { public class NPCServiceImpl extends AbstractService implements NPCService {
/** /**
* The {@link SpawnService} used to spawn the {@link NPC} instances * The {@link SpawnService} used to spawn the {@link NPC} instances

View File

@@ -0,0 +1,31 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver 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.
*
* l2jserver 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 l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.network.broadcast;
import com.l2jserver.game.net.Lineage2Connection;
import com.l2jserver.model.world.WorldObject;
import com.l2jserver.service.Service;
/**
* This service is responsible for sending neighbor {@link WorldObject} packets.
* This service also sends some packets that are bounded to an event.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface BroadcastService extends Service {
void broadcast(Lineage2Connection conn);
}

View File

@@ -0,0 +1,190 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver 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.
*
* l2jserver 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 l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.network.broadcast;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.l2jserver.game.net.Lineage2Connection;
import com.l2jserver.game.net.SystemMessage;
import com.l2jserver.game.net.packet.server.SM_ATTACK;
import com.l2jserver.game.net.packet.server.SM_CHAR_INFO_BROADCAST;
import com.l2jserver.game.net.packet.server.SM_MOVE;
import com.l2jserver.game.net.packet.server.SM_MOVE_TYPE;
import com.l2jserver.game.net.packet.server.SM_NPC_INFO;
import com.l2jserver.game.net.packet.server.SM_OBJECT_REMOVE;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.PositionableObject;
import com.l2jserver.model.world.WorldObject;
import com.l2jserver.model.world.actor.event.ActorAttackHitEvent;
import com.l2jserver.model.world.character.event.CharacterEnterWorldEvent;
import com.l2jserver.model.world.character.event.CharacterLeaveWorldEvent;
import com.l2jserver.model.world.character.event.CharacterMoveEvent;
import com.l2jserver.model.world.character.event.CharacterRunningEvent;
import com.l2jserver.model.world.character.event.CharacterWalkingEvent;
import com.l2jserver.model.world.npc.event.NPCSpawnEvent;
import com.l2jserver.model.world.player.event.PlayerTeleportedEvent;
import com.l2jserver.model.world.player.event.PlayerTeleportingEvent;
import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.game.world.event.FilteredWorldListener;
import com.l2jserver.service.game.world.event.WorldEvent;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.service.game.world.event.WorldListener;
import com.l2jserver.service.game.world.filter.impl.KnownListFilter;
import com.l2jserver.service.game.world.filter.impl.KnownListUpdateFilter;
import com.l2jserver.service.network.NetworkService;
import com.l2jserver.util.geometry.Point3D;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
@Depends({ NetworkService.class, WorldService.class })
public class BroadcastServiceImpl extends AbstractService implements
BroadcastService {
private final WorldService worldService;
private final WorldEventDispatcher eventDispatcher;
@Inject
public BroadcastServiceImpl(WorldService worldService,
WorldEventDispatcher eventDispatcher) {
this.worldService = worldService;
this.eventDispatcher = eventDispatcher;
}
@Override
public void broadcast(final Lineage2Connection conn) {
Preconditions.checkNotNull(conn, "conn");
final L2Character character = conn.getCharacter();
Preconditions.checkNotNull(character, "character");
final CharacterID id = character.getID();
// broadcast everything nearby
broadcast(conn);
// event broadcast listener
// this listener will be filtered so that only interesting events are
// dispatched, once a event arrives will be possible to check check if
// the given event will be broadcasted or not
final WorldListener neighborListener = new FilteredWorldListener<PositionableObject>(
new KnownListFilter(character)) {
@Override
protected boolean dispatch(WorldEvent e, PositionableObject object) {
if (e instanceof NPCSpawnEvent) {
broadcast(conn, e.getObject());
} else if (e instanceof CharacterMoveEvent) {
final CharacterMoveEvent evt = (CharacterMoveEvent) e;
conn.write(new SM_MOVE((L2Character) object, evt.getPoint()
.getCoordinate()));
} else if (e instanceof PlayerTeleportedEvent
|| e instanceof CharacterEnterWorldEvent) {
broadcast(conn, e.getObject());
} else if (e instanceof PlayerTeleportingEvent
|| e instanceof CharacterLeaveWorldEvent) {
// object is now out of sight
conn.write(new SM_OBJECT_REMOVE(object));
} else if (e instanceof CharacterWalkingEvent) {
conn.write(new SM_MOVE_TYPE(((CharacterWalkingEvent) e)
.getCharacter()));
} else if (e instanceof CharacterRunningEvent) {
conn.write(new SM_MOVE_TYPE(((CharacterRunningEvent) e)
.getCharacter()));
}
// keep listener alive
return true;
}
};
// add the global listener
eventDispatcher.addListener(neighborListener);
// this listener is bound directly to the character, no need for filters
// or any other test inside listener
final WorldListener sendPacketListener = new WorldListener() {
@Override
public boolean dispatch(WorldEvent e) {
if (e instanceof CharacterMoveEvent) {
final CharacterMoveEvent evt = (CharacterMoveEvent) e;
// process update known list
broadcastUpdate(conn, character, evt.getPoint());
} else if (e instanceof PlayerTeleportedEvent
|| e instanceof CharacterEnterWorldEvent) {
broadcastAll(conn, character);
} else if (e instanceof ActorAttackHitEvent) {
conn.write(new SM_ATTACK(((ActorAttackHitEvent) e).getHit()));
conn.sendSystemMessage(SystemMessage.YOU_DID_S1_DMG,
(int) ((ActorAttackHitEvent) e).getHit()
.getDamage());
}
// keep listener alive
return true;
}
};
// add listener only for this character
eventDispatcher.addListener(id, sendPacketListener);
}
/**
* Broadcast all nearby objects to this client
*
* @param conn
* the connection
* @param character
* the character
*/
private void broadcastAll(Lineage2Connection conn, L2Character character) {
for (final WorldObject o : worldService.iterable(new KnownListFilter(
character))) {
broadcast(conn, o);
}
}
/**
* Broadcast new nearby objects to this client. Will only broadcast if the
* object was out-of-range before and now is in range.
*
* @param conn
* the connection
* @param character
* the character
* @param point
* the old point
*/
private void broadcastUpdate(Lineage2Connection conn,
L2Character character, Point3D point) {
for (final WorldObject o : worldService
.iterable(new KnownListUpdateFilter(character, point))) {
broadcast(conn, o);
}
}
/**
* Broadcast an object to this client
*
* @param conn
* the connection
* @param character
* the character
*/
private void broadcast(Lineage2Connection conn, WorldObject o) {
if (o instanceof NPC) {
conn.write(new SM_NPC_INFO((NPC) o));
} else if (o instanceof L2Character) {
conn.write(new SM_CHAR_INFO_BROADCAST((L2Character) o));
}
}
}