1
0
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:
2011-12-18 18:07:59 -02:00
parent 87a1c0d3a5
commit b9e460b70c
17 changed files with 702 additions and 244 deletions

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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();
}
}
}

View File

@@ -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();
}
};
}
}

View File

@@ -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();

View File

@@ -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() };
}
}

View File

@@ -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));
}
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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) {
}
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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