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

ThreadService implementation

Signed-off-by: Rogiel <rogiel@rogiel.com>
This commit is contained in:
2011-05-27 12:35:05 -03:00
parent 73f51e53c0
commit faec07b8d5
23 changed files with 532 additions and 85 deletions

View File

@@ -0,0 +1,38 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.game.ai;
import com.l2jserver.game.ai.desires.Desire;
import com.l2jserver.model.world.NPC;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class MonsterAI extends NPCAI {
/**
* @param creature
*/
protected MonsterAI(NPC creature) {
super(creature);
}
@Override
protected void handleDesire(Desire desire) {
super.handleDesire(desire);
}
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.game.ai;
import com.google.inject.Inject;
import com.l2jserver.game.ai.desires.Desire;
import com.l2jserver.game.ai.desires.MoveDesire;
import com.l2jserver.model.world.NPC;
import com.l2jserver.service.game.npc.NPCService;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class NPCAI extends AI<NPC> {
@Inject
protected NPCService npcService;
/**
* @param npc
* the npc
*/
protected NPCAI(NPC npc) {
super(npc);
}
@Override
protected void handleDesire(Desire desire) {
if (desire instanceof MoveDesire) {
}
}
}

View File

@@ -16,6 +16,7 @@
*/ */
package com.l2jserver.db.dao.h2; package com.l2jserver.db.dao.h2;
import com.google.inject.Inject;
import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.jdbc.JDBCCharacterDAO; import com.l2jserver.db.dao.jdbc.JDBCCharacterDAO;
import com.l2jserver.model.id.object.provider.CharacterIDProvider; import com.l2jserver.model.id.object.provider.CharacterIDProvider;
@@ -31,6 +32,7 @@ import com.l2jserver.service.database.DatabaseService;
*/ */
public class H2CharacterDAO extends JDBCCharacterDAO implements public class H2CharacterDAO extends JDBCCharacterDAO implements
CharacterDAO { CharacterDAO {
@Inject
public H2CharacterDAO(DatabaseService database, public H2CharacterDAO(DatabaseService database,
CharacterIDProvider idFactory, CharacterIDProvider idFactory,
CharacterTemplateIDProvider templateIdFactory, CharacterTemplateIDProvider templateIdFactory,

View File

@@ -16,6 +16,7 @@
*/ */
package com.l2jserver.db.dao.h2; package com.l2jserver.db.dao.h2;
import com.google.inject.Inject;
import com.l2jserver.db.dao.CharacterFriendDAO; import com.l2jserver.db.dao.CharacterFriendDAO;
import com.l2jserver.db.dao.jdbc.JDBCCharacterFriendDAO; import com.l2jserver.db.dao.jdbc.JDBCCharacterFriendDAO;
import com.l2jserver.model.id.object.provider.CharacterIDProvider; import com.l2jserver.model.id.object.provider.CharacterIDProvider;
@@ -29,6 +30,7 @@ import com.l2jserver.service.database.DatabaseService;
*/ */
public class H2CharacterFriendDAO extends JDBCCharacterFriendDAO implements public class H2CharacterFriendDAO extends JDBCCharacterFriendDAO implements
CharacterFriendDAO { CharacterFriendDAO {
@Inject
public H2CharacterFriendDAO(DatabaseService database, public H2CharacterFriendDAO(DatabaseService database,
FriendIDProvider idProvider, CharacterIDProvider charIdProvider) { FriendIDProvider idProvider, CharacterIDProvider charIdProvider) {
super(database, idProvider, charIdProvider); super(database, idProvider, charIdProvider);

View File

@@ -16,6 +16,7 @@
*/ */
package com.l2jserver.db.dao.h2; package com.l2jserver.db.dao.h2;
import com.google.inject.Inject;
import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.ClanDAO; import com.l2jserver.db.dao.ClanDAO;
import com.l2jserver.db.dao.jdbc.JDBCClanDAO; import com.l2jserver.db.dao.jdbc.JDBCClanDAO;
@@ -29,6 +30,7 @@ import com.l2jserver.service.database.DatabaseService;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public class H2ClanDAO extends JDBCClanDAO implements ClanDAO { public class H2ClanDAO extends JDBCClanDAO implements ClanDAO {
@Inject
public H2ClanDAO(DatabaseService database, public H2ClanDAO(DatabaseService database,
ClanIDProvider clanIdFactory, CharacterIDProvider idFactory) { ClanIDProvider clanIdFactory, CharacterIDProvider idFactory) {
super(database, clanIdFactory, idFactory); super(database, clanIdFactory, idFactory);

View File

@@ -16,6 +16,7 @@
*/ */
package com.l2jserver.db.dao.h2; package com.l2jserver.db.dao.h2;
import com.google.inject.Inject;
import com.l2jserver.db.dao.ItemDAO; import com.l2jserver.db.dao.ItemDAO;
import com.l2jserver.db.dao.jdbc.JDBCItemDAO; import com.l2jserver.db.dao.jdbc.JDBCItemDAO;
import com.l2jserver.model.id.object.provider.CharacterIDProvider; import com.l2jserver.model.id.object.provider.CharacterIDProvider;
@@ -29,6 +30,7 @@ import com.l2jserver.service.database.DatabaseService;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public class H2ItemDAO extends JDBCItemDAO implements ItemDAO { public class H2ItemDAO extends JDBCItemDAO implements ItemDAO {
@Inject
public H2ItemDAO(DatabaseService database, ItemIDProvider idFactory, public H2ItemDAO(DatabaseService database, ItemIDProvider idFactory,
ItemTemplateIDProvider templateIdFactory, ItemTemplateIDProvider templateIdFactory,
CharacterIDProvider charIdFactory) { CharacterIDProvider charIdFactory) {

View File

@@ -16,6 +16,7 @@
*/ */
package com.l2jserver.db.dao.h2; package com.l2jserver.db.dao.h2;
import com.google.inject.Inject;
import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.NPCDAO; import com.l2jserver.db.dao.NPCDAO;
import com.l2jserver.db.dao.jdbc.JDBCNPCDAO; import com.l2jserver.db.dao.jdbc.JDBCNPCDAO;
@@ -29,6 +30,7 @@ import com.l2jserver.service.database.DatabaseService;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public class H2NPCDAO extends JDBCNPCDAO implements NPCDAO { public class H2NPCDAO extends JDBCNPCDAO implements NPCDAO {
@Inject
public H2NPCDAO(DatabaseService database, NPCIDProvider idProvider, public H2NPCDAO(DatabaseService database, NPCIDProvider idProvider,
NPCTemplateIDProvider templateIdProvider) { NPCTemplateIDProvider templateIdProvider) {
super(database, idProvider, templateIdProvider); super(database, idProvider, templateIdProvider);

View File

@@ -16,9 +16,11 @@
*/ */
package com.l2jserver.game.ai; package com.l2jserver.game.ai;
import com.google.inject.Inject;
import com.l2jserver.game.ai.desires.Desire; import com.l2jserver.game.ai.desires.Desire;
import com.l2jserver.game.ai.desires.DesireQueue; import com.l2jserver.game.ai.desires.DesireQueue;
import com.l2jserver.model.world.Actor; import com.l2jserver.model.world.Actor;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
@@ -26,14 +28,35 @@ import com.l2jserver.model.world.Actor;
* the {@link Actor} type for this {@link AI} * the {@link Actor} type for this {@link AI}
*/ */
public abstract class AI<T extends Actor> { public abstract class AI<T extends Actor> {
/**
* The desire queue for this AI
*/
protected DesireQueue desireQueue = new DesireQueue(); protected DesireQueue desireQueue = new DesireQueue();
protected final T creature; /**
* The actor controlled by this AI
*/
protected final T actor;
protected AI(T creature) { @Inject
this.creature = creature; protected WorldEventDispatcher eventDispatcher;
protected AI(T actor) {
this.actor = actor;
} }
protected void handleDesire(Desire desire) { /**
desire.handleDesire(this); * Executes an AI tick
*/
protected void tick() {
Desire desire = desireQueue.poll();
handleDesire(desire);
} }
/**
* Handles the given desire
*
* @param desire
* the desire
*/
protected abstract void handleDesire(Desire desire);
} }

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jserver.game.ai.desires; package com.l2jserver.game.ai.desires;
import com.l2jserver.game.ai.AI;
import com.l2jserver.model.world.Actor; import com.l2jserver.model.world.Actor;
/** /**
@@ -43,11 +42,6 @@ public final class AttackDesire extends AbstractDesire {
this.target = target; this.target = target;
} }
@Override
public void handleDesire(AI<?> ai) {
// TODO: Implement
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) if (this == o)

View File

@@ -16,14 +16,8 @@
*/ */
package com.l2jserver.game.ai.desires; package com.l2jserver.game.ai.desires;
import com.l2jserver.game.ai.AI;
/** /**
* This interface represents basic desire functions.<br> * This interface represents basic desire functions.
* Each desire should implement {@link #handleDesire(com.l2jserver.game.ai.AI)}
* method with default behavior.<br>
* AI can override {@link com.l2jserver.game.ai.AI#handleDesire(Desire)} to
* implement custom behavior of desire.<br>
* *
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
* @see com.l2jserver.game.ai.AI * @see com.l2jserver.game.ai.AI
@@ -31,15 +25,6 @@ import com.l2jserver.game.ai.AI;
* @see com.l2jserver.game.ai.desires.AbstractDesire * @see com.l2jserver.game.ai.desires.AbstractDesire
*/ */
public interface Desire extends Comparable<Desire> { public interface Desire extends Comparable<Desire> {
/**
* Invokes default desire action. AI can override invocation of this method
* to handle desire in it's own way
*
* @param ai
* actor that is doing this desire
*/
void handleDesire(AI<?> ai);
/** /**
* Returns hashcode for this object, must be overrided by child * Returns hashcode for this object, must be overrided by child
* *

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jserver.game.ai.desires; package com.l2jserver.game.ai.desires;
import com.l2jserver.game.ai.AI;
import com.l2jserver.model.world.Actor; import com.l2jserver.model.world.Actor;
import com.l2jserver.util.geometry.Point3D; import com.l2jserver.util.geometry.Point3D;
@@ -44,14 +43,6 @@ public final class MoveDesire extends AbstractDesire {
this.point = point; this.point = point;
} }
@Override
public void handleDesire(AI<?> ai) {
// TODO: Implement
}
/**
* {@inheritDoc}
*/
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) if (this == o)
@@ -64,9 +55,6 @@ public final class MoveDesire extends AbstractDesire {
return point.equals(that.point); return point.equals(that.point);
} }
/**
* {@inheritDoc}
*/
@Override @Override
public int hashCode() { public int hashCode() {
return point.hashCode(); return point.hashCode();

View File

@@ -25,6 +25,7 @@ import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.id.object.NPCID; import com.l2jserver.model.id.object.NPCID;
import com.l2jserver.model.id.object.provider.ObjectIDResolver; import com.l2jserver.model.id.object.provider.ObjectIDResolver;
import com.l2jserver.model.world.NPC; import com.l2jserver.model.world.NPC;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.npc.ActionServiceException; import com.l2jserver.service.game.npc.ActionServiceException;
import com.l2jserver.service.game.npc.NPCService; import com.l2jserver.service.game.npc.NPCService;
import com.l2jserver.util.geometry.Coordinate; import com.l2jserver.util.geometry.Coordinate;
@@ -97,6 +98,8 @@ public class CharacterActionPacket extends AbstractClientPacket {
npcService.action(npc, conn.getCharacter(), action); npcService.action(npc, conn.getCharacter(), action);
} catch (ActionServiceException e) { } catch (ActionServiceException e) {
conn.sendActionFailed(); conn.sendActionFailed();
} catch (CannotSetTargetServiceException e) {
conn.sendActionFailed();
} }
} }
} }

View File

@@ -27,6 +27,7 @@ import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.id.object.NPCID; import com.l2jserver.model.id.object.NPCID;
import com.l2jserver.model.id.object.provider.ObjectIDResolver; import com.l2jserver.model.id.object.provider.ObjectIDResolver;
import com.l2jserver.model.world.NPC; import com.l2jserver.model.world.NPC;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.npc.ActionServiceException; import com.l2jserver.service.game.npc.ActionServiceException;
import com.l2jserver.service.game.npc.NPCService; import com.l2jserver.service.game.npc.NPCService;
import com.l2jserver.util.BufferUtils; import com.l2jserver.util.BufferUtils;
@@ -86,6 +87,8 @@ public class CharacterRequestBypass extends AbstractClientPacket {
createArgumentArray(tokenizer)); createArgumentArray(tokenizer));
} catch (ActionServiceException e) { } catch (ActionServiceException e) {
conn.sendActionFailed(); conn.sendActionFailed();
} catch (CannotSetTargetServiceException e) {
conn.sendActionFailed();
} }
} }
} }

View File

@@ -29,6 +29,12 @@ import com.l2jserver.service.game.ai.AIScript;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public class NPC extends Actor { public class NPC extends Actor {
private NPCState state;
public enum NPCState {
MOVING, ATTACKING;
}
/** /**
* Creates a new instance * Creates a new instance
* *
@@ -39,6 +45,42 @@ public class NPC extends Actor {
super(templateID); super(templateID);
} }
/**
* @return the state
*/
public NPCState getState() {
return state;
}
/**
* @return true if NPC is idle
*/
public boolean isIdle() {
return state == null;
}
/**
* @return true if NPC is idle
*/
public boolean isMoving() {
return state == NPCState.MOVING;
}
/**
* @return true if NPC is idle
*/
public boolean isAttacking() {
return state == NPCState.ATTACKING;
}
/**
* @param state
* the state to set
*/
public void setState(NPCState state) {
this.state = state;
}
@Override @Override
public ActorSex getSex() { public ActorSex getSex() {
return this.getTemplate().getSex(); return this.getTemplate().getSex();

View File

@@ -25,6 +25,8 @@ import com.l2jserver.service.configuration.ConfigurationService;
import com.l2jserver.service.configuration.ProxyConfigurationService; import com.l2jserver.service.configuration.ProxyConfigurationService;
import com.l2jserver.service.core.Log4JLoggingService; import com.l2jserver.service.core.Log4JLoggingService;
import com.l2jserver.service.core.LoggingService; import com.l2jserver.service.core.LoggingService;
import com.l2jserver.service.core.threading.ThreadService;
import com.l2jserver.service.core.threading.ThreadServiceImpl;
import com.l2jserver.service.core.vfs.VFSService; import com.l2jserver.service.core.vfs.VFSService;
import com.l2jserver.service.core.vfs.VFSServiceImpl; import com.l2jserver.service.core.vfs.VFSServiceImpl;
import com.l2jserver.service.database.DatabaseService; import com.l2jserver.service.database.DatabaseService;
@@ -66,9 +68,12 @@ public class ServiceModule extends AbstractModule {
bind(LoggingService.class).to(Log4JLoggingService.class).in( bind(LoggingService.class).to(Log4JLoggingService.class).in(
Scopes.SINGLETON); Scopes.SINGLETON);
bind(VFSService.class).to(VFSServiceImpl.class).in(Scopes.SINGLETON); bind(VFSService.class).to(VFSServiceImpl.class).in(Scopes.SINGLETON);
bind(ThreadService.class).to(ThreadServiceImpl.class).in(
Scopes.SINGLETON);
bind(ConfigurationService.class).to(ProxyConfigurationService.class) bind(ConfigurationService.class).to(ProxyConfigurationService.class)
.in(Scopes.SINGLETON); .in(Scopes.SINGLETON);
bind(CacheService.class).to(EhCacheService.class).in(Scopes.SINGLETON); bind(CacheService.class).to(EhCacheService.class).in(Scopes.SINGLETON);
bind(DatabaseService.class).to(JDBCDatabaseService.class).in( bind(DatabaseService.class).to(JDBCDatabaseService.class).in(
Scopes.SINGLETON); Scopes.SINGLETON);
bind(WorldIDService.class).to(CachedWorldIDService.class).in( bind(WorldIDService.class).to(CachedWorldIDService.class).in(

View File

@@ -200,7 +200,7 @@ public class EhCacheService extends AbstractService implements CacheService {
final Element element = cache.get(key); final Element element = cache.get(key);
if (element == null) if (element == null)
return null; return null;
return (V) element.getValue(); return (V) element.getObjectValue();
} }
@Override @Override

View File

@@ -0,0 +1,29 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.core.threading;
import java.util.concurrent.ScheduledFuture;
/**
* This future instance extends {@link ScheduledFuture}. An scheduled future
* cannot return values neither await for its termination because its execution
* is continuously repeated.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface ScheduledAsyncFuture extends ScheduledFuture<Object> {
}

View File

@@ -0,0 +1,71 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.core.threading;
import java.util.concurrent.Callable;
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.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface ThreadPool {
/**
* Executes an asynchronous tasks.
*
* @param <T>
* the task return type
* @param callable
* the callable instance
* @return the {@link AsyncFuture} notified once the task has completed
*/
<T> AsyncFuture<T> async(Callable<T> callable);
/**
* Executes an asynchronous tasks at an scheduled time.
*
* @param <T>
* the task return type
* @param callable
* the callable instance
* @param delay
* the initial delay to wait before the task is executed
* @param unit
* the time unit of delay
* @return the {@link AsyncFuture} notified once the task has completed
*/
<T> AsyncFuture<T> async(long delay, TimeUnit unit, Callable<T> callable);
/**
* Executes an asynchronous tasks at an scheduled time.
*
* @param callable
* the callable instance
* @param delay
* the initial delay to wait before the task is executed
* @param repeat
* the repeating interval for this task
* @param unit
* the time unit of delay
* @return the {@link AsyncFuture} notified once the task has completed
*/
ScheduledAsyncFuture async(long delay, TimeUnit unit, long repeat,
Runnable task);
}

View File

@@ -30,6 +30,8 @@ import com.l2jserver.service.Service;
public interface ThreadService extends Service { public interface ThreadService extends Service {
/** /**
* Executes an asynchronous tasks. * Executes an asynchronous tasks.
* <p>
* Tasks scheduled here will go to an default shared thread pool.
* *
* @param <T> * @param <T>
* the task return type * the task return type
@@ -43,6 +45,8 @@ public interface ThreadService extends Service {
* Executes an asynchronous tasks at an scheduled time. <b>Please note that * Executes an asynchronous tasks at an scheduled time. <b>Please note that
* resources in scheduled thread pool are limited and tasks should be * resources in scheduled thread pool are limited and tasks should be
* performed fast.</b> * performed fast.</b>
* <p>
* Tasks scheduled here will go to an default shared thread pool.
* *
* @param <T> * @param <T>
* the task return type * the task return type
@@ -55,4 +59,44 @@ public interface ThreadService extends Service {
* @return the {@link AsyncFuture} notified once the task has completed * @return the {@link AsyncFuture} notified once the task has completed
*/ */
<T> AsyncFuture<T> async(long delay, TimeUnit unit, Callable<T> callable); <T> AsyncFuture<T> async(long delay, TimeUnit unit, Callable<T> callable);
/**
* Executes an asynchronous tasks at an scheduled time. <b>Please note that
* resources in scheduled thread pool are limited and tasks should be
* performed fast.</b>
* <p>
* Tasks scheduled here will go to an default shared thread pool.
*
* @param callable
* the callable instance
* @param delay
* the initial delay to wait before the task is executed
* @param repeat
* the repeating interval for this task
* @param unit
* the time unit of delay
* @return the {@link AsyncFuture} notified once the task has completed
*/
ScheduledAsyncFuture async(long delay, TimeUnit unit, long repeat,
Runnable task);
/**
* Creates a new thread pool.
*
* @param name
* the pool name
* @param maxThreads
* the maximum amount of threads.
* @return the new thread pool
*/
ThreadPool createThreadPool(String name, int maxThreads);
/**
* Disposes an given thread pool. After disposing the thread pool will no
* longer be usable.
*
* @param pool
* the thread pool to be disposed
*/
void dispose(ThreadPool pool);
} }

View File

@@ -17,11 +17,12 @@
package com.l2jserver.service.core.threading; package com.l2jserver.service.core.threading;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@@ -44,25 +45,19 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
*/ */
private final Logger log = LoggerFactory.getLogger(this.getClass()); private final Logger log = LoggerFactory.getLogger(this.getClass());
/** private ThreadPool pool;
* The scheduler Thread pool
*/
private ScheduledExecutorService scheduler;
/**
* The asynchronous Thread pool
*/
private ExecutorService async;
@Override @Override
protected void doStart() throws ServiceStartException { protected void doStart() throws ServiceStartException {
scheduler = Executors.newScheduledThreadPool(10); pool = createThreadPool("shared", 20);
async = Executors.newCachedThreadPool(); // scheduler = Executors.newScheduledThreadPool(10);
// async = Executors.newCachedThreadPool();
} }
@Override @Override
public <T> AsyncFuture<T> async(Callable<T> callable) { public <T> AsyncFuture<T> async(Callable<T> callable) {
Preconditions.checkNotNull(callable, "callable"); Preconditions.checkNotNull(callable, "callable");
return new AsyncFutureImpl<T>(async.submit(callable)); return pool.async(callable);
} }
@Override @Override
@@ -71,25 +66,37 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
Preconditions.checkArgument(delay >= 0, "delay < 0"); Preconditions.checkArgument(delay >= 0, "delay < 0");
Preconditions.checkNotNull(unit, "unit"); Preconditions.checkNotNull(unit, "unit");
Preconditions.checkNotNull(callable, "callable"); Preconditions.checkNotNull(callable, "callable");
return new AsyncFutureImpl<T>(scheduler.schedule(callable, delay, unit)); return pool.async(delay, unit, callable);
}
@Override
public ScheduledAsyncFuture async(long delay, TimeUnit unit, long repeat,
Runnable task) {
Preconditions.checkArgument(delay >= 0, "delay < 0");
Preconditions.checkArgument(repeat >= 0, "repeat < 0");
Preconditions.checkNotNull(unit, "unit");
Preconditions.checkNotNull(task, "task");
return pool.async(delay, unit, repeat, task);
}
@Override
public ThreadPool createThreadPool(String name, int maxThreads) {
return new ThreadPoolImpl(name,
Executors.newScheduledThreadPool(maxThreads));
}
@Override
public void dispose(ThreadPool pool) {
if (pool instanceof ThreadPoolImpl)
((ThreadPoolImpl) pool).executor.shutdown();
throw new UnsupportedOperationException(
"The given ThreadPool is not supported by this service");
} }
@Override @Override
protected void doStop() throws ServiceStopException { protected void doStop() throws ServiceStopException {
scheduler.shutdown(); dispose(pool);
async.shutdown(); pool = null;
try {
scheduler.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.warn("Scheduler thread did not stop in 60 seconds", e);
}
try {
async.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.warn("Asynchronous thread did not stop in 60 seconds", e);
}
scheduler = null;
async = null;
} }
/** /**
@@ -99,7 +106,7 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
* @param <T> * @param <T>
* the return type * the return type
*/ */
public static class AsyncFutureImpl<T> implements AsyncFuture<T> { private class AsyncFutureImpl<T> implements AsyncFuture<T> {
/** /**
* The future that is delegated in this implementation * The future that is delegated in this implementation
*/ */
@@ -184,4 +191,92 @@ public class ThreadServiceImpl extends AbstractService implements ThreadService
} }
} }
} }
private class ScheduledAsyncFutureImpl implements ScheduledAsyncFuture {
private final ScheduledFuture<?> future;
public ScheduledAsyncFutureImpl(ScheduledFuture<?> future) {
this.future = future;
}
@Override
public long getDelay(TimeUnit unit) {
return future.getDelay(unit);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return future.cancel(mayInterruptIfRunning);
}
@Override
public int compareTo(Delayed o) {
return future.compareTo(o);
}
@Override
public boolean isCancelled() {
return future.isCancelled();
}
@Override
public boolean isDone() {
return future.isDone();
}
@Override
public Object get() throws InterruptedException, ExecutionException {
throw new UnsupportedOperationException();
}
@Override
public Object get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException,
TimeoutException {
throw new UnsupportedOperationException();
}
}
private class ThreadPoolImpl implements ThreadPool {
/**
* This thread pool name
*/
private final String name;
/**
* The backing executor
*/
private final ScheduledExecutorService executor;
public ThreadPoolImpl(String name, ScheduledExecutorService executor) {
this.name = name;
this.executor = executor;
}
@Override
public <T> AsyncFuture<T> async(Callable<T> callable) {
log.debug("Task {} submited to {}", callable, name);
return new AsyncFutureImpl<T>(executor.submit(callable));
}
@Override
public <T> AsyncFuture<T> async(long delay, TimeUnit unit,
Callable<T> callable) {
if (log.isDebugEnabled())
log.debug("Task {} scheduled in {} {} to {}", new Object[] {
callable, delay, unit, name });
return new AsyncFutureImpl<T>(executor.schedule(callable, delay,
unit));
}
@Override
public ScheduledAsyncFuture async(long delay, TimeUnit unit,
long repeat, Runnable task) {
if (log.isDebugEnabled())
log.debug("Task {} scheduled every {} {} to {}", new Object[] {
task, repeat, unit, name });
return new ScheduledAsyncFutureImpl(executor.scheduleAtFixedRate(
task, delay, repeat, unit));
}
}
} }

View File

@@ -24,8 +24,11 @@ import com.l2jserver.model.template.NPCTemplate;
import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC; import com.l2jserver.model.world.NPC;
import com.l2jserver.service.Service; import com.l2jserver.service.Service;
import com.l2jserver.service.core.threading.AsyncFuture;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.spawn.AlreadySpawnedServiceException; import com.l2jserver.service.game.spawn.AlreadySpawnedServiceException;
import com.l2jserver.service.game.spawn.SpawnPointNotFoundServiceException; import com.l2jserver.service.game.spawn.SpawnPointNotFoundServiceException;
import com.l2jserver.util.geometry.Point3D;
/** /**
* This service manages {@link NPC} instances * This service manages {@link NPC} instances
@@ -43,9 +46,11 @@ public interface NPCService extends Service {
* the character * the character
* @param action * @param action
* the action type * the action type
* @throws CannotSetTargetServiceException
* if was not possible to set the target
*/ */
void action(NPC npc, L2Character character, CharacterAction action) void action(NPC npc, L2Character character, CharacterAction action)
throws ActionServiceException; throws ActionServiceException, CannotSetTargetServiceException;
/** /**
* Executes an action for an NPC. Each {@link NPCTemplate} have it's own * Executes an action for an NPC. Each {@link NPCTemplate} have it's own
@@ -57,9 +62,22 @@ public interface NPCService extends Service {
* the character * the character
* @param args * @param args
* the action arguments * the action arguments
* @throws CannotSetTargetServiceException
* if was not possible to set the target
*/ */
void action(NPC npc, L2Character character, String... args) void action(NPC npc, L2Character character, String... args)
throws ActionServiceException; throws ActionServiceException, CannotSetTargetServiceException;
/**
* Moves an given <tt>npc</tt> to an <tt>point</tt>
*
* @param npc
* the NPC
* @param point
* the destination point
* @return the future informing once the NPC has been moved to that location
*/
AsyncFuture<Boolean> move(NPC npc, Point3D point);
/** /**
* Load from database and spawn all {@link NPC NPCs} instances * Load from database and spawn all {@link NPC NPCs} instances

View File

@@ -18,6 +18,8 @@ package com.l2jserver.service.game.npc;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -27,10 +29,16 @@ import com.l2jserver.game.net.Lineage2Connection;
import com.l2jserver.game.net.packet.client.CharacterActionPacket.CharacterAction; import com.l2jserver.game.net.packet.client.CharacterActionPacket.CharacterAction;
import com.l2jserver.game.net.packet.server.ActorAttackPacket; import com.l2jserver.game.net.packet.server.ActorAttackPacket;
import com.l2jserver.model.server.AttackHit; import com.l2jserver.model.server.AttackHit;
import com.l2jserver.model.server.AttackHit.AttackHitFlag;
import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC; import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.NPC.NPCState;
import com.l2jserver.model.world.npc.controller.NPCController; import com.l2jserver.model.world.npc.controller.NPCController;
import com.l2jserver.service.AbstractService; import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.core.threading.AsyncFuture;
import com.l2jserver.service.core.threading.ThreadService;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.character.CharacterService; import com.l2jserver.service.game.character.CharacterService;
import com.l2jserver.service.game.spawn.AlreadySpawnedServiceException; import com.l2jserver.service.game.spawn.AlreadySpawnedServiceException;
import com.l2jserver.service.game.spawn.SpawnPointNotFoundServiceException; import com.l2jserver.service.game.spawn.SpawnPointNotFoundServiceException;
@@ -38,12 +46,15 @@ import com.l2jserver.service.game.spawn.SpawnService;
import com.l2jserver.service.network.NetworkService; import com.l2jserver.service.network.NetworkService;
import com.l2jserver.util.exception.L2Exception; import com.l2jserver.util.exception.L2Exception;
import com.l2jserver.util.factory.CollectionFactory; import com.l2jserver.util.factory.CollectionFactory;
import com.l2jserver.util.geometry.Point3D;
/** /**
* Default {@link NPCService} implementation * Default {@link NPCService} implementation
* *
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
@Depends({ SpawnService.class, NetworkService.class, CharacterService.class,
ThreadService.class })
public class NPCServiceImpl extends AbstractService implements NPCService { public class NPCServiceImpl extends AbstractService implements NPCService {
/** /**
* The {@link SpawnService} used to spawn the {@link NPC} instances * The {@link SpawnService} used to spawn the {@link NPC} instances
@@ -56,8 +67,11 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
/** /**
* The {@link CharacterService} * The {@link CharacterService}
*/ */
@SuppressWarnings("unused")
private final CharacterService characterService; private final CharacterService characterService;
/**
* The {@link ThreadService}
*/
private final ThreadService threadService;
/** /**
* The {@link NPCDAO} * The {@link NPCDAO}
@@ -79,21 +93,25 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
@Inject @Inject
public NPCServiceImpl(SpawnService spawnService, public NPCServiceImpl(SpawnService spawnService,
NetworkService networkService, CharacterService characterService, NetworkService networkService, CharacterService characterService,
NPCDAO npcDao, Injector injector) { ThreadService threadService, NPCDAO npcDao, Injector injector) {
this.spawnService = spawnService; this.spawnService = spawnService;
this.networkService = networkService; this.networkService = networkService;
this.characterService = characterService; this.characterService = characterService;
this.threadService = threadService;
this.npcDao = npcDao; this.npcDao = npcDao;
this.injector = injector; this.injector = injector;
} }
@Override @Override
public void action(NPC npc, L2Character character, CharacterAction action) public void action(NPC npc, L2Character character, CharacterAction action)
throws ActionServiceException { throws ActionServiceException, CannotSetTargetServiceException {
Preconditions.checkNotNull(npc, "npc"); Preconditions.checkNotNull(npc, "npc");
Preconditions.checkNotNull(character, "character"); Preconditions.checkNotNull(character, "character");
Preconditions.checkNotNull(action, "action"); Preconditions.checkNotNull(action, "action");
if (npc.getTemplate().isTargetable())
characterService.target(character, npc);
final Lineage2Connection conn = networkService.discover(character final Lineage2Connection conn = networkService.discover(character
.getID()); .getID());
try { try {
@@ -106,12 +124,15 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
@Override @Override
public void action(NPC npc, L2Character character, String... args) public void action(NPC npc, L2Character character, String... args)
throws ActionServiceException { throws ActionServiceException, CannotSetTargetServiceException {
Preconditions.checkNotNull(npc, "npc"); Preconditions.checkNotNull(npc, "npc");
Preconditions.checkNotNull(character, "character"); Preconditions.checkNotNull(character, "character");
if (args == null) if (args == null)
args = new String[0]; args = new String[0];
if (npc.getTemplate().isTargetable())
characterService.target(character, npc);
final Lineage2Connection conn = networkService.discover(character final Lineage2Connection conn = networkService.discover(character
.getID()); .getID());
try { try {
@@ -123,7 +144,30 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
} }
@Override @Override
public Collection<NPC> spawnAll() throws SpawnPointNotFoundServiceException, public AsyncFuture<Boolean> move(final NPC npc, final Point3D point) {
if (!npc.isIdle())
// TODO throw an exception
return null;
npc.setState(NPCState.MOVING);
// calculate walking time
final Point3D start = npc.getPoint();
final double distance = start.getDistance(point);
final double seconds = distance / npc.getTemplate().getRunSpeed();
// TODO this is an dirty implementation!
return threadService.async((int) (seconds * 1000),
TimeUnit.MILLISECONDS, new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
npc.setState(null);
npc.setPoint(point);
return false;
}
});
}
@Override
public Collection<NPC> spawnAll()
throws SpawnPointNotFoundServiceException,
AlreadySpawnedServiceException { AlreadySpawnedServiceException {
final Collection<NPC> npcs = npcDao.loadAll(); final Collection<NPC> npcs = npcDao.loadAll();
for (final NPC npc : npcs) { for (final NPC npc : npcs) {
@@ -140,7 +184,8 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
Preconditions.checkNotNull(attacker, "attacker"); Preconditions.checkNotNull(attacker, "attacker");
conn.write(new ActorAttackPacket(conn.getCharacter(), new AttackHit( conn.write(new ActorAttackPacket(conn.getCharacter(), new AttackHit(
conn.getCharacter(), npc))); conn.getCharacter(), npc, AttackHitFlag.MISS,
AttackHitFlag.SOULSHOT)));
} }
private NPCController getController(NPC npc) { private NPCController getController(NPC npc) {

View File

@@ -19,7 +19,6 @@ package com.l2jserver.service.game.world.event;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -30,8 +29,11 @@ import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.AbstractFuture; import com.google.common.util.concurrent.AbstractFuture;
import com.google.inject.Inject;
import com.l2jserver.model.id.ObjectID; import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.world.WorldObject; import com.l2jserver.model.world.WorldObject;
import com.l2jserver.service.core.threading.ThreadPool;
import com.l2jserver.service.core.threading.ThreadService;
import com.l2jserver.util.factory.CollectionFactory; import com.l2jserver.util.factory.CollectionFactory;
/** /**
@@ -46,10 +48,12 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory
.getLogger(WorldEventDispatcherImpl.class); .getLogger(WorldEventDispatcherImpl.class);
private final ThreadService threadService;
/** /**
* The execution thread * The execution thread
*/ */
private Timer timer; private ThreadPool threadPool;
/** /**
* The list of all global listeners * The list of all global listeners
@@ -66,10 +70,14 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
private Queue<EventContainer> events = CollectionFactory private Queue<EventContainer> events = CollectionFactory
.newConcurrentQueue(); .newConcurrentQueue();
@Inject
public WorldEventDispatcherImpl(ThreadService threadService) {
this.threadService = threadService;
}
public void start() { public void start() {
// TODO event dispatching should be done using ThreadService threadPool = threadService.createThreadPool("event-dispatcher", 1);
timer = new Timer(); threadPool.async(0, TimeUnit.MILLISECONDS, 20, new TimerTask() {
final TimerTask task = new TimerTask() {
@Override @Override
public void run() { public void run() {
EventContainer event; EventContainer event;
@@ -91,8 +99,7 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
} }
} }
} }
}; });
timer.scheduleAtFixedRate(task, 0, 50);
} }
@Override @Override
@@ -223,8 +230,8 @@ public class WorldEventDispatcherImpl implements WorldEventDispatcher {
} }
public void stop() { public void stop() {
timer.cancel(); threadService.dispose(threadPool);
timer = null; threadPool = null;
} }
/** /**