null.
*/
public Item[] remove(ItemID itemID) {
- final ArrayListcount is bigger than {@link Item#getCount()}.
+ */
+ Item split(Item item, long count) throws NotEnoughItemsServiceException;
+
+ /**
+ * Stacks several items into a single one. Items must be provided by the
+ * same template!
+ *
+ * @param items
+ * the items to be stacked
+ * @return the stacked item (it may be a totally new item or it might reuse
+ * another one)
+ * @throws NonStackableItemsServiceException
+ * if the item templates says they are not stackable
+ */
+ Item stack(Item... items) throws NonStackableItemsServiceException;
+
/**
* Picks up an dropped item and places it into another players inventory
*
@@ -68,6 +95,35 @@ public interface ItemService extends Service {
Item pickUp(Item item, L2Character character)
throws ItemNotOnGroundServiceException, NotSpawnedServiceException;
+ /**
+ * Drops an item on the ground. If actor is not
+ * null he is flagged as the dropper actor.
+ *
+ * @param item
+ * the item
+ * @param count
+ * the number of items to be dropped. Will cause an split.
+ * @param point
+ * the drop point. Can be null if
+ * {@link Item#getPoint()} is set.
+ * @param actor
+ * the dropping actor. Can be null.
+ * @return item or another instance if the item was splitted.
+ * @throws ItemAlreadyOnGroundServiceException
+ * if the item is already dropped
+ * @throws AlreadySpawnedServiceException
+ * if the item is already spawned in the {@link WorldService}
+ * @throws SpawnPointNotFoundServiceException
+ * if point was null and
+ * {@link Item#getPoint()} was not set.
+ * @throws NotEnoughItemsServiceException
+ * if count is bigger than {@link Item#getCount()}.
+ */
+ Item drop(Item item, long count, Point3D point, Actor actor)
+ throws ItemAlreadyOnGroundServiceException,
+ AlreadySpawnedServiceException, SpawnPointNotFoundServiceException,
+ NotEnoughItemsServiceException;
+
/**
* Drops an item on the ground. If actor is not
* null he is flagged as the dropper actor.
@@ -86,8 +142,11 @@ public interface ItemService extends Service {
* @throws SpawnPointNotFoundServiceException
* if point was null and
* {@link Item#getPoint()} was not set.
+ * @throws NotEnoughItemsServiceException
+ * if count is bigger than {@link Item#getCount()}.
*/
void drop(Item item, Point3D point, Actor actor)
throws ItemAlreadyOnGroundServiceException,
- AlreadySpawnedServiceException, SpawnPointNotFoundServiceException;
+ AlreadySpawnedServiceException, SpawnPointNotFoundServiceException,
+ NotEnoughItemsServiceException;
}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/item/ItemServiceImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/item/ItemServiceImpl.java
index b0de05953..e067b73ab 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/item/ItemServiceImpl.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/item/ItemServiceImpl.java
@@ -16,15 +16,22 @@
*/
package com.l2jserver.service.game.item;
+import java.util.Arrays;
import java.util.List;
+import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.l2jserver.game.net.packet.client.CM_CHAR_ACTION.CharacterAction;
+import com.l2jserver.model.Model.ObjectDesire;
import com.l2jserver.model.dao.ItemDAO;
+import com.l2jserver.model.id.object.ItemID;
+import com.l2jserver.model.id.object.provider.ItemIDProvider;
+import com.l2jserver.model.id.template.ItemTemplateID;
import com.l2jserver.model.world.Actor;
import com.l2jserver.model.world.Item;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.character.CharacterInventory.ItemLocation;
+import com.l2jserver.model.world.item.ItemDropEvent;
import com.l2jserver.model.world.item.ItemPickUpEvent;
import com.l2jserver.service.AbstractService;
import com.l2jserver.service.AbstractService.Depends;
@@ -56,6 +63,10 @@ public class ItemServiceImpl extends AbstractService implements ItemService {
* The {@link WorldService} event dispatcher
*/
private final WorldEventDispatcher eventDispatcher;
+ /**
+ * The {@link ItemID} provider
+ */
+ private final ItemIDProvider itemIdProvider;
/**
* All items on the ground persisted to the database
@@ -69,13 +80,16 @@ public class ItemServiceImpl extends AbstractService implements ItemService {
* the spawn service
* @param eventDispatcher
* the world service event dispatcher
+ * @param itemIdProvider
+ * the {@link ItemID} provider
*/
@Inject
private ItemServiceImpl(ItemDAO itemDao, SpawnService spawnService,
- WorldEventDispatcher eventDispatcher) {
+ WorldEventDispatcher eventDispatcher, ItemIDProvider itemIdProvider) {
this.itemDao = itemDao;
this.spawnService = spawnService;
this.eventDispatcher = eventDispatcher;
+ this.itemIdProvider = itemIdProvider;
}
@Override
@@ -104,6 +118,44 @@ public class ItemServiceImpl extends AbstractService implements ItemService {
return item;
}
+ @Override
+ public Item split(Item item, long count)
+ throws NotEnoughItemsServiceException {
+ if (item.getCount() < count)
+ throw new NotEnoughItemsServiceException();
+ if (item.getCount() == count)
+ return item;
+
+ final Item splitItem = item.getTemplate().create();
+ splitItem.setID(itemIdProvider.createID());
+ splitItem.setCount(count);
+ item.setCount(item.getCount() - count);
+
+ splitItem.setObjectDesire(ObjectDesire.INSERT);
+
+ return splitItem;
+ }
+
+ @Override
+ public Item stack(Item... items) throws NonStackableItemsServiceException {
+ Preconditions.checkState(items.length >= 2,
+ "items length must be 2 or greater");
+ // TODO implement real item stacking
+
+ final ItemTemplateID templateID = items[0].getTemplateID();
+ for (final Item item : items) {
+ if (!item.getTemplateID().equals(templateID))
+ throw new NonStackableItemsServiceException();
+ }
+
+ final Item item = items[0];
+ for (int i = 1; i < items.length; i++) {
+ item.setCount(item.getCount() + items[i].getCount());
+ }
+
+ return item;
+ }
+
@Override
public Item pickUp(Item item, L2Character character)
throws ItemNotOnGroundServiceException, NotSpawnedServiceException {
@@ -111,15 +163,75 @@ public class ItemServiceImpl extends AbstractService implements ItemService {
if (item.getLocation() != ItemLocation.GROUND)
throw new ItemNotOnGroundServiceException();
+ final Item originalItem = item;
+
item.setLocation(ItemLocation.INVENTORY);
item.setPaperdoll(null);
item.setOwnerID(character.getID());
- character.getInventory().add(item);
+ final Item[] items = character.getInventory().getItems(
+ item.getTemplateID());
+ if (items.length != 0) {
+ Item[] stackItems = Arrays.copyOf(items, items.length + 1);
+ stackItems[items.length] = item;
+ try {
+ item = stack(stackItems);
+ Item[] removedItems = character.getInventory().remove(
+ stackItems);
+ for (final Item removeItem : removedItems) {
+ if (!removeItem.equals(item)) {
+ itemDao.delete(removeItem);
+ itemIdProvider.destroy(removeItem.getID());
+ }
+ }
+ character.getInventory().add(item);
+ } catch (NonStackableItemsServiceException e) {
+ character.getInventory().add(item);
+ }
+ } else {
+ character.getInventory().add(item);
+ }
- items.remove(item);
-
- spawnService.unspawn(item);
- eventDispatcher.dispatch(new ItemPickUpEvent(character, item));
+ character.getInventory().add(item);
+ this.items.remove(item);
+
+ itemDao.save(item);
+ spawnService.unspawn(originalItem);
+ eventDispatcher.dispatch(new ItemPickUpEvent(character,
+ originalItem, item));
+
+ return item;
+ }
+ }
+
+ @Override
+ public Item drop(Item item, long count, Point3D point, Actor actor)
+ throws SpawnPointNotFoundServiceException,
+ ItemAlreadyOnGroundServiceException,
+ AlreadySpawnedServiceException, NotEnoughItemsServiceException {
+ synchronized (item) {
+ if (item.getLocation() == ItemLocation.GROUND)
+ throw new AlreadySpawnedServiceException();
+
+ final Item sourceItem = item;
+ item = split(sourceItem, count);
+
+ item.setLocation(ItemLocation.GROUND);
+ item.setPaperdoll(null);
+
+ spawnService.spawn(item, point);
+ eventDispatcher.dispatch(new ItemDropEvent(actor, item));
+
+ if (actor instanceof L2Character) {
+ if (sourceItem.equals(item)) {
+ ((L2Character) actor).getInventory().remove(item);
+ }
+ }
+
+ itemDao.save(item);
+ if (!item.equals(sourceItem)) {
+ itemDao.save(sourceItem);
+ }
+ items.add(item);
return item;
}
@@ -128,18 +240,9 @@ public class ItemServiceImpl extends AbstractService implements ItemService {
@Override
public void drop(Item item, Point3D point, Actor actor)
throws SpawnPointNotFoundServiceException,
- ItemAlreadyOnGroundServiceException, AlreadySpawnedServiceException {
- synchronized (item) {
- if (item.getLocation() == ItemLocation.GROUND)
- throw new AlreadySpawnedServiceException();
-
- item.setLocation(ItemLocation.GROUND);
- item.setPaperdoll(null);
- // point will be set here
- spawnService.spawn(item, point);
-
- items.add(item);
- }
+ ItemAlreadyOnGroundServiceException,
+ AlreadySpawnedServiceException, NotEnoughItemsServiceException {
+ drop(item, item.getCount(), point, actor);
}
@Override
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/item/NonStackableItemsServiceException.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/item/NonStackableItemsServiceException.java
new file mode 100644
index 000000000..85ae18d95
--- /dev/null
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/item/NonStackableItemsServiceException.java
@@ -0,0 +1,59 @@
+/*
+ * This file is part of l2jserver2 + * Also note that this service is a low level implementation. In most cases, it + * might be more suitable the usage of high-level services, like + * {@link ItemService}, {@link NPCService} or {@link CharacterService}, since + * they can provide more security and dispatch more events to the + * {@link WorldService}. * * @author Rogiel */ diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java index b7caa4170..1be7abdd7 100644 --- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java +++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/network/broadcast/BroadcastServiceImpl.java @@ -46,6 +46,7 @@ import com.l2jserver.model.world.character.event.CharacterLeaveWorldEvent; import com.l2jserver.model.world.character.event.CharacterMoveEvent; import com.l2jserver.model.world.character.event.CharacterRunningEvent; import com.l2jserver.model.world.character.event.CharacterWalkingEvent; +import com.l2jserver.model.world.item.ItemDropEvent; import com.l2jserver.model.world.item.ItemPickUpEvent; import com.l2jserver.model.world.npc.event.NPCSpawnEvent; import com.l2jserver.model.world.player.event.PlayerTeleportedEvent; @@ -115,7 +116,7 @@ public class BroadcastServiceImpl extends AbstractService implements @Override protected boolean dispatch(WorldEvent e, PositionableObject object) { log.debug("Broadcast event received: {}", e); - if (e instanceof NPCSpawnEvent) { + if (e instanceof NPCSpawnEvent || e instanceof ItemDropEvent) { broadcast(conn, e.getObject()); } else if (e instanceof CharacterMoveEvent) { final CharacterMoveEvent evt = (CharacterMoveEvent) e; @@ -129,7 +130,7 @@ public class BroadcastServiceImpl extends AbstractService implements || e instanceof ActorUnspawnEvent || e instanceof ItemPickUpEvent) { // object is now out of sight - //FIXME pick up animation is not happening + // 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)