diff --git a/src/main/java/com/l2jserver/L2JGameServerMain.java b/src/main/java/com/l2jserver/L2JGameServerMain.java index 35a69ce86..1be4ead35 100644 --- a/src/main/java/com/l2jserver/L2JGameServerMain.java +++ b/src/main/java/com/l2jserver/L2JGameServerMain.java @@ -57,8 +57,14 @@ public class L2JGameServerMain { serviceManager.start(BlowfishKeygenService.class); serviceManager.start(NetworkService.class); - // spawn + // spawn everything 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) { System.out.println("GameServer could not be started!"); e.printStackTrace(); diff --git a/src/main/java/com/l2jserver/game/net/packet/client/CM_PROTOCOL_VERSION.java b/src/main/java/com/l2jserver/game/net/packet/client/CM_PROTOCOL_VERSION.java index 5af43a5a3..ec6b13182 100644 --- a/src/main/java/com/l2jserver/game/net/packet/client/CM_PROTOCOL_VERSION.java +++ b/src/main/java/com/l2jserver/game/net/packet/client/CM_PROTOCOL_VERSION.java @@ -88,7 +88,7 @@ public class CM_PROTOCOL_VERSION extends AbstractClientPacket { log.debug("Client protocol version: {}", version); conn.setVersion(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); // notify wrong protocol and close connection conn.write(new SM_KEY(inKey, false)).addListener( diff --git a/src/main/java/com/l2jserver/service/ServiceManager.java b/src/main/java/com/l2jserver/service/ServiceManager.java index eef3e8746..23e82a691 100644 --- a/src/main/java/com/l2jserver/service/ServiceManager.java +++ b/src/main/java/com/l2jserver/service/ServiceManager.java @@ -74,18 +74,18 @@ public class ServiceManager { knownServices.add(service); try { startDependencies(service.getDependencies()); - logger.info("{}: Starting service...", - serviceClass.getCanonicalName()); + logger.debug("{}: Starting service...", + serviceClass.getSimpleName()); service.start(); - logger.info("{}: Service started!", serviceClass.getCanonicalName()); + logger.info("{} started", serviceClass.getSimpleName()); return service; } catch (ServiceStartException e) { logger.error("{}: Error starting service: {}", - serviceClass.getCanonicalName(), e); + serviceClass.getSimpleName(), e); throw e; } catch (Exception e) { logger.error("{}: Error starting service: {}", - serviceClass.getCanonicalName(), e); + serviceClass.getSimpleName(), e); throw new ServiceStartException(e); } } @@ -110,15 +110,15 @@ public class ServiceManager { return; knownServices.add(service); try { - logger.info("{0}: Stopping service...", - serviceClass.getCanonicalName()); + logger.debug("{0}: Stopping service...", + serviceClass.getSimpleName()); stopDependencies(service); service.stop(); logger.info("{0}: Service stopped!", - serviceClass.getCanonicalName()); + serviceClass.getSimpleName()); } catch (ServiceStopException e) { logger.error("{0}: Error stopping service: {1}", - serviceClass.getCanonicalName(), e.getCause()); + serviceClass.getSimpleName(), e.getCause()); throw e; } } @@ -160,23 +160,23 @@ public class ServiceManager { throw new ServiceStopException("Service is already stopped"); knownServices.add(service); try { - logger.info("{0}: Restaring service...", - serviceClass.getCanonicalName()); + logger.debug("{0}: Restaring service...", + serviceClass.getSimpleName()); service.restart(); logger.info("{0}: Service restarted!", - serviceClass.getCanonicalName()); + serviceClass.getSimpleName()); return service; } catch (ServiceStartException e) { logger.error("{0}: Error starting service: {1}", - serviceClass.getCanonicalName(), e.getCause()); + serviceClass.getSimpleName(), e.getCause()); throw e; } catch (ServiceStopException e) { logger.error("{0}: Error stopping service: {1}", - serviceClass.getCanonicalName(), e.getCause()); + serviceClass.getSimpleName(), e.getCause()); throw e; } catch (ServiceException e) { logger.error("{0}: Error restarting service: {1}", - serviceClass.getCanonicalName(), e.getCause()); + serviceClass.getSimpleName(), e.getCause()); throw e; } } diff --git a/src/main/java/com/l2jserver/service/ServiceModule.java b/src/main/java/com/l2jserver/service/ServiceModule.java index fbf4bb02f..547cf44b4 100644 --- a/src/main/java/com/l2jserver/service/ServiceModule.java +++ b/src/main/java/com/l2jserver/service/ServiceModule.java @@ -55,6 +55,8 @@ import com.l2jserver.service.game.world.event.WorldEventDispatcher; import com.l2jserver.service.game.world.event.WorldEventDispatcherImpl; import com.l2jserver.service.network.NettyNetworkService; 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.GameGuardServiceImpl; import com.l2jserver.service.network.keygen.BlowfishKeygenService; @@ -101,6 +103,8 @@ public class ServiceModule extends AbstractModule { .in(Scopes.SINGLETON); bind(SpawnService.class).to(SpawnServiceImpl.class) .in(Scopes.SINGLETON); + bind(BroadcastService.class).to(BroadcastServiceImpl.class).in( + Scopes.SINGLETON); bind(CharacterService.class).to(CharacterServiceImpl.class).in( Scopes.SINGLETON); bind(AttackService.class).to(AttackServiceImpl.class).in( diff --git a/src/main/java/com/l2jserver/service/configuration/ProxyConfigurationService.java b/src/main/java/com/l2jserver/service/configuration/ProxyConfigurationService.java index b9860b740..feeb1f7bd 100644 --- a/src/main/java/com/l2jserver/service/configuration/ProxyConfigurationService.java +++ b/src/main/java/com/l2jserver/service/configuration/ProxyConfigurationService.java @@ -81,13 +81,13 @@ public class ProxyConfigurationService extends AbstractService implements if (cache.containsKey(config)) return (C) cache.get(config); - logger.info("Trying to create {} proxy", config); + logger.debug("Trying to create {} proxy", config); Properties properties; try { properties = findProperties(config); } catch (IOException e) { properties = new Properties(); - logger.info( + logger.warn( "Configuration file for {} not found, falling back to default values", config); } diff --git a/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java b/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java index 3e5e39a1d..4d07b612e 100644 --- a/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java +++ b/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java @@ -21,16 +21,12 @@ import com.google.inject.Inject; import com.l2jserver.db.dao.ItemDAO; 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; -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_INVENTORY; 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_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.model.id.object.CharacterID; 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.CharacterState; 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.CharacterEvent; 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.CharacterTargetSelectedEvent; 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.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.SpawnService; 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.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.broadcast.BroadcastService; import com.l2jserver.service.network.gameguard.GameGuardService; import com.l2jserver.util.geometry.Coordinate; import com.l2jserver.util.geometry.Point3D; @@ -85,14 +70,15 @@ import com.l2jserver.util.geometry.Point3D; * @author Rogiel */ @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 CharacterService { /** - * The {@link WorldService} + * The {@link BroadcastService} */ - private final WorldService worldService; - /* + private final BroadcastService broadcastService; + /** * The {@link WorldService} event dispatcher */ private final WorldEventDispatcher eventDispatcher; @@ -127,11 +113,11 @@ public class CharacterServiceImpl extends AbstractService implements // private final AIService aiService; @Inject - public CharacterServiceImpl(WorldService worldService, + public CharacterServiceImpl(BroadcastService broadcastService, WorldEventDispatcher eventDispatcher, ChatService chatService, NetworkService networkService, SpawnService spawnService, NPCService npcService, GameGuardService ggService, ItemDAO itemDao) { - this.worldService = worldService; + this.broadcastService = broadcastService; this.eventDispatcher = eventDispatcher; this.chatService = chatService; this.networkService = networkService; @@ -154,7 +140,7 @@ public class CharacterServiceImpl extends AbstractService implements itemDao.loadInventory(character); character.setOnline(true); - + // inventory interfere on calculators character.getStats().updateCalculator(); @@ -176,77 +162,8 @@ public class CharacterServiceImpl extends AbstractService implements } }; - // 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 - // TODO this should not be here, it should be in world service or a - // newly created broadcast service. - final WorldListener neighboorListener = new FilteredWorldListener( - 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( - 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); + // start broadcasting -- will broadcast all nearby objects + broadcastService.broadcast(conn); // leave world event eventDispatcher.addListener(id, new CharacterListener() { @@ -261,9 +178,9 @@ public class CharacterServiceImpl extends AbstractService implements chatService.getTradeChannel().removeChatChannelListener( tradeChatListener); - // remove broadcast listener - eventDispatcher.removeListener(neighboorListener); - eventDispatcher.removeListener(sendPacketListener); + // // remove broadcast listener + // eventDispatcher.removeListener(neighboorListener); + // eventDispatcher.removeListener(id, sendPacketListener);s // we can kill this listener now return false; @@ -295,7 +212,7 @@ public class CharacterServiceImpl extends AbstractService implements // we can ignore this one } - broadcast(conn, character); + // broadcast(conn, character); // spawn the player -- this will also dispatch a spawn event // here the object is registered in the world @@ -305,20 +222,6 @@ public class CharacterServiceImpl extends AbstractService implements 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 public void leaveWorld(L2Character character) throws NotSpawnedServiceException { diff --git a/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java b/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java index 154969660..0198fdfe3 100644 --- a/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java +++ b/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java @@ -36,6 +36,7 @@ import com.l2jserver.service.AbstractService; import com.l2jserver.service.AbstractService.Depends; import com.l2jserver.service.core.threading.AsyncFuture; import com.l2jserver.service.core.threading.ThreadService; +import com.l2jserver.service.database.DatabaseService; import com.l2jserver.service.game.AttackService; import com.l2jserver.service.game.character.CannotSetTargetServiceException; import com.l2jserver.service.game.character.CharacterService; @@ -53,7 +54,7 @@ import com.l2jserver.util.geometry.Point3D; * @author Rogiel */ @Depends({ SpawnService.class, NetworkService.class, CharacterService.class, - ThreadService.class, AttackService.class }) + ThreadService.class, AttackService.class, DatabaseService.class }) public class NPCServiceImpl extends AbstractService implements NPCService { /** * The {@link SpawnService} used to spawn the {@link NPC} instances diff --git a/src/main/java/com/l2jserver/service/network/broadcast/BroadcastService.java b/src/main/java/com/l2jserver/service/network/broadcast/BroadcastService.java new file mode 100644 index 000000000..fcfe29717 --- /dev/null +++ b/src/main/java/com/l2jserver/service/network/broadcast/BroadcastService.java @@ -0,0 +1,31 @@ +/* + * This file is part of l2jserver . + * + * 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 . + */ +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 Rogiel + */ +public interface BroadcastService extends Service { + void broadcast(Lineage2Connection conn); +} diff --git a/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java b/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java new file mode 100644 index 000000000..4de2cd490 --- /dev/null +++ b/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java @@ -0,0 +1,190 @@ +/* + * This file is part of l2jserver . + * + * 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 . + */ +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 Rogiel + */ +@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( + 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)); + } + } +}