1
0
mirror of https://github.com/Rogiel/l2jserver2 synced 2025-12-05 23:22:47 +00:00

Decouples NPCService and NPCController from Lineage2Client class

This commit is contained in:
2011-12-18 22:13:03 -02:00
parent b9e460b70c
commit b169723299
10110 changed files with 10600 additions and 10327 deletions

View File

@@ -41,6 +41,7 @@ import com.l2jserver.game.net.packet.client.CM_CHAR_OPEN_MAP;
import com.l2jserver.game.net.packet.client.CM_CHAR_POSITION;
import com.l2jserver.game.net.packet.client.CM_CHAR_REQ_INVENTORY;
import com.l2jserver.game.net.packet.client.CM_CHAR_SELECT;
import com.l2jserver.game.net.packet.client.CM_CHAR_TARGET_UNSELECT;
import com.l2jserver.game.net.packet.client.CM_ENTER_WORLD;
import com.l2jserver.game.net.packet.client.CM_EXT_REQ_ALL_FORTRESS_INFO;
import com.l2jserver.game.net.packet.client.CM_EXT_REQ_KEY_MAPPING;
@@ -193,6 +194,8 @@ public class Lineage2PacketReader extends OneToOneDecoder {
return CM_ITEM_DROP.class;
case CM_ITEM_DESTROY.OPCODE:
return CM_ITEM_DESTROY.class;
case CM_CHAR_TARGET_UNSELECT.OPCODE:
return CM_CHAR_TARGET_UNSELECT.class;
default:
logger.warn("Unknown packet for 0x{}", Integer.toHexString(opcode));
break;

View File

@@ -29,6 +29,7 @@ import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.id.object.NPCID;
import com.l2jserver.model.id.object.provider.ObjectIDResolver;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.NPCController.NPCControllerException;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.npc.ActionServiceException;
import com.l2jserver.service.game.npc.NPCService;
@@ -101,6 +102,10 @@ public class CM_BYPASS extends AbstractClientPacket {
conn.sendActionFailed();
} catch (CannotSetTargetServiceException e) {
conn.sendActionFailed();
} catch (NPCControllerException e) {
if (e.getSystemMessage() != null)
conn.sendSystemMessage(e.getSystemMessage());
conn.sendActionFailed();
}
} else {
log.warn("Client requested an bypass not supported by server");

View File

@@ -28,6 +28,7 @@ import com.l2jserver.model.id.object.NPCID;
import com.l2jserver.model.id.object.provider.ObjectIDResolver;
import com.l2jserver.model.world.Item;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.NPCController.NPCControllerException;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.item.ItemNotOnGroundServiceException;
import com.l2jserver.service.game.item.ItemService;
@@ -118,6 +119,10 @@ public class CM_CHAR_ACTION extends AbstractClientPacket {
final NPC npc = ((NPCID) id).getObject();
try {
npcService.action(npc, conn.getCharacter(), action);
} catch(NPCControllerException e) {
if(e.getSystemMessage() != null)
conn.sendSystemMessage(e.getSystemMessage());
conn.sendActionFailed();
} catch (ActionServiceException | CannotSetTargetServiceException e) {
conn.sendActionFailed();
}

View File

@@ -0,0 +1,72 @@
/*
* 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.game.net.packet.client;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.inject.Inject;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.SystemMessage;
import com.l2jserver.game.net.packet.AbstractClientPacket;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.character.CharacterService;
/**
* This packet cancels the target selection
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class CM_CHAR_TARGET_UNSELECT extends AbstractClientPacket {
/**
* The packet OPCODE
*/
public static final int OPCODE = 0x48;
/**
* The {@link CharacterService}
*/
private final CharacterService charService;
/**
* Now known for sure
*/
@SuppressWarnings("unused")
private boolean unselect;
/**
* @param charService
* the character service
*/
@Inject
public CM_CHAR_TARGET_UNSELECT(CharacterService charService) {
this.charService = charService;
}
@Override
public void read(Lineage2Client conn, ChannelBuffer buffer) {
this.unselect = (buffer.readByte() == 1 ? true : false);
}
@Override
public void process(final Lineage2Client conn) {
try {
charService.target(conn.getCharacter(), null);
} catch (CannotSetTargetServiceException e) {
conn.sendSystemMessage(SystemMessage.FAILED_DISABLE_TARGET);
}
}
}

View File

@@ -48,11 +48,7 @@ public class SM_NPC_INFO extends AbstractServerPacket {
buffer.writeInt(npc.getID().getID());
buffer.writeInt(template.getID().getID() + 1000000); // npctype id
// if (npc instanceof NPC) {
buffer.writeInt((template.isAttackable() ? 0x01 : 0x00));
// } else {
// buffer.writeInt(0x01);
// }
buffer.writeInt((template.isAttackable() ? 0x01 : 0x00)); // attackable
buffer.writeInt(npc.getPoint().getX());
buffer.writeInt(npc.getPoint().getY());
buffer.writeInt(npc.getPoint().getZ());

View File

@@ -38,7 +38,7 @@ import com.l2jserver.model.template.actor.ActorSex;
import com.l2jserver.model.template.actor.ActorTemplate;
import com.l2jserver.model.template.npc.NPCTemplate.TalkMetadata.Chat;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.controller.NPCController;
import com.l2jserver.model.world.npc.NPCController;
import com.l2jserver.util.factory.CollectionFactory;
import com.l2jserver.util.jaxb.ItemTemplateIDAdapter;
import com.l2jserver.util.jaxb.NPCTemplateIDAdapter;

View File

@@ -14,18 +14,19 @@
* 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.npc.controller;
package com.l2jserver.model.world.npc;
import java.util.Arrays;
import org.htmlparser.Parser;
import org.htmlparser.util.ParserException;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.server.SM_HTML;
import com.google.inject.Inject;
import com.l2jserver.model.template.npc.NPCTemplate;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.service.game.character.CharacterService;
import com.l2jserver.service.game.npc.NPCService;
import com.l2jserver.util.exception.L2Exception;
import com.l2jserver.util.html.markup.HtmlTemplate;
import com.l2jserver.util.html.markup.MarkupTag;
@@ -37,19 +38,53 @@ import com.l2jserver.util.html.markup.MarkupTag;
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class BaseNPCController implements NPCController {
public abstract class BaseNPCController implements NPCController {
/**
* The {@link CharacterService}
*/
@Inject
protected CharacterService charService;
/**
* The {@link NPCService}
*/
@Inject
protected NPCService npcService;
@Override
public void action(NPC npc, Lineage2Client conn, L2Character character,
final String... args) throws L2Exception {
public void action(NPC npc, L2Character character, final String... args)
throws L2Exception {
if (npc.getID().equals(character.getTargetID())) {
interact(npc, character, args);
} else {
charService.target(character, npc);
}
}
/**
* Performs the controller-specific NPC<->L2Character interaction.
*
* @param npc
* the {@link NPC} instance
* @param character
* the interacting character
* @param args
* the action arguments
* @throws NPCControllerException
* if the exception requires an system message response
* @throws L2Exception
* any {@link L2Exception}
*/
public void interact(NPC npc, L2Character character, final String... args)
throws L2Exception {
if (args.length == 2) {
if (args[0].equals("Chat")) {
if (talk(npc, conn, character,
if (talk(npc, character,
Arrays.copyOfRange(args, 1, args.length)))
return;
}
} else if (args.length == 0 || args.length == 1) {
// default action is talk
if (talk(npc, conn, character, new String[0]))
if (talk(npc, character, new String[0]))
return;
}
// action not handled message
@@ -62,8 +97,7 @@ public class BaseNPCController implements NPCController {
body.text("Arguments: " + Arrays.toString(args));
}
}.register("name", character.getName());
conn.write(new SM_HTML(npc, template));
conn.sendActionFailed();
npcService.talk(npc, character, template);
}
/**
@@ -71,8 +105,6 @@ public class BaseNPCController implements NPCController {
*
* @param npc
* the {@link NPC} instance
* @param conn
* the connection to {@link L2Character}
* @param character
* the interacting character
* @param args
@@ -81,8 +113,8 @@ public class BaseNPCController implements NPCController {
* @throws L2Exception
* if the talk action could not be performed
*/
protected boolean talk(NPC npc, Lineage2Client conn, L2Character character,
String... args) throws L2Exception {
protected boolean talk(NPC npc, L2Character character, String... args)
throws L2Exception {
String id = null;
if (args.length >= 1) {
id = args[0];
@@ -90,8 +122,7 @@ public class BaseNPCController implements NPCController {
final String html = getHTML(npc, id);
if (html == null)
return false;
conn.write(new SM_HTML(npc, html));
conn.sendActionFailed();
npcService.talk(npc, character, html);
return true;
}

View File

@@ -14,9 +14,9 @@
* 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.npc.controller;
package com.l2jserver.model.world.npc;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.SystemMessage;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.util.exception.L2Exception;
@@ -33,15 +33,54 @@ public interface NPCController {
*
* @param npc
* the {@link NPC} instance
* @param conn
* the connection to {@link L2Character}
* @param character
* the interacting character
* @param args
* the action arguments
* @throws NPCControllerException
* if the exception requires an system message response
* @throws L2Exception
* any {@link L2Exception}
*/
void action(NPC npc, Lineage2Client conn, L2Character character,
String... args) throws L2Exception;
void action(NPC npc, L2Character character, String... args)
throws NPCControllerException, L2Exception;
/**
* Exception thrown if the {@link NPCController} could not perform an
* certain operation
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public static class NPCControllerException extends L2Exception {
private static final long serialVersionUID = 1L;
/**
* The {@link SystemMessage}
*/
private final SystemMessage systemMessage;
/**
* Creates a new instance
*
* @param systemMessage
* the {@link SystemMessage} to be sent to the client
*/
public NPCControllerException(SystemMessage systemMessage) {
this.systemMessage = systemMessage;
}
/**
* Creates a new instance with a <code>null</code> system message.
*/
public NPCControllerException() {
this(null);
}
/**
* @return the system message
*/
public SystemMessage getSystemMessage() {
return systemMessage;
}
}
}

View File

@@ -1,59 +0,0 @@
/*
* 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.npc.controller;
import com.google.inject.Inject;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.server.SM_ACTOR_STATUS_UPDATE;
import com.l2jserver.game.net.packet.server.SM_ACTOR_STATUS_UPDATE.Stat;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.service.game.character.CharacterService;
import com.l2jserver.service.game.npc.NPCService;
import com.l2jserver.util.exception.L2Exception;
/**
* This controller is used to control teleporters (e.g. gatekeepers)
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class MonsterController extends BaseNPCController {
/**
* The {@link CharacterService}
*/
@Inject
protected CharacterService charService;
/**
* The {@link NPCService}
*/
@Inject
protected NPCService npcService;
@Override
public void action(NPC mob, Lineage2Client conn, L2Character character,
String... args) throws L2Exception {
// send hp update
if (mob.getID().equals(character.getTargetID())) {
charService.attack(character, mob);
} else {
charService.target(character, mob);
conn.write(new SM_ACTOR_STATUS_UPDATE(mob).add(Stat.MAX_HP,
(int) mob.getTemplate().getMaximumHP()).add(Stat.HP,
(int) mob.getHP()));
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.npc.controller.impl;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.BaseNPCController;
import com.l2jserver.service.game.character.ActorIsNotAttackableServiceException;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.service.game.npc.NotAttackableNPCServiceException;
/**
* This controller is used to control monsters
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class MonsterController extends BaseNPCController {
@Override
public void interact(NPC npc, L2Character character, String... args)
throws CannotSetTargetServiceException,
ActorIsNotAttackableServiceException,
NotAttackableNPCServiceException {
charService.attack(character, npc);
}
}

View File

@@ -14,14 +14,13 @@
* 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.npc.controller;
package com.l2jserver.model.world.npc.controller.impl;
import java.util.Arrays;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.server.SM_HTML;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.BaseNPCController;
import com.l2jserver.util.exception.L2Exception;
import com.l2jserver.util.html.markup.HtmlTemplate;
import com.l2jserver.util.html.markup.MarkupTag;
@@ -34,7 +33,7 @@ import com.l2jserver.util.html.markup.MarkupTag;
*/
public class NotImplementedNPCController extends BaseNPCController {
@Override
public void action(NPC npc, Lineage2Client conn, L2Character character,
public void interact(NPC npc, L2Character character,
final String... args) throws L2Exception {
// action not handled
final HtmlTemplate template = new HtmlTemplate() {
@@ -46,7 +45,6 @@ public class NotImplementedNPCController extends BaseNPCController {
body.text("Arguments: " + Arrays.toString(args));
}
}.register("name", character.getName());
conn.write(new SM_HTML(npc, template));
conn.sendActionFailed();
npcService.talk(npc, character, template);
}
}

View File

@@ -0,0 +1,27 @@
/*
* 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.npc.controller.impl;
import com.l2jserver.model.world.npc.BaseNPCController;
/**
* This controller is used to control teleporters (e.g. gatekeepers)
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class SimpleNPCController extends BaseNPCController {
}

View File

@@ -14,14 +14,14 @@
* 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.npc.controller;
package com.l2jserver.model.world.npc.controller.impl;
import com.google.inject.Inject;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.model.id.template.provider.TeleportationTemplateIDProvider;
import com.l2jserver.model.template.npc.TeleportationTemplate;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.BaseNPCController;
import com.l2jserver.service.game.spawn.SpawnService;
import com.l2jserver.util.exception.L2Exception;
@@ -43,23 +43,20 @@ public class TeleporterController extends BaseNPCController {
protected TeleportationTemplateIDProvider teleportationIdProvider;
@Override
public void action(NPC npc, Lineage2Client conn, L2Character character,
String... args) throws L2Exception {
public void interact(NPC npc, L2Character character, String... args)
throws L2Exception {
if (args.length >= 2) {
if (args[0].equals("goto")) {
final TeleportationTemplate tele = teleportationIdProvider
.resolveID(Integer.parseInt(args[1])).getTemplate();
if (tele == null) {
// TODO notify user that his destination is invalid
conn.sendActionFailed();
return;
} else {
// TODO remove items from character inventory
spawnService.teleport(character, tele.getCoordinate());
return;
throw new NPCControllerException();
}
// TODO remove items from character inventory
spawnService.teleport(character, tele.getCoordinate());
return;
}
}
super.action(npc, conn, character, args);
super.interact(npc, character, args);
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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.npc.event;
import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.WorldObject;
/**
* Event dispatched once a {@link NPC} has died.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class NPCTalkEvent implements NPCEvent {
private final NPC npc;
private final L2Character character;
private final String html;
/**
* @param npc
* the {@link NPC} that is talking to the player
* @param character
* the {@link L2Character} talking to the {@link NPC}
* @param html
* the message html content
*/
public NPCTalkEvent(NPC npc, L2Character character, String html) {
this.npc = npc;
this.character = character;
this.html = html;
}
/**
* @return the character
*/
public L2Character getCharacter() {
return character;
}
/**
* @return the html
*/
public String getHtml() {
return html;
}
@Override
public WorldObject getObject() {
return npc;
}
@Override
public NPC getNPC() {
return npc;
}
@Override
public ObjectID<?>[] getDispatchableObjects() {
return new ObjectID[] { npc.getID(), character.getID() };
}
}

View File

@@ -120,14 +120,11 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO<NPC, NPCID> implements
.getInt(NPC_TEMPLATE_ID));
NPCTemplate template = templateId.getTemplate();
if (template == null) {
// set default npc instance, for now!
// RoxxyGatekeeperTemplate - 30006
log.warn("No template found for {}", templateId);
return null;
}
final NPC npc = template.create();
npc.setID(id);
if (rs.getString(HP) != null)
@@ -301,7 +298,7 @@ public abstract class JDBCNPCDAO extends AbstractJDBCDAO<NPC, NPCID> implements
}
});
}
@Override
protected NPC[] wrap(Model<?>... objects) {
final NPC[] array = new NPC[objects.length];

View File

@@ -270,7 +270,6 @@ public class CharacterServiceImpl extends AbstractService implements
public void target(L2Character character, Actor target)
throws CannotSetTargetServiceException {
Preconditions.checkNotNull(character, "character");
Preconditions.checkNotNull(target, "target");
log.debug("Setting {} target to {}", character, target);

View File

@@ -16,15 +16,18 @@
*/
package com.l2jserver.service.game.npc;
import com.l2jserver.game.net.SystemMessage;
import com.l2jserver.game.net.packet.client.CM_CHAR_ACTION.CharacterAction;
import com.l2jserver.model.template.npc.NPCTemplate;
import com.l2jserver.model.world.Actor;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.NPCController.NPCControllerException;
import com.l2jserver.service.Service;
import com.l2jserver.service.core.threading.AsyncFuture;
import com.l2jserver.service.game.character.CannotSetTargetServiceException;
import com.l2jserver.util.geometry.Point3D;
import com.l2jserver.util.html.markup.HtmlTemplate;
/**
* This service controls {@link NPC} objects. It can execute {@link NPC}
@@ -47,9 +50,12 @@ public interface NPCService extends Service {
* if the action thrown an exception
* @throws CannotSetTargetServiceException
* if was not possible to set the target
* @throws NPCControllerException
* if the exception requires an {@link SystemMessage}
*/
void action(NPC npc, L2Character character, CharacterAction action)
throws ActionServiceException, CannotSetTargetServiceException;
throws ActionServiceException, CannotSetTargetServiceException,
NPCControllerException;
/**
* Executes an action for an NPC. Each {@link NPCTemplate} have it's own
@@ -65,9 +71,38 @@ public interface NPCService extends Service {
* if the action thrown an exeption
* @throws CannotSetTargetServiceException
* if was not possible to set the target
* @throws NPCControllerException
* if the exception requires an {@link SystemMessage}
*/
void action(NPC npc, L2Character character, String... args)
throws ActionServiceException, CannotSetTargetServiceException;
throws ActionServiceException, CannotSetTargetServiceException,
NPCControllerException;
/**
* Sends an HTML message with the given <code>npc</code>
*
* @param npc
* the {@link NPC} that is sending the message
* @param character
* the {@link L2Character character} that is talking to the
* {@link NPC}
* @param template
* the {@link HtmlTemplate}
*/
void talk(NPC npc, L2Character character, HtmlTemplate template);
/**
* Sends an HTML message with the given <code>npc</code>
*
* @param npc
* the {@link NPC} that is sending the message
* @param character
* the {@link L2Character character} that is talking to the
* {@link NPC}
* @param html
* the html content
*/
void talk(NPC npc, L2Character character, String html);
/**
* Kills the given <tt>npc</tt>. If "nobody" killed the NPC (i.e. died by

View File

@@ -28,7 +28,6 @@ import com.google.common.base.Preconditions;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.client.CM_CHAR_ACTION.CharacterAction;
import com.l2jserver.model.dao.NPCDAO;
import com.l2jserver.model.template.npc.NPCTemplate;
@@ -36,8 +35,10 @@ import com.l2jserver.model.world.Actor;
import com.l2jserver.model.world.Actor.ActorState;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
import com.l2jserver.model.world.npc.controller.NPCController;
import com.l2jserver.model.world.npc.NPCController;
import com.l2jserver.model.world.npc.NPCController.NPCControllerException;
import com.l2jserver.model.world.npc.event.NPCDieEvent;
import com.l2jserver.model.world.npc.event.NPCTalkEvent;
import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.ServiceStartException;
@@ -53,18 +54,18 @@ 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.util.exception.L2Exception;
import com.l2jserver.util.factory.CollectionFactory;
import com.l2jserver.util.geometry.Point3D;
import com.l2jserver.util.html.markup.HtmlTemplate;
/**
* Default {@link NPCService} implementation
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
@Depends({ SpawnService.class, NetworkService.class, CharacterService.class,
ThreadService.class, AttackService.class, DatabaseService.class })
@Depends({ SpawnService.class, CharacterService.class, ThreadService.class,
AttackService.class, DatabaseService.class })
public class NPCServiceImpl extends AbstractService implements NPCService {
/**
* The logger
@@ -75,10 +76,6 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
* The {@link SpawnService} used to spawn the {@link NPC} instances
*/
private final SpawnService spawnService;
/**
* The {@link NetworkService} used to discover {@link Lineage2Client}
*/
private final NetworkService networkService;
/**
* The {@link CharacterService}
*/
@@ -121,8 +118,6 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
/**
* @param spawnService
* the spawn service
* @param networkService
* the network service
* @param characterService
* the character service
* @param threadService
@@ -138,12 +133,10 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
*/
@Inject
public NPCServiceImpl(SpawnService spawnService,
NetworkService networkService, CharacterService characterService,
ThreadService threadService, AttackService attackService,
WorldEventDispatcher eventDispatcher, NPCDAO npcDao,
Injector injector) {
CharacterService characterService, ThreadService threadService,
AttackService attackService, WorldEventDispatcher eventDispatcher,
NPCDAO npcDao, Injector injector) {
this.spawnService = spawnService;
this.networkService = networkService;
this.characterService = characterService;
this.threadService = threadService;
this.attackService = attackService;
@@ -168,7 +161,8 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
@Override
public void action(NPC npc, L2Character character, CharacterAction action)
throws ActionServiceException, CannotSetTargetServiceException {
throws ActionServiceException, CannotSetTargetServiceException,
NPCControllerException {
Preconditions.checkNotNull(npc, "npc");
Preconditions.checkNotNull(character, "character");
Preconditions.checkNotNull(action, "action");
@@ -176,10 +170,11 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
log.debug("{} interacting with {} (action={})", new Object[] {
character, npc, action });
final Lineage2Client conn = networkService.discover(character.getID());
try {
final NPCController controller = getController(npc);
controller.action(npc, conn, character, new String[0]);
controller.action(npc, character, new String[0]);
} catch (NPCControllerException e) {
throw e;
} catch (L2Exception e) {
throw new ActionServiceException(e);
}
@@ -187,24 +182,39 @@ public class NPCServiceImpl extends AbstractService implements NPCService {
@Override
public void action(NPC npc, L2Character character, String... args)
throws ActionServiceException, CannotSetTargetServiceException {
throws ActionServiceException, CannotSetTargetServiceException, NPCControllerException {
Preconditions.checkNotNull(npc, "npc");
Preconditions.checkNotNull(character, "character");
if (args == null)
args = new String[0];
log.debug("{} interacting with {} (action={})", new Object[] {
log.debug("{} interacting with {} (args={})", new Object[] {
character, npc, Arrays.toString(args) });
final Lineage2Client conn = networkService.discover(character.getID());
try {
final NPCController controller = getController(npc);
controller.action(npc, conn, character, args);
controller.action(npc, character, args);
} catch (NPCControllerException e) {
throw e;
} catch (L2Exception e) {
throw new ActionServiceException(e);
}
}
@Override
public void talk(NPC npc, L2Character character, HtmlTemplate template) {
Preconditions.checkNotNull(template, "template");
talk(npc, character, template.toHtmlString());
}
@Override
public void talk(NPC npc, L2Character character, String html) {
Preconditions.checkNotNull(npc, "npc");
Preconditions.checkNotNull(character, "character");
Preconditions.checkNotNull(html, "html");
eventDispatcher.dispatch(new NPCTalkEvent(npc, character, html));
}
@Override
public void die(NPC npc, Actor killer) {
Preconditions.checkNotNull(npc, "npc");

View File

@@ -23,11 +23,6 @@ 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.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_TELEPORT;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.world.Actor;
import com.l2jserver.model.world.Actor.ActorState;
import com.l2jserver.model.world.L2Character;
@@ -70,10 +65,6 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService {
* The {@link WorldService} event dispatcher
*/
private final WorldEventDispatcher eventDispatcher;
/**
* The {@link NetworkService}
*/
private final NetworkService networkService;
/**
* The {@link ThreadService}
*/
@@ -84,18 +75,14 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService {
* the world service
* @param eventDispatcher
* the world service event dispatcher
* @param networkService
* the network service
* @param threadService
* the thread service
*/
@Inject
public SpawnServiceImpl(WorldService worldService,
WorldEventDispatcher eventDispatcher,
NetworkService networkService, ThreadService threadService) {
WorldEventDispatcher eventDispatcher, ThreadService threadService) {
this.worldService = worldService;
this.eventDispatcher = eventDispatcher;
this.networkService = networkService;
this.threadService = threadService;
}
@@ -229,13 +216,6 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService {
if (((L2Character) actor).isTeleporting())
throw new CharacterAlreadyTeleportingServiceException();
final Lineage2Client conn = networkService
.discover((CharacterID) actor.getID());
if (conn == null)
// TODO throw an exception here
return;
conn.write(new SM_CHAR_TELEPORT(conn.getCharacter(), coordinate
.toPoint()));
((L2Character) actor).setState(ActorState.TELEPORTING);
((L2Character) actor).setTargetLocation(coordinate.toPoint());
} else {
@@ -251,8 +231,6 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService {
public void finishTeleport(L2Character character)
throws CharacterNotTeleportingServiceException {
Preconditions.checkNotNull(character, "character");
final CharacterID id = character.getID();
final Lineage2Client conn = networkService.discover(id);
if (!character.isTeleporting())
throw new CharacterNotTeleportingServiceException();
@@ -266,8 +244,5 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService {
.getTargetLocation()));
character.setTargetLocation(null);
conn.write(new SM_CHAR_INFO(character));
conn.write(new SM_CHAR_INFO_EXTRA(character));
}
}

View File

@@ -26,11 +26,15 @@ import com.l2jserver.game.net.SystemMessage;
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_ACTOR_STATUS_UPDATE;
import com.l2jserver.game.net.packet.server.SM_ACTOR_STATUS_UPDATE.Stat;
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_CHAR_TELEPORT;
import com.l2jserver.game.net.packet.server.SM_HTML;
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_MOVE_TYPE;
@@ -39,6 +43,7 @@ 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.Actor;
import com.l2jserver.model.world.Item;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.NPC;
@@ -60,6 +65,7 @@ import com.l2jserver.model.world.character.event.CharacterWalkingEvent;
import com.l2jserver.model.world.item.ItemDropEvent;
import com.l2jserver.model.world.item.ItemPickEvent;
import com.l2jserver.model.world.npc.event.NPCSpawnEvent;
import com.l2jserver.model.world.npc.event.NPCTalkEvent;
import com.l2jserver.model.world.player.event.PlayerTeleportedEvent;
import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
@@ -133,10 +139,7 @@ public class BroadcastServiceImpl extends AbstractService implements
Preconditions.checkNotNull(conn, "conn");
final CharacterID id = character.getID();
log.debug("Starting character broadcast");
// broadcast everything nearby
// broadcast(conn);
log.debug("Registering character broadcast listeners");
// event broadcast listener
// this listener will be filtered so that only interesting events are
@@ -191,71 +194,7 @@ public class BroadcastServiceImpl extends AbstractService implements
// process update known list
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);
clientEnterWorld(conn, (CharacterEnterWorldEvent) e);
} else if (e instanceof CharacterStartMovingEvent) {
conn.write(new SM_ACTOR_MOVE(
((CharacterStartMovingEvent) e).getCharacter(),
@@ -263,10 +202,22 @@ public class BroadcastServiceImpl extends AbstractService implements
.getCoordinate()));
} else if (e instanceof CharacterTargetSelectedEvent) {
final CharacterTargetSelectedEvent evt = (CharacterTargetSelectedEvent) e;
conn.write(new SM_TARGET(evt.getTarget(), evt
.getCharacter().getLevel()
- evt.getTarget().getLevel()));
final Actor target = evt.getTarget();
final L2Character character = evt.getCharacter();
conn.write(new SM_TARGET(target, character.getLevel()
- target.getLevel()));
if (target instanceof NPC) {
final NPC mob = (NPC) target;
conn.write(new SM_ACTOR_STATUS_UPDATE(mob).add(
Stat.MAX_HP,
(int) mob.getTemplate().getMaximumHP()).add(
Stat.HP, (int) mob.getHP()));
}
} else if (e instanceof PlayerTeleportedEvent) {
final L2Character character = (L2Character) ((PlayerTeleportedEvent) e)
.getPlayer();
conn.write(new SM_CHAR_INFO(character));
conn.write(new SM_CHAR_INFO_EXTRA(character));
broadcastAll(conn, character);
} else if (e instanceof ActorAttackHitEvent) {
conn.write(new SM_ATTACK(((ActorAttackHitEvent) e).getHit()));
@@ -276,6 +227,14 @@ public class BroadcastServiceImpl extends AbstractService implements
} else if (e instanceof CharacterWalkingEvent
|| e instanceof CharacterRunningEvent) {
conn.write(new SM_MOVE_TYPE((L2Character) e.getObject()));
} else if (e instanceof ActorTeleportingEvent) {
final ActorTeleportingEvent evt = (ActorTeleportingEvent) e;
conn.write(new SM_CHAR_TELEPORT((L2Character) evt
.getActor(), evt.getPoint()));
} else if (e instanceof NPCTalkEvent) {
conn.write(new SM_HTML(((NPCTalkEvent) e).getNPC(),
((NPCTalkEvent) e).getHtml()));
conn.sendActionFailed();
}
// keep listener alive
return true;
@@ -339,4 +298,73 @@ public class BroadcastServiceImpl extends AbstractService implements
conn.write(new SM_ITEM_GROUND((Item) o));
}
}
/**
* Sends required packets for a client to enter the game virtual world
*
* @param conn
* the Lineage 2 connection
* @param e
* the event
*/
private void clientEnterWorld(final Lineage2Client conn,
CharacterEnterWorldEvent e) {
final L2Character character = e.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(e.getCharacter()));
conn.write(new SM_CHAR_INFO_EXTRA(e.getCharacter()));
conn.write(new SM_CHAR_INVENTORY(e.getCharacter().getInventory()));
broadcastAll(conn, character);
}
}