mirror of
https://github.com/Rogiel/l2jserver2
synced 2025-12-06 07:32:46 +00:00
Decouples CharacterService from NetworkService
This commit is contained in:
@@ -19,8 +19,7 @@ package com.l2jserver.service.core.threading;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This is an ThreadPool you can use it to schedule tasks in the future or to
|
||||
* repeat them many times.
|
||||
* This is an ThreadPool that you can use to asynchronously execute tasks.
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@@ -72,4 +71,9 @@ public interface ThreadPool {
|
||||
* execute tasks.
|
||||
*/
|
||||
void dispose();
|
||||
|
||||
/**
|
||||
* @return true if the thread pool is no longer usable (i.e. was disposed)
|
||||
*/
|
||||
boolean isDisposed();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of l2jserver2 <l2jserver2.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.service.core.threading;
|
||||
|
||||
/**
|
||||
* The priority of the thread pool
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
public enum ThreadPoolPriority {
|
||||
/**
|
||||
* High priority.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Processor will block {@link ThreadPoolPriority#LOW} priority threads in
|
||||
* order to finish tasks in pools on this priority.
|
||||
*/
|
||||
NORMAL(Thread.NORM_PRIORITY),
|
||||
/**
|
||||
* Low priority.
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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 <code>threadTimeout</code>
|
||||
* @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 <code>threadTimeout</code>
|
||||
* @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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* This file is part of l2jserver2 <l2jserver2.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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 <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
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<Runnable> 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 <T> Future<T> submit(Callable<T> task) {
|
||||
return pool.async(wrap(task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> 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 <T> List<Future<T>> invokeAll(
|
||||
Collection<? extends Callable<T>> tasks)
|
||||
throws InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<Future<T>> invokeAll(
|
||||
Collection<? extends Callable<T>> tasks, long timeout,
|
||||
TimeUnit unit) throws InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
|
||||
throws InterruptedException, ExecutionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T invokeAny(Collection<? extends Callable<T>> 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<Runnable> wrap(final Runnable command) {
|
||||
return new Task<Runnable>() {
|
||||
@Override
|
||||
public Runnable call() throws Exception {
|
||||
command.run();
|
||||
return command;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an {@link Runnable} into an {@link Task}
|
||||
*
|
||||
* @param <T>
|
||||
* the {@link Task} return type
|
||||
* @param command
|
||||
* the {@link Runnable} to be wrapped
|
||||
* @return the wrapped {@link Runnable}
|
||||
*/
|
||||
public static <T> Task<T> wrap(final Callable<T> command) {
|
||||
return new Task<T>() {
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
return command.call();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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 <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
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();
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of l2jserver2 <l2jserver2.com>.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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 <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
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() };
|
||||
}
|
||||
}
|
||||
@@ -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 <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,16 +82,23 @@ 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() {
|
||||
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;
|
||||
|
||||
log.debug("Dispatching event {}", event.event);
|
||||
|
||||
// set state
|
||||
@@ -100,27 +106,29 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
|
||||
event.future.complete = false;
|
||||
|
||||
// dispatch
|
||||
if (doDispatch(event))
|
||||
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);
|
||||
log.warn(
|
||||
"Exception in WorldEventDispatcher thread",
|
||||
t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends WorldEvent> WorldEventFuture<E> dispatch(E event) {
|
||||
public <E extends WorldEvent> WorldEventFuture<E> dispatch(final E event) {
|
||||
Preconditions.checkNotNull(event, "event");
|
||||
log.debug("Queing dispatch for event {}", event);
|
||||
|
||||
final WorldEventFutureImpl<E> future = new WorldEventFutureImpl<E>();
|
||||
events.add(new EventContainer(event, future));
|
||||
// final WorldEventFutureImpl<E> future = new WorldEventFutureImpl<E>();
|
||||
// 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<WorldListener> 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) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<E extends WorldEvent> extends Future<E> {
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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 <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <tt>client</tt>
|
||||
*
|
||||
* @param conn
|
||||
* the Lineage 2 client
|
||||
* the character
|
||||
*/
|
||||
void broadcast(Lineage2Client conn);
|
||||
void broadcast(L2Character conn);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<GameGuardResponse> query(Lineage2Client conn);
|
||||
Future<GameGuardResponse> query(L2Character character);
|
||||
|
||||
/**
|
||||
* The Game guard key state
|
||||
|
||||
@@ -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<GameGuardResponse> query(final Lineage2Client conn) {
|
||||
public Future<GameGuardResponse> 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
|
||||
|
||||
Reference in New Issue
Block a user