.
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.service.core.threading;
+
+/**
+ * The priority of the thread pool
+ *
+ * @author Rogiel
+ */
+public enum ThreadPoolPriority {
+ /**
+ * High priority.
+ *
+ * Processor will block {@link ThreadPoolPriority#NORMAL} and
+ * {@link ThreadPoolPriority#LOW} priority threads in order to finish tasks
+ * in pools on this priority.
+ */
+ HIGH(Thread.MAX_PRIORITY),
+ /**
+ * Normal priority.
+ *
+ * Processor will block {@link ThreadPoolPriority#LOW} priority threads in
+ * order to finish tasks in pools on this priority.
+ */
+ NORMAL(Thread.NORM_PRIORITY),
+ /**
+ * Low priority.
+ *
+ * Processor will give very low priority for tasks in this level.
+ */
+ LOW(Thread.MIN_PRIORITY);
+
+ /**
+ * The priority to be used on {@link Thread}
+ */
+ public final int threadPriority;
+
+ ThreadPoolPriority(int threadPriority) {
+ this.threadPriority = threadPriority;
+ }
+}
diff --git a/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadService.java b/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadService.java
index d308ffefc..a93ebe327 100644
--- a/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadService.java
+++ b/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadService.java
@@ -79,16 +79,72 @@ public interface ThreadService extends Service {
ScheduledAsyncFuture async(long delay, TimeUnit unit, long repeat,
Runnable task);
+ /**
+ * Creates a new thread pool with {@link ThreadPoolPriority#NORMAL normal}
+ * priority and that can be increased up to {@link Integer#MAX_VALUE} active
+ * threads, if necessary.
+ *
+ * Threads in this pool will never expire.
+ *
+ * @param name
+ * the pool name
+ * @param threads
+ * the maximum amount of active threads
+ * @return the new thread pool
+ */
+ ThreadPool createThreadPool(String name, int threads);
+
+ /**
+ * Creates a new thread pool that can increase up to
+ * {@link Integer#MAX_VALUE} active threads, if necessary.
+ *
+ * Threads in this pool will never expire.
+ *
+ * @param name
+ * the pool name
+ * @param threads
+ * the maximum amount of active threads
+ * @param priority
+ * the processor scheduling priority
+ * @return the new thread pool
+ */
+ ThreadPool createThreadPool(String name, int threads,
+ ThreadPoolPriority priority);
+
+ /**
+ * Creates a new thread pool with {@link ThreadPoolPriority#NORMAL normal}
+ * priority.
+ *
+ * @param name
+ * the pool name
+ * @param threads
+ * the maximum amount of active threads
+ * @param threadTimeout
+ * the time it takes to expire an inactive thread
+ * @param threadTimeoutUnit
+ * the {@link TimeUnit} for threadTimeout
+ * @return the new thread pool
+ */
+ ThreadPool createThreadPool(String name, int threads, long threadTimeout,
+ TimeUnit threadTimeoutUnit);
+
/**
* Creates a new thread pool.
*
* @param name
* the pool name
- * @param maxThreads
- * the maximum amount of threads.
+ * @param threads
+ * the maximum amount of active threads
+ * @param threadTimeout
+ * the time it takes to expire an inactive thread
+ * @param threadTimeoutUnit
+ * the {@link TimeUnit} for threadTimeout
+ * @param priority
+ * the processor scheduling priority
* @return the new thread pool
*/
- ThreadPool createThreadPool(String name, int maxThreads);
+ ThreadPool createThreadPool(String name, int threads, long threadTimeout,
+ TimeUnit threadTimeoutUnit, ThreadPoolPriority priority);
/**
* Disposes an given thread pool. After disposing the thread pool will no
diff --git a/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadServiceImpl.java b/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadServiceImpl.java
index 0e50e1bc6..959b867da 100644
--- a/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadServiceImpl.java
+++ b/l2jserver2-common/src/main/java/com/l2jserver/service/core/threading/ThreadServiceImpl.java
@@ -22,12 +22,13 @@ import java.util.Map.Entry;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -62,7 +63,7 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
@Override
protected void doStart() throws ServiceStartException {
threadPools = CollectionFactory.newMap();
- pool = createThreadPool("shared", 20);
+ pool = createThreadPool("shared", 1);
pool.async(50, TimeUnit.MILLISECONDS, 50, new Runnable() {
@Override
@@ -111,21 +112,61 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
}
@Override
- public ThreadPool createThreadPool(String name, int maxThreads) {
- log.debug("Creating new ThreadPool {} with maximum of {} threads",
- name, maxThreads);
- final ThreadPoolImpl pool = new ThreadPoolImpl(name,
- Executors.newScheduledThreadPool(maxThreads));
+ public ThreadPool createThreadPool(final String name, final int threads,
+ final long threadTimeout, final TimeUnit threadTimeoutUnit,
+ final ThreadPoolPriority priority) {
+ log.debug(
+ "Creating new {} priority ThreadPool {}; threads: {}, timeout:{}",
+ new Object[] { priority, name, threads, threadTimeout });
+ final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
+ threads);
+ if (threadTimeout >= 1) {
+ executor.setKeepAliveTime(threadTimeout, threadTimeoutUnit);
+ executor.allowCoreThreadTimeOut(true);
+ }
+ executor.setThreadFactory(new ThreadFactory() {
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+
+ @Override
+ public Thread newThread(Runnable r) {
+ final Thread thread = new Thread(r, name + "-"
+ + threadNumber.getAndIncrement());
+ thread.setPriority(priority.threadPriority);
+ return thread;
+ }
+ });
+
+ final ThreadPoolImpl pool = new ThreadPoolImpl(name, executor);
threadPools.put(name, pool);
return pool;
}
+ @Override
+ public ThreadPool createThreadPool(String name, int threads) {
+ return createThreadPool(name, threads, -1, null,
+ ThreadPoolPriority.NORMAL);
+ }
+
+ @Override
+ public ThreadPool createThreadPool(String name, int threads,
+ ThreadPoolPriority priority) {
+ return createThreadPool(name, threads, -1, null, priority);
+ }
+
+ @Override
+ public ThreadPool createThreadPool(String name, int threads,
+ long threadTimeout, TimeUnit threadTimeoutUnit) {
+ return createThreadPool(name, threads, threadTimeout,
+ threadTimeoutUnit, ThreadPoolPriority.NORMAL);
+ }
+
@Override
public void dispose(ThreadPool pool) {
log.debug("Disposing ThreadPool {}", pool);
if (pool instanceof ThreadPoolImpl) {
((ThreadPoolImpl) pool).executor.shutdown();
threadPools.remove(((ThreadPoolImpl) pool).name);
+ return;
}
throw new UnsupportedOperationException(
"The given ThreadPool is not supported by this service");
@@ -331,7 +372,7 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
/**
* The backing executor
*/
- private final ScheduledExecutorService executor;
+ private final ScheduledThreadPoolExecutor executor;
/**
* The list of active and pending futures
*/
@@ -342,9 +383,9 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
* @param name
* the pool name
* @param executor
- * the backing {@link ScheduledExecutorService}
+ * the backing {@link ScheduledThreadPoolExecutor}
*/
- public ThreadPoolImpl(String name, ScheduledExecutorService executor) {
+ public ThreadPoolImpl(String name, ScheduledThreadPoolExecutor executor) {
this.name = name;
this.executor = executor;
}
@@ -392,5 +433,10 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
}
}
}
+
+ @Override
+ public boolean isDisposed() {
+ return executor.isShutdown();
+ }
}
}
diff --git a/l2jserver2-common/src/main/java/com/l2jserver/util/ThreadPoolUtils.java b/l2jserver2-common/src/main/java/com/l2jserver/util/ThreadPoolUtils.java
new file mode 100644
index 000000000..1d04826d0
--- /dev/null
+++ b/l2jserver2-common/src/main/java/com/l2jserver/util/ThreadPoolUtils.java
@@ -0,0 +1,156 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.util;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import com.l2jserver.service.core.threading.Task;
+import com.l2jserver.service.core.threading.ThreadPool;
+
+/**
+ * @author Rogiel
+ */
+public class ThreadPoolUtils {
+ /**
+ * Wraps an {@link ThreadPool} into an {@link Executor}
+ *
+ * @param pool
+ * the pool the to be wrapped
+ * @return the wrapped {@link Executor}
+ */
+ public static ExecutorService wrap(final ThreadPool pool) {
+ return new ExecutorService() {
+ @Override
+ public void execute(final Runnable command) {
+ pool.async(wrap(command));
+ }
+
+ @Override
+ public void shutdown() {
+ pool.dispose();
+ }
+
+ @Override
+ public List shutdownNow() {
+ pool.dispose();
+ return null;
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return pool.isDisposed();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return pool.isDisposed();
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Future submit(Callable task) {
+ return pool.async(wrap(task));
+ }
+
+ @Override
+ public Future submit(Runnable task, T result) {
+ return pool.async(wrap(Executors.callable(task, result)));
+ }
+
+ @Override
+ public Future> submit(Runnable task) {
+ return pool.async(wrap(task));
+ }
+
+ @Override
+ public List> invokeAll(
+ Collection extends Callable> tasks)
+ throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List> invokeAll(
+ Collection extends Callable> tasks, long timeout,
+ TimeUnit unit) throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public T invokeAny(Collection extends Callable> tasks)
+ throws InterruptedException, ExecutionException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public T invokeAny(Collection extends Callable> tasks,
+ long timeout, TimeUnit unit) throws InterruptedException,
+ ExecutionException, TimeoutException {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Wraps an {@link Runnable} into an {@link Task}
+ *
+ * @param command
+ * the {@link Runnable} to be wrapped
+ * @return the wrapped {@link Runnable}
+ */
+ public static Task wrap(final Runnable command) {
+ return new Task() {
+ @Override
+ public Runnable call() throws Exception {
+ command.run();
+ return command;
+ }
+ };
+ }
+
+ /**
+ * Wraps an {@link Runnable} into an {@link Task}
+ *
+ * @param
+ * the {@link Task} return type
+ * @param command
+ * the {@link Runnable} to be wrapped
+ * @return the wrapped {@link Runnable}
+ */
+ public static Task wrap(final Callable command) {
+ return new Task() {
+ @Override
+ public T call() throws Exception {
+ return command.call();
+ }
+ };
+ }
+}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/L2JGameServerMain.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/L2JGameServerMain.java
index 4b13f743f..1394ad5fa 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/L2JGameServerMain.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/L2JGameServerMain.java
@@ -16,7 +16,9 @@
*/
package com.l2jserver;
+import com.l2jserver.service.Service;
import com.l2jserver.service.ServiceManager;
+import com.l2jserver.service.ServiceStopException;
import com.l2jserver.service.cache.CacheService;
import com.l2jserver.service.configuration.ConfigurationService;
import com.l2jserver.service.database.DatabaseService;
@@ -37,41 +39,42 @@ import com.l2jserver.service.network.keygen.BlowfishKeygenService;
* @author Rogiel
*/
public class L2JGameServerMain {
+ public static final Class>[] SERVICES = { CacheService.class,
+ ConfigurationService.class, DatabaseService.class,
+ WorldIDService.class, ScriptingService.class,
+ TemplateService.class, ChatService.class, NPCService.class,
+ ItemService.class, CharacterService.class, PathingService.class,
+ BlowfishKeygenService.class, NetworkService.class };
+
/**
* Main method
*
* @param args
* no arguments are used
*/
+ @SuppressWarnings("unchecked")
public static void main(String[] args) {
final L2JGameServer server = new L2JGameServer();
try {
final ServiceManager serviceManager = server.getInjector()
.getInstance(ServiceManager.class);
- serviceManager.start(CacheService.class);
- serviceManager.start(ConfigurationService.class);
- serviceManager.start(DatabaseService.class);
- serviceManager.start(WorldIDService.class);
+ for (final Class> service : SERVICES) {
+ serviceManager.start((Class extends Service>) service);
+ }
- serviceManager.start(ScriptingService.class);
- serviceManager.start(TemplateService.class);
-
- serviceManager.start(ChatService.class);
- serviceManager.start(NPCService.class);
- serviceManager.start(ItemService.class);
-
- serviceManager.start(CharacterService.class);
- serviceManager.start(PathingService.class);
-
- serviceManager.start(BlowfishKeygenService.class);
- serviceManager.start(NetworkService.class);
-
- // final long free = Runtime.getRuntime().freeMemory();
- // final long allocated = Runtime.getRuntime().totalMemory();
- // final long maximum = Runtime.getRuntime().maxMemory();
- // final long processors =
- // Runtime.getRuntime().availableProcessors();
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ for (final Class> service : SERVICES) {
+ try {
+ serviceManager
+ .stop((Class extends Service>) service);
+ } catch (ServiceStopException e) {
+ }
+ }
+ }
+ }));
} catch (Exception e) {
System.out.println("GameServer could not be started!");
e.printStackTrace();
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/model/world/character/event/CharacterStartMovingEvent.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/model/world/character/event/CharacterStartMovingEvent.java
new file mode 100644
index 000000000..f10044e37
--- /dev/null
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/model/world/character/event/CharacterStartMovingEvent.java
@@ -0,0 +1,85 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.model.world.character.event;
+
+import com.l2jserver.model.id.ObjectID;
+import com.l2jserver.model.world.Actor;
+import com.l2jserver.model.world.L2Character;
+import com.l2jserver.model.world.Player;
+import com.l2jserver.model.world.WorldObject;
+import com.l2jserver.util.geometry.Point3D;
+
+/**
+ * Event triggered once a character moves
+ *
+ * @author Rogiel
+ */
+public class CharacterStartMovingEvent implements CharacterEvent {
+ /**
+ * The character that is logging in
+ */
+ private final L2Character character;
+ /**
+ * The old point of the character
+ */
+ private final Point3D point;
+
+ /**
+ * Creates a new instance
+ *
+ * @param character
+ * the character
+ * @param point
+ * the character point before moving
+ */
+ public CharacterStartMovingEvent(L2Character character, Point3D point) {
+ this.character = character;
+ this.point = point;
+ }
+
+ /**
+ * @return the old point
+ */
+ public Point3D getPoint() {
+ return point;
+ }
+
+ @Override
+ public Player getPlayer() {
+ return character;
+ }
+
+ @Override
+ public Actor getActor() {
+ return character;
+ }
+
+ @Override
+ public WorldObject getObject() {
+ return character;
+ }
+
+ @Override
+ public L2Character getCharacter() {
+ return character;
+ }
+
+ @Override
+ public ObjectID>[] getDispatchableObjects() {
+ return new ObjectID>[] { character.getID() };
+ }
+}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java
index 2544be29d..aa5eeb2e4 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java
@@ -21,22 +21,12 @@ import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
-import com.l2jserver.game.net.Lineage2Client;
-import com.l2jserver.game.net.SystemMessage;
-import com.l2jserver.game.net.packet.server.SM_CHAR_INFO;
-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_ACTOR_CHAT;
-import com.l2jserver.game.net.packet.server.SM_ACTOR_MOVE;
-import com.l2jserver.game.net.packet.server.SM_MOVE_TYPE;
-import com.l2jserver.game.net.packet.server.SM_TARGET;
import com.l2jserver.model.dao.CharacterDAO;
import com.l2jserver.model.dao.ItemDAO;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.provider.CharacterIDProvider;
import com.l2jserver.model.id.template.CharacterTemplateID;
import com.l2jserver.model.id.template.provider.CharacterTemplateIDProvider;
-import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.model.template.actor.ActorSex;
import com.l2jserver.model.template.character.CharacterClass;
import com.l2jserver.model.template.character.CharacterTemplate;
@@ -49,21 +39,16 @@ import com.l2jserver.model.world.character.CharacterAppearance.CharacterFace;
import com.l2jserver.model.world.character.CharacterAppearance.CharacterHairColor;
import com.l2jserver.model.world.character.CharacterAppearance.CharacterHairStyle;
import com.l2jserver.model.world.character.event.CharacterEnterWorldEvent;
-import com.l2jserver.model.world.character.event.CharacterEvent;
import com.l2jserver.model.world.character.event.CharacterLeaveWorldEvent;
-import com.l2jserver.model.world.character.event.CharacterListener;
import com.l2jserver.model.world.character.event.CharacterMoveEvent;
import com.l2jserver.model.world.character.event.CharacterRunningEvent;
+import com.l2jserver.model.world.character.event.CharacterStartMovingEvent;
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.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.game.AttackService;
-import com.l2jserver.service.game.chat.ChatChannel;
-import com.l2jserver.service.game.chat.ChatChannelListener;
-import com.l2jserver.service.game.chat.ChatMessageType;
-import com.l2jserver.service.game.chat.ChatService;
import com.l2jserver.service.game.npc.NPCService;
import com.l2jserver.service.game.npc.NotAttackableNPCServiceException;
import com.l2jserver.service.game.spawn.AlreadySpawnedServiceException;
@@ -72,7 +57,6 @@ 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.WorldEventDispatcher;
-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;
@@ -83,9 +67,8 @@ import com.l2jserver.util.geometry.Point3D;
*
* @author Rogiel
*/
-@Depends({ WorldService.class, ChatService.class, NetworkService.class,
- SpawnService.class, AttackService.class, GameGuardService.class,
- BroadcastService.class })
+@Depends({ WorldService.class, SpawnService.class, AttackService.class,
+ GameGuardService.class, BroadcastService.class })
public class CharacterServiceImpl extends AbstractService implements
CharacterService {
/**
@@ -102,14 +85,6 @@ public class CharacterServiceImpl extends AbstractService implements
* The {@link WorldService} event dispatcher
*/
private final WorldEventDispatcher eventDispatcher;
- /**
- * The {@link ChatService}
- */
- private final ChatService chatService;
- /**
- * The {@link NetworkService}
- */
- private final NetworkService networkService;
/**
* The {@link SpawnService}
*/
@@ -151,10 +126,6 @@ public class CharacterServiceImpl extends AbstractService implements
* the broadcast service
* @param eventDispatcher
* the world service event dispatcher
- * @param chatService
- * the chat service
- * @param networkService
- * the network service
* @param spawnService
* the spawn service
* @param npcService
@@ -172,16 +143,13 @@ public class CharacterServiceImpl extends AbstractService implements
*/
@Inject
public CharacterServiceImpl(BroadcastService broadcastService,
- WorldEventDispatcher eventDispatcher, ChatService chatService,
- NetworkService networkService, SpawnService spawnService,
+ WorldEventDispatcher eventDispatcher, SpawnService spawnService,
NPCService npcService, GameGuardService ggService,
CharacterDAO characterDao, ItemDAO itemDao,
CharacterTemplateIDProvider charTemplateIdProvider,
CharacterIDProvider charIdProvider) {
this.broadcastService = broadcastService;
this.eventDispatcher = eventDispatcher;
- this.chatService = chatService;
- this.networkService = networkService;
this.spawnService = spawnService;
this.npcService = npcService;
this.ggService = ggService;
@@ -255,85 +223,16 @@ public class CharacterServiceImpl extends AbstractService implements
log.debug("Character {} is entering world", character);
- final CharacterID id = character.getID();
- final Lineage2Client conn = networkService.discover(id);
- if (conn == null) {
- log.debug(
- "Character {} cannot enter world, no Lineage2Client object found",
- character);
- return;
- }
-
itemDao.loadInventory(character);
-
character.setOnline(true);
-
// inventory interfere on calculators
character.getStats().updateCalculator();
- // chat listener
- final ChatChannelListener globalChatListener = new ChatChannelListener() {
- @Override
- public void onMessage(ChatChannel channel, ChatMessage message) {
- conn.write(new SM_ACTOR_CHAT(message.getSender().getObject(),
- ChatMessageType.ALL, message.getMessage()));
- }
- };
- final ChatChannelListener tradeChatListener = new ChatChannelListener() {
- @Override
- public void onMessage(ChatChannel channel, ChatMessage message) {
- conn.write(new SM_ACTOR_CHAT(message.getSender().getObject(),
- ChatMessageType.TRADE, message.getMessage()));
- }
- };
-
- // leave world event
- eventDispatcher.addListener(id, new CharacterListener() {
- @Override
- protected boolean dispatch(CharacterEvent e) {
- if (!(e instanceof CharacterLeaveWorldEvent))
- return true;
-
- log.debug(
- "Character {} is leaving world, removing chat listeners",
- character);
-
- // remove chat listeners
- chatService.getGlobalChannel().removeMessageListener(
- globalChatListener);
- chatService.getTradeChannel().removeMessageListener(
- tradeChatListener);
-
- // // remove broadcast listener
- // eventDispatcher.removeListener(neighboorListener);
- // eventDispatcher.removeListener(id, sendPacketListener);s
-
- // we can kill this listener now
- return false;
- }
- });
-
- // register global chat listener
- chatService.getGlobalChannel().addMessageListener(globalChatListener);
- chatService.getTradeChannel().addMessageListener(tradeChatListener);
-
// query client game guard -- if key is invalid, the connection will be
// closed as soon as possible
- ggService.query(conn);
-
- // send this user information
- log.debug("Sending character information packets");
- conn.write(new SM_CHAR_INFO(character));
- conn.write(new SM_CHAR_INFO_EXTRA(character));
- conn.write(new SM_CHAR_INVENTORY(character.getInventory()));
-
- log.debug("Sending greeting message to client");
- conn.sendSystemMessage(SystemMessage.WELCOME_TO_LINEAGE);
- conn.sendMessage("This an an development version for l2jserver 2.0");
- conn.sendMessage("Please note that many of the features are not yet implemented.");
-
+ ggService.query(character);
// start broadcasting -- will broadcast all nearby objects
- broadcastService.broadcast(conn);
+ broadcastService.broadcast(character);
// characters start in run mode
try {
@@ -342,14 +241,15 @@ public class CharacterServiceImpl extends AbstractService implements
// we can ignore this one
}
- // broadcast(conn, character);
-
// spawn the player -- this will also dispatch a spawn event
// here the object is registered in the world
spawnService.spawn(character, null);
// dispatch enter world event
eventDispatcher.dispatch(new CharacterEnterWorldEvent(character));
+
+ // update character
+ characterDao.save(character);
}
@Override
@@ -362,6 +262,8 @@ public class CharacterServiceImpl extends AbstractService implements
spawnService.unspawn(character);
eventDispatcher.dispatch(new CharacterLeaveWorldEvent(character));
character.setOnline(false);
+
+ characterDao.save(character);
}
@Override
@@ -372,9 +274,6 @@ public class CharacterServiceImpl extends AbstractService implements
log.debug("Setting {} target to {}", character, target);
- final CharacterID id = character.getID();
- final Lineage2Client conn = networkService.discover(id);
-
if (target == null && character.getTargetID() != null) {
// if is trying to select null (remove target) and the character has
// an target, trigger an deselect
@@ -382,7 +281,6 @@ public class CharacterServiceImpl extends AbstractService implements
character.setTargetID(null);
eventDispatcher.dispatch(new CharacterTargetDeselectedEvent(
character, oldTarget));
- // TODO we need to send an packet here to inform of deselection
} else if (target != null && !target.getID().equals(character.getID())) {
// if new target is not null and the current character target is
// null or different, trigger the selection.
@@ -395,8 +293,6 @@ public class CharacterServiceImpl extends AbstractService implements
character.setTargetID(target.getID());
eventDispatcher.dispatch(new CharacterTargetSelectedEvent(
character, target));
- conn.write(new SM_TARGET(target, character.getLevel()
- - target.getLevel()));
} else {
// this indicates an inconsistency: reset target and throws an
// exception
@@ -416,8 +312,6 @@ public class CharacterServiceImpl extends AbstractService implements
log.debug("Character {} is trying to attack {}", character, target);
- final CharacterID id = character.getID();
- final Lineage2Client conn = networkService.discover(id);
// check if this Actor can be attacked
if (target instanceof NPC) {
final NPC npc = (NPC) target;
@@ -431,11 +325,11 @@ public class CharacterServiceImpl extends AbstractService implements
// now attack the npc
log.debug("Sending {} attack request to NPCService", character);
- npcService.attack(npc, conn, character);
+ npcService.attack(npc, character);
} else {
- // TODO throw an exception
- conn.sendActionFailed();
+ throw new ActorIsNotAttackableServiceException();
}
+ characterDao.save(character);
}
@Override
@@ -463,20 +357,17 @@ public class CharacterServiceImpl extends AbstractService implements
log.debug("{} is moving to {}", character, coordinate);
- final CharacterID id = character.getID();
- final Lineage2Client conn = networkService.discover(id);
// we don't set the character coordinate here, this will be done by
// validation packets, sent by client
character.setState(ActorState.MOVING);
character.setTargetLocation(coordinate.toPoint());
- // for now, let's just write the packet, we don't have much validation
- // to be done yet. With character validation packet, another packet of
- // these will be broadcasted.
- conn.write(new SM_ACTOR_MOVE(character, coordinate));
- // we don't dispatch events here, they will be dispatched by
- // with the same packet referred up here.
+ // dispatch the start moving event. BroadcastService will catch it and
+ // notify the client.
+ eventDispatcher.dispatch(new CharacterStartMovingEvent(character,
+ coordinate.toPoint()));
+ characterDao.save(character);
}
@Override
@@ -519,8 +410,6 @@ public class CharacterServiceImpl extends AbstractService implements
public void walk(L2Character character)
throws CharacterAlreadyWalkingServiceException {
Preconditions.checkNotNull(character, "character");
- final CharacterID id = character.getID();
- final Lineage2Client conn = networkService.discover(id);
// test if character is running
if (character.getMoveType() == CharacterMoveType.WALK)
throw new CharacterAlreadyWalkingServiceException();
@@ -531,15 +420,12 @@ public class CharacterServiceImpl extends AbstractService implements
character.setMoveType(CharacterMoveType.WALK);
eventDispatcher.dispatch(new CharacterWalkingEvent(character));
- conn.write(new SM_MOVE_TYPE(character));
}
@Override
public void run(L2Character character)
throws CharacterAlreadyRunningServiceException {
Preconditions.checkNotNull(character, "character");
- final CharacterID id = character.getID();
- final Lineage2Client conn = networkService.discover(id);
// test if character is walking
if (character.getMoveType() == CharacterMoveType.RUN)
throw new CharacterAlreadyRunningServiceException();
@@ -550,6 +436,5 @@ public class CharacterServiceImpl extends AbstractService implements
character.setMoveType(CharacterMoveType.RUN);
eventDispatcher.dispatch(new CharacterRunningEvent(character));
- conn.write(new SM_MOVE_TYPE(character));
}
}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCService.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCService.java
index dbd36e853..7ce845702 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCService.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCService.java
@@ -16,7 +16,6 @@
*/
package com.l2jserver.service.game.npc;
-import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.client.CM_CHAR_ACTION.CharacterAction;
import com.l2jserver.model.template.npc.NPCTemplate;
import com.l2jserver.model.world.Actor;
@@ -97,13 +96,11 @@ public interface NPCService extends Service {
*
* @param npc
* the npc
- * @param conn
- * the {@link Lineage2Client} object
* @param attacker
* the character
* @throws NotAttackableNPCServiceException
* if {@link NPC} is not attackable
*/
- void attack(NPC npc, Lineage2Client conn, L2Character attacker)
+ void attack(NPC npc, L2Character attacker)
throws NotAttackableNPCServiceException;
}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java
index 113854a08..1b3ceebd3 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/npc/NPCServiceImpl.java
@@ -255,10 +255,9 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
}
@Override
- public void attack(NPC npc, Lineage2Client conn, L2Character attacker)
+ public void attack(NPC npc, L2Character attacker)
throws NotAttackableNPCServiceException {
Preconditions.checkNotNull(npc, "npc");
- Preconditions.checkNotNull(conn, "conn");
Preconditions.checkNotNull(attacker, "attacker");
log.debug("{} is being attacked by {}", npc, attacker);
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventDispatcherImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventDispatcherImpl.java
index 6076759f0..35fc829f7 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventDispatcherImpl.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventDispatcherImpl.java
@@ -19,7 +19,6 @@ package com.l2jserver.service.game.world.event;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
-import java.util.TimerTask;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -83,44 +82,53 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
}
/**
- * Stats the world event disptacher
+ * Stats the world event dispatcher
*/
public void start() {
- threadPool = threadService.createThreadPool("event-dispatcher", 1);
- threadPool.async(0, TimeUnit.MILLISECONDS, 20, new TimerTask() {
- @Override
- public void run() {
- EventContainer event;
- while ((event = events.poll()) != null) {
- try {
- log.debug("Dispatching event {}", event.event);
+ final int threads = Runtime.getRuntime().availableProcessors();
+ threadPool = threadService
+ .createThreadPool("event-dispatcher", threads);
+ for (int i = 0; i < threads; i++) {
+ threadPool.async(0, TimeUnit.MILLISECONDS, 10, new Runnable() {
+ @Override
+ public void run() {
+ EventContainer event;
+ while ((event = events.poll()) != null) {
+ synchronized (event) {
+ try {
+ if (event.future.isCancelled())
+ continue;
- // set state
- event.future.running = true;
- event.future.complete = false;
+ log.debug("Dispatching event {}", event.event);
- // dispatch
- if (doDispatch(event))
- // the set will update state
- event.future.set(event.event);
- } catch (Throwable t) {
- event.future.setException(t);
- log.warn("Exception in WorldEventDispatcher thread", t);
+ // set state
+ event.future.running = true;
+ event.future.complete = false;
+
+ // dispatch
+ doDispatch(event.event);
+ // the set will update state
+ event.future.set(event.event);
+ } catch (Throwable t) {
+ event.future.setException(t);
+ log.warn(
+ "Exception in WorldEventDispatcher thread",
+ t);
+ }
+ }
}
}
- }
- });
+ });
+ }
}
@Override
- public WorldEventFuture dispatch(E event) {
+ public WorldEventFuture dispatch(final E event) {
Preconditions.checkNotNull(event, "event");
log.debug("Queing dispatch for event {}", event);
+
final WorldEventFutureImpl future = new WorldEventFutureImpl();
events.add(new EventContainer(event, future));
- // final WorldEventFutureImpl future = new WorldEventFutureImpl();
- // final EventContainer c = new EventContainer(event, future);
- // doDispatch(c);
return future;
}
@@ -129,18 +137,15 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
*
* @param event
* the event
- * @return true if dispatch was not canceled
*/
- public synchronized boolean doDispatch(EventContainer event) {
- final ObjectID>[] objects = event.event.getDispatchableObjects();
+ private synchronized void doDispatch(WorldEvent event) {
+ final ObjectID>[] objects = event.getDispatchableObjects();
for (ObjectID> obj : objects) {
if (obj == null)
continue;
for (final WorldListener listener : globalListeners) {
- if (event.future.isCancelled())
- return false;
try {
- if (!listener.dispatch(event.event))
+ if (!listener.dispatch(event))
// remove listener if return value is false
globalListeners.remove(listener);
} catch (Throwable t) {
@@ -151,10 +156,8 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
}
final Set listeners = getListeners(obj);
for (final WorldListener listener : listeners) {
- if (event.future.isCancelled())
- return false;
try {
- if (!listener.dispatch(event.event))
+ if (!listener.dispatch(event))
// remove listener if return value is false
listeners.remove(listener);
} catch (Throwable t) {
@@ -164,7 +167,6 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
}
}
}
- return true;
}
@Override
@@ -288,10 +290,10 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
}
@Override
- public void await() throws InterruptedException {
+ public void await() throws ExecutionException {
try {
super.get();
- } catch (ExecutionException e) {
+ } catch (InterruptedException e) {
}
}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventFuture.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventFuture.java
index 772a9baf2..a4e76b182 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventFuture.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/world/event/WorldEventFuture.java
@@ -16,6 +16,7 @@
*/
package com.l2jserver.service.game.world.event;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -34,10 +35,10 @@ public interface WorldEventFuture extends Future {
/**
* Waits until the event is dispatched to all listeners
*
- * @throws InterruptedException
- * if the thread has been interrupted while waiting
+ * @throws ExecutionException
+ * if any error occur while dispatching the event
*/
- void await() throws InterruptedException;
+ void await() throws ExecutionException;
/**
* Waits until the event is dispatched to all listeners
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/NettyNetworkService.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/NettyNetworkService.java
index 1368917b6..140443f55 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/NettyNetworkService.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/NettyNetworkService.java
@@ -17,7 +17,7 @@
package com.l2jserver.service.network;
import java.util.Set;
-import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFuture;
@@ -26,6 +26,8 @@ import org.jboss.netty.channel.ServerChannel;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.logging.Slf4JLoggerFactory;
+import org.jboss.netty.util.ThreadNameDeterminer;
+import org.jboss.netty.util.ThreadRenamingRunnable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,8 +43,12 @@ import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.configuration.ConfigurationService;
import com.l2jserver.service.core.LoggingService;
+import com.l2jserver.service.core.threading.ThreadPool;
+import com.l2jserver.service.core.threading.ThreadPoolPriority;
+import com.l2jserver.service.core.threading.ThreadService;
import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.network.keygen.BlowfishKeygenService;
+import com.l2jserver.util.ThreadPoolUtils;
import com.l2jserver.util.factory.CollectionFactory;
/**
@@ -50,8 +56,8 @@ import com.l2jserver.util.factory.CollectionFactory;
*
* @author Rogiel
*/
-@Depends({ LoggingService.class, BlowfishKeygenService.class,
- WorldService.class })
+@Depends({ LoggingService.class, ThreadService.class,
+ BlowfishKeygenService.class, WorldService.class })
public class NettyNetworkService extends AbstractService implements
NetworkService {
/**
@@ -59,6 +65,11 @@ public class NettyNetworkService extends AbstractService implements
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
+ /**
+ * The {@link ThreadService}
+ */
+ private final ThreadService threadService;
+
/**
* The network configuration object
*/
@@ -68,6 +79,14 @@ public class NettyNetworkService extends AbstractService implements
*/
private final Injector injector;
+ /**
+ * Netty Boss {@link ThreadPool}
+ */
+ private ThreadPool bossPool;
+ /**
+ * Netty Worker {@link ThreadPool}
+ */
+ private ThreadPool workerPool;
/**
* The server bootstrap
*/
@@ -86,10 +105,13 @@ public class NettyNetworkService extends AbstractService implements
* the configuration service
* @param injector
* the {@link Guice} {@link Injector}
+ * @param threadService
+ * the {@link ThreadService}
*/
@Inject
public NettyNetworkService(ConfigurationService configService,
- Injector injector) {
+ Injector injector, ThreadService threadService) {
+ this.threadService = threadService;
this.config = configService.get(NetworkConfiguration.class);
this.injector = injector;
InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory());
@@ -97,9 +119,24 @@ public class NettyNetworkService extends AbstractService implements
@Override
protected void doStart() {
+ bossPool = threadService.createThreadPool("netty-boss", 10, 60,
+ TimeUnit.SECONDS, ThreadPoolPriority.HIGH);
+ workerPool = threadService.createThreadPool("netty-worker", 50, 60,
+ TimeUnit.SECONDS, ThreadPoolPriority.HIGH);
+
+ ThreadRenamingRunnable
+ .setThreadNameDeterminer(new ThreadNameDeterminer() {
+ @Override
+ public String determineThreadName(String currentThreadName,
+ String proposedThreadName) throws Exception {
+ return currentThreadName;
+ }
+ });
+
server = new ServerBootstrap(new NioServerSocketChannelFactory(
- Executors.newCachedThreadPool(),
- Executors.newCachedThreadPool()));
+ ThreadPoolUtils.wrap(bossPool),
+ ThreadPoolUtils.wrap(workerPool), 50));
+
server.setPipelineFactory(new Lineage2PipelineFactory(injector, this));
channel = (ServerChannel) server.bind(config.getListenAddress());
}
@@ -160,9 +197,15 @@ public class NettyNetworkService extends AbstractService implements
protected void doStop() {
try {
channel.close().awaitUninterruptibly();
+ server.releaseExternalResources();
+ bossPool.dispose();
+ workerPool.dispose();
} finally {
server = null;
channel = null;
+ bossPool = null;
+ workerPool = null;
}
+ clients.clear();
}
}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastService.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastService.java
index d75057ba1..9b71c7068 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastService.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastService.java
@@ -16,7 +16,7 @@
*/
package com.l2jserver.service.network.broadcast;
-import com.l2jserver.game.net.Lineage2Client;
+import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.WorldObject;
import com.l2jserver.service.Service;
@@ -31,7 +31,7 @@ public interface BroadcastService extends Service {
* Broadcast all nearby objects to the given client
*
* @param conn
- * the Lineage 2 client
+ * the character
*/
- void broadcast(Lineage2Client conn);
+ void broadcast(L2Character conn);
}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java
index a969376fb..cfcb2e050 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java
@@ -23,16 +23,22 @@ import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.l2jserver.game.net.Lineage2Client;
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_ACTOR_CHAT;
import com.l2jserver.game.net.packet.server.SM_ACTOR_DIE;
+import com.l2jserver.game.net.packet.server.SM_ACTOR_MOVE;
+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_ITEM_GROUND;
import com.l2jserver.game.net.packet.server.SM_ITEM_PICK;
-import com.l2jserver.game.net.packet.server.SM_ACTOR_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.server.ChatMessage;
import com.l2jserver.model.world.Item;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
@@ -43,9 +49,13 @@ import com.l2jserver.model.world.actor.event.ActorDieEvent;
import com.l2jserver.model.world.actor.event.ActorTeleportingEvent;
import com.l2jserver.model.world.actor.event.ActorUnspawnEvent;
import com.l2jserver.model.world.character.event.CharacterEnterWorldEvent;
+import com.l2jserver.model.world.character.event.CharacterEvent;
import com.l2jserver.model.world.character.event.CharacterLeaveWorldEvent;
+import com.l2jserver.model.world.character.event.CharacterListener;
import com.l2jserver.model.world.character.event.CharacterMoveEvent;
import com.l2jserver.model.world.character.event.CharacterRunningEvent;
+import com.l2jserver.model.world.character.event.CharacterStartMovingEvent;
+import com.l2jserver.model.world.character.event.CharacterTargetSelectedEvent;
import com.l2jserver.model.world.character.event.CharacterWalkingEvent;
import com.l2jserver.model.world.item.ItemDropEvent;
import com.l2jserver.model.world.item.ItemPickEvent;
@@ -53,6 +63,10 @@ import com.l2jserver.model.world.npc.event.NPCSpawnEvent;
import com.l2jserver.model.world.player.event.PlayerTeleportedEvent;
import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
+import com.l2jserver.service.game.chat.ChatChannel;
+import com.l2jserver.service.game.chat.ChatChannelListener;
+import com.l2jserver.service.game.chat.ChatMessageType;
+import com.l2jserver.service.game.chat.ChatService;
import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.game.world.event.FilteredWorldListener;
import com.l2jserver.service.game.world.event.WorldEvent;
@@ -78,6 +92,15 @@ public class BroadcastServiceImpl extends AbstractService implements
* The world service
*/
private final WorldService worldService;
+ /**
+ * The {@link ChatService}
+ */
+ private final ChatService chatService;
+ /**
+ * The {@link ChatService}
+ */
+ private final NetworkService networkService;
+
/**
* The world service event dispatcher
*/
@@ -86,21 +109,28 @@ public class BroadcastServiceImpl extends AbstractService implements
/**
* @param worldService
* the world service
+ * @param chatService
+ * the chat service
+ * @param networkService
+ * the network service
* @param eventDispatcher
* the world service event disptacher
*/
@Inject
public BroadcastServiceImpl(WorldService worldService,
+ ChatService chatService, NetworkService networkService,
WorldEventDispatcher eventDispatcher) {
this.worldService = worldService;
+ this.chatService = chatService;
+ this.networkService = networkService;
this.eventDispatcher = eventDispatcher;
}
@Override
- public void broadcast(final Lineage2Client conn) {
- Preconditions.checkNotNull(conn, "conn");
- final L2Character character = conn.getCharacter();
+ public void broadcast(final L2Character character) {
Preconditions.checkNotNull(character, "character");
+ final Lineage2Client conn = networkService.discover(character.getID());
+ Preconditions.checkNotNull(conn, "conn");
final CharacterID id = character.getID();
log.debug("Starting character broadcast");
@@ -121,8 +151,8 @@ public class BroadcastServiceImpl extends AbstractService implements
broadcast(conn, e.getObject());
} else if (e instanceof CharacterMoveEvent) {
final CharacterMoveEvent evt = (CharacterMoveEvent) e;
- conn.write(new SM_ACTOR_MOVE((L2Character) object, evt.getPoint()
- .getCoordinate()));
+ conn.write(new SM_ACTOR_MOVE((L2Character) object, evt
+ .getPoint().getCoordinate()));
} else if (e instanceof PlayerTeleportedEvent
|| e instanceof CharacterEnterWorldEvent) {
broadcast(conn, e.getObject());
@@ -134,7 +164,6 @@ public class BroadcastServiceImpl extends AbstractService implements
|| e instanceof CharacterLeaveWorldEvent
|| e instanceof ActorUnspawnEvent) {
// object is now out of sight
- // FIXME pick up animation is not happening
conn.write(new SM_OBJECT_REMOVE(object));
} else if (e instanceof CharacterWalkingEvent) {
conn.write(new SM_MOVE_TYPE(((CharacterWalkingEvent) e)
@@ -160,15 +189,93 @@ public class BroadcastServiceImpl extends AbstractService implements
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) {
+ broadcastUpdate(conn, evt.getCharacter(), evt.getPoint());
+ } else if (e instanceof CharacterEnterWorldEvent) {
+ final CharacterEnterWorldEvent evt = (CharacterEnterWorldEvent) e;
+ final L2Character character = evt.getCharacter();
+ final CharacterID id = character.getID();
+
+ // chat listener
+ final ChatChannelListener globalChatListener = new ChatChannelListener() {
+ @Override
+ public void onMessage(ChatChannel channel,
+ ChatMessage message) {
+ conn.write(new SM_ACTOR_CHAT(message.getSender()
+ .getObject(), ChatMessageType.ALL, message
+ .getMessage()));
+ }
+ };
+ final ChatChannelListener tradeChatListener = new ChatChannelListener() {
+ @Override
+ public void onMessage(ChatChannel channel,
+ ChatMessage message) {
+ conn.write(new SM_ACTOR_CHAT(message.getSender()
+ .getObject(), ChatMessageType.TRADE,
+ message.getMessage()));
+ }
+ };
+
+ // leave world event
+ eventDispatcher.addListener(id, new CharacterListener() {
+ @Override
+ protected boolean dispatch(CharacterEvent e) {
+ if (!(e instanceof CharacterLeaveWorldEvent))
+ return true;
+
+ log.debug(
+ "Character {} is leaving world, removing chat listeners",
+ character);
+
+ // remove chat listeners
+ chatService.getGlobalChannel()
+ .removeMessageListener(globalChatListener);
+ chatService.getTradeChannel()
+ .removeMessageListener(tradeChatListener);
+
+ // we can kill this listener now
+ return false;
+ }
+ });
+
+ // register global chat listener
+ chatService.getGlobalChannel().addMessageListener(
+ globalChatListener);
+ chatService.getTradeChannel().addMessageListener(
+ tradeChatListener);
+
+ log.debug("Sending greeting message to client");
+ conn.sendSystemMessage(SystemMessage.WELCOME_TO_LINEAGE);
+ conn.sendMessage("This an an development version for l2jserver 2.0");
+ conn.sendMessage("Please note that many of the features are not yet implemented.");
+
+ // send this user information
+ log.debug("Sending character information packets");
+ conn.write(new SM_CHAR_INFO(evt.getCharacter()));
+ conn.write(new SM_CHAR_INFO_EXTRA(evt.getCharacter()));
+ conn.write(new SM_CHAR_INVENTORY(evt.getCharacter()
+ .getInventory()));
+
+ broadcastAll(conn, character);
+ } else if (e instanceof CharacterStartMovingEvent) {
+ conn.write(new SM_ACTOR_MOVE(
+ ((CharacterStartMovingEvent) e).getCharacter(),
+ ((CharacterStartMovingEvent) e).getPoint()
+ .getCoordinate()));
+ } else if (e instanceof CharacterTargetSelectedEvent) {
+ final CharacterTargetSelectedEvent evt = (CharacterTargetSelectedEvent) e;
+ conn.write(new SM_TARGET(evt.getTarget(), evt
+ .getCharacter().getLevel()
+ - evt.getTarget().getLevel()));
+ } else if (e instanceof PlayerTeleportedEvent) {
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());
+ } else if (e instanceof CharacterWalkingEvent
+ || e instanceof CharacterRunningEvent) {
+ conn.write(new SM_MOVE_TYPE((L2Character) e.getObject()));
}
// keep listener alive
return true;
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardService.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardService.java
index 5a4aa38af..0837ea1f5 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardService.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardService.java
@@ -19,6 +19,7 @@ package com.l2jserver.service.network.gameguard;
import java.util.concurrent.Future;
import com.l2jserver.game.net.Lineage2Client;
+import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.Service;
/**
@@ -30,11 +31,11 @@ public interface GameGuardService extends Service {
/**
* Queries the client GameGuard for an response
*
- * @param conn
- * the lineage 2 connection
+ * @param character
+ * the lineage 2 character
* @return an future that will be used to obtain validation status
*/
- Future query(Lineage2Client conn);
+ Future query(L2Character character);
/**
* The Game guard key state
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardServiceImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardServiceImpl.java
index faa527499..f27f4721a 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardServiceImpl.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/gameguard/GameGuardServiceImpl.java
@@ -27,12 +27,15 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.util.concurrent.AbstractFuture;
+import com.google.inject.Inject;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.server.SM_GG_QUERY;
+import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.ServiceStartException;
import com.l2jserver.service.ServiceStopException;
+import com.l2jserver.service.game.chat.ChatService;
import com.l2jserver.service.network.NetworkService;
import com.l2jserver.util.factory.CollectionFactory;
@@ -64,6 +67,11 @@ public class GameGuardServiceImpl extends AbstractService implements
(byte) 0xde, (byte) 0xc3, 0x68, (byte) 0xf6, 0x2d, 0x23,
(byte) 0xf1, 0x3f, (byte) 0xee, 0x68, 0x5b, (byte) 0xc5 };
+ /**
+ * The {@link ChatService}
+ */
+ private final NetworkService networkService;
+
/**
* The map containing all pending futures
*/
@@ -76,6 +84,15 @@ public class GameGuardServiceImpl extends AbstractService implements
@SuppressWarnings("unused")
private MessageDigest digester;
+ /**
+ * @param networkService
+ * the network service
+ */
+ @Inject
+ private GameGuardServiceImpl(NetworkService networkService) {
+ this.networkService = networkService;
+ }
+
@Override
protected void doStart() throws ServiceStartException {
futures = CollectionFactory.newMap();
@@ -87,8 +104,9 @@ public class GameGuardServiceImpl extends AbstractService implements
}
@Override
- public Future query(final Lineage2Client conn) {
+ public Future query(final L2Character character) {
log.debug("Quering client for GameGuard authentication key");
+ final Lineage2Client conn = networkService.discover(character.getID());
conn.write(new SM_GG_QUERY(STATIC_KEY)).addListener(
new ChannelFutureListener() {
@Override