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

Implements item dropping and pickup stacking

This commit is contained in:
2011-12-15 16:41:09 -02:00
parent 352735c8c9
commit f87b9dd755
19 changed files with 581 additions and 77 deletions

View File

@@ -204,7 +204,7 @@ public enum SystemMessage {
* ID: 29<br>
* Message: You have obtained $s2 $s1.
*/
YOU_PICKED_UP_S1_S2(29),
YOU_PICKED_UP_S2_S1(29),
/**
* ID: 30<br>

View File

@@ -41,6 +41,7 @@ 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_CHAT;
import com.l2jserver.game.net.packet.client.CM_DROP_ITEM;
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;
@@ -187,6 +188,8 @@ public class Lineage2PacketReader extends OneToOneDecoder {
return CM_CHAR_OPEN_MAP.class;
case CM_ATTACK.OPCODE:
return CM_ATTACK.class;
case CM_DROP_ITEM.OPCODE:
return CM_DROP_ITEM.class;
default:
logger.warn("Unknown packet for 0x{}", Integer.toHexString(opcode));
break;

View File

@@ -118,9 +118,7 @@ public class CM_CHAR_ACTION extends AbstractClientPacket {
final NPC npc = ((NPCID) id).getObject();
try {
npcService.action(npc, conn.getCharacter(), action);
} catch (ActionServiceException e) {
conn.sendActionFailed();
} catch (CannotSetTargetServiceException e) {
} catch (ActionServiceException | CannotSetTargetServiceException e) {
conn.sendActionFailed();
}
} else if (id instanceof ItemID) {
@@ -133,7 +131,7 @@ public class CM_CHAR_ACTION extends AbstractClientPacket {
} else { // update only
conn.updateInventoryItems(stackItem);
}
conn.sendSystemMessage(SystemMessage.YOU_PICKED_UP_S1_S2, Long
conn.sendSystemMessage(SystemMessage.YOU_PICKED_UP_S2_S1, Long
.toString(item.getCount()), item.getTemplate()
.getName());
conn.sendActionFailed();

View File

@@ -0,0 +1,122 @@
/*
* 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.model.id.object.ItemID;
import com.l2jserver.model.id.object.provider.ItemIDProvider;
import com.l2jserver.model.world.Item;
import com.l2jserver.service.game.item.ItemAlreadyOnGroundServiceException;
import com.l2jserver.service.game.item.ItemService;
import com.l2jserver.service.game.item.NotEnoughItemsServiceException;
import com.l2jserver.service.game.spawn.AlreadySpawnedServiceException;
import com.l2jserver.service.game.spawn.SpawnPointNotFoundServiceException;
import com.l2jserver.util.geometry.Point3D;
/**
* This packet drops items on the ground.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class CM_DROP_ITEM extends AbstractClientPacket {
/**
* The packet OPCODE
*/
public static final int OPCODE = 0x17;
/**
* The {@link ItemService}
*/
private final ItemService itemService;
private final ItemIDProvider itemIdProvider;
/**
* The item ID
*/
private int objectId;
/**
* The number of items to be dropped
*/
private long count;
/**
* The location to be dropped
*/
private Point3D point;
/**
* @param itemService
* the item service
* @param itemIdProvider
* the item id provider
*/
@Inject
public CM_DROP_ITEM(ItemService itemService, ItemIDProvider itemIdProvider) {
this.itemService = itemService;
this.itemIdProvider = itemIdProvider;
}
@Override
public void read(Lineage2Client conn, ChannelBuffer buffer) {
objectId = buffer.readInt();
count = buffer.readLong();
point = Point3D.fromXYZ(buffer.readInt(), buffer.readInt(),
buffer.readInt());
}
@Override
public void process(final Lineage2Client conn) {
final ItemID id = itemIdProvider.resolveID(objectId);
final Item item = id.getObject();
if (item == null) {
conn.sendActionFailed();
return;
}
if (!conn.getCharacterID().equals(item.getOwnerID())) {
conn.sendActionFailed();
return;
}
try {
final Item dropped = itemService.drop(item, count, point,
conn.getCharacter());
if (dropped.equals(item)) {
conn.removeInventoryItems(dropped);
} else {
conn.updateInventoryItems(item);
}
if (dropped.getCount() == 1) {
conn.sendSystemMessage(SystemMessage.YOU_DROPPED_S1, item
.getTemplate().getName());
} else {
conn.sendSystemMessage(SystemMessage.DROPPED_S1_S2, item
.getTemplate().getName(), Long.toString(dropped
.getCount()));
}
} catch (ItemAlreadyOnGroundServiceException
| AlreadySpawnedServiceException
| SpawnPointNotFoundServiceException
| NotEnoughItemsServiceException e) {
conn.sendActionFailed();
}
}
}

View File

@@ -59,6 +59,7 @@ public class SM_CHAR_INVENTORY extends AbstractServerPacket {
int slot = 0;
for (Item item : inventory) {
if (item.getLocation() == ItemLocation.WAREHOUSE
|| item.getLocation() == ItemLocation.GROUND
|| item.getLocation() == null) {
continue;
}

View File

@@ -17,21 +17,22 @@
package com.l2jserver.model.world;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.ItemID;
import com.l2jserver.model.id.template.ItemTemplateID;
import com.l2jserver.model.template.item.ItemTemplate;
import com.l2jserver.model.world.character.CharacterInventory.ItemLocation;
import com.l2jserver.model.world.character.CharacterInventory.InventoryPaperdoll;
import com.l2jserver.model.world.character.CharacterInventory.ItemLocation;
/**
* This class represents an {@link Item} in the Lineage II World. The item can
* be:
* <ul>
* <li><b>In the {@link L2Character character} inventory</b>: <tt>location</tt>
* is {@link ItemLocation#INVENTORY}, <tt>coordinate</tt> and
* <tt>paperdoll</tt> are null.</li>
* is {@link ItemLocation#INVENTORY}, <tt>coordinate</tt> and <tt>paperdoll</tt>
* are null.</li>
* <li><b>In the {@link L2Character character} warehouse</b>: <tt>location</tt>
* is {@link ItemLocation#WAREHOUSE}, <tt>coordinate</tt> and
* <tt>paperdoll</tt> are null.</li>
* is {@link ItemLocation#WAREHOUSE}, <tt>coordinate</tt> and <tt>paperdoll</tt>
* are null.</li>
* <li><b>Equipped by the {@link L2Character character}</b>: <tt>location</tt>
* is {@link ItemLocation#PAPERDOLL}, <tt>paperdoll</tt> is not null and
* <tt>coordinate</tt> is null.</li>
@@ -58,7 +59,7 @@ public class Item extends PositionableObject {
/**
* Inventory location of this item
*/
private ItemLocation location;
private ItemLocation location = ItemLocation.INVENTORY;
/**
* Paperdoll slot for this item
*/
@@ -156,4 +157,9 @@ public class Item extends PositionableObject {
desireUpdate();
this.ownerID = ownerID;
}
@Override
public ItemID getID() {
return (ItemID) super.getID();
}
}

View File

@@ -16,12 +16,13 @@
*/
package com.l2jserver.model.world.character;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.l2jserver.model.id.object.ItemID;
import com.l2jserver.model.id.template.ItemTemplateID;
import com.l2jserver.model.world.Item;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.util.factory.CollectionFactory;
@@ -76,6 +77,23 @@ public class CharacterInventory implements Iterable<Item> {
return null;
}
/**
* Removes several items from the players inventory.
*
* @param items
* the items to be removed
* @return the items that were effectivelly removed
*/
public Item[] remove(Item... items) {
final List<Item> removedItems = CollectionFactory.newList();
for (final Item item : items) {
if (this.items.remove(item)) {
removedItems.add(item);
}
}
return removedItems.toArray(new Item[removedItems.size()]);
}
/**
* Removes all items from the given {@link ItemID}
*
@@ -84,7 +102,7 @@ public class CharacterInventory implements Iterable<Item> {
* @return an array of all items removed. Can never be <code>null</code>.
*/
public Item[] remove(ItemID itemID) {
final ArrayList<Item> removedItems = new ArrayList<Item>();
final List<Item> removedItems = CollectionFactory.newList();
for (final Item item : items) {
if (item.getID().equals(itemID)) {
items.remove(item);
@@ -94,6 +112,23 @@ public class CharacterInventory implements Iterable<Item> {
return removedItems.toArray(new Item[removedItems.size()]);
}
/**
* Returns all items from the given {@link ItemTemplateID}
*
* @param itemTemplateID
* the {@link ItemTemplateID}
* @return an array of all items with the given ID
*/
public Item[] getItems(ItemTemplateID itemTemplateID) {
final List<Item> allItems = CollectionFactory.newList();
for (final Item item : items) {
if (item.getTemplateID().equals(itemTemplateID)) {
allItems.add(item);
}
}
return allItems.toArray(new Item[allItems.size()]);
}
/**
* Get the item in the given <tt>paperdoll</tt> slot
*

View File

@@ -19,20 +19,19 @@ package com.l2jserver.model.world.item;
import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.world.Actor;
import com.l2jserver.model.world.Item;
import com.l2jserver.model.world.Player;
import com.l2jserver.model.world.WorldObject;
import com.l2jserver.model.world.player.event.PlayerEvent;
import com.l2jserver.model.world.actor.event.ActorEvent;
/**
* Event dispatched once an {@link Item} has been dropped on the ground.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class ItemDropEvent implements ItemEvent, PlayerEvent {
public class ItemDropEvent implements ItemEvent, ActorEvent {
/**
* The dropping player
* The dropping actor
*/
private final Player player;
private final Actor actor;
/**
* The item dropped
*/
@@ -41,13 +40,13 @@ public class ItemDropEvent implements ItemEvent, PlayerEvent {
/**
* Creates a new instance of this event
*
* @param player
* the dropping player
* @param actor
* the dropping actor
* @param item
* the dropped item
*/
public ItemDropEvent(Player player, Item item) {
this.player = player;
public ItemDropEvent(Actor actor, Item item) {
this.actor = actor;
this.item = item;
}
@@ -56,11 +55,6 @@ public class ItemDropEvent implements ItemEvent, PlayerEvent {
return item;
}
@Override
public Player getPlayer() {
return player;
}
@Override
public Item getItem() {
return item;
@@ -68,7 +62,7 @@ public class ItemDropEvent implements ItemEvent, PlayerEvent {
@Override
public Actor getActor() {
return player;
return actor;
}
@Override

View File

@@ -38,6 +38,10 @@ public class ItemPickUpEvent implements ItemEvent, CharacterEvent {
* The item picked up
*/
private final Item item;
/**
* The new item
*/
private final Item newItem;
/**
* Creates a new instance of this event
@@ -46,10 +50,19 @@ public class ItemPickUpEvent implements ItemEvent, CharacterEvent {
* the picking up character
* @param item
* the picked up item
* @param newItem the new {@link Item}
*/
public ItemPickUpEvent(L2Character character, Item item) {
public ItemPickUpEvent(L2Character character, Item item, Item newItem) {
this.character = character;
this.item = item;
this.newItem = newItem;
}
/**
* @return the new {@link Item}
*/
public Item getNewItem() {
return newItem;
}
@Override

View File

@@ -184,12 +184,13 @@ public abstract class JDBCItemDAO extends AbstractJDBCDAO<Item, ItemID>
@Override
protected String query() {
return "SELECT * FROM `" + TABLE + "` WHERE `" + CHAR_ID
+ "` = ?";
+ "` = ? AND `location` = ?";
}
@Override
protected void parametize(PreparedStatement st) throws SQLException {
st.setInt(1, character.getID().getID());
st.setString(2, ItemLocation.INVENTORY.name());
}
@Override
@@ -239,23 +240,47 @@ public abstract class JDBCItemDAO extends AbstractJDBCDAO<Item, ItemID>
@Override
public boolean insert(Item item) {
throw new UnsupportedOperationException(
"Saving items is not yet implemented!");
return database.query(new InsertUpdateQuery<Item>(item) {
@Override
protected String query() {
return "INSERT INTO `" + TABLE + "` (`" + ITEM_ID + "`,`"
+ TEMPLATE_ID + "`,`" + CHAR_ID + "`,`" + LOCATION
+ "`,`" + PAPERDOLL + "`,`" + COUNT + "`,`" + COORD_X
+ "`,`" + COORD_Y + "`,`" + COORD_Z
+ "`) VALUES(?,?,?,?,?,?,?,?,?)";
}
@Override
protected void parametize(PreparedStatement st, Item item)
throws SQLException {
int i = 1;
st.setInt(i++, item.getID().getID());
st.setInt(i++, item.getTemplateID().getID());
if (item.getOwnerID() != null) {
st.setInt(i++, item.getOwnerID().getID());
} else {
st.setNull(i++, Types.INTEGER);
}
st.setString(i++, item.getLocation().name());
st.setString(i++, (item.getPaperdoll() != null ? item
.getPaperdoll().name() : null));
st.setLong(i++, item.getCount());
if (item.getPoint() != null) {
st.setInt(i++, item.getPoint().getX());
st.setInt(i++, item.getPoint().getY());
st.setInt(i++, item.getPoint().getZ());
} else {
st.setNull(i++, Types.INTEGER);
st.setNull(i++, Types.INTEGER);
st.setNull(i++, Types.INTEGER);
}
}
}) > 0;
}
@Override
public boolean update(Item item) {
// public static final String ITEM_ID = "item_id";
// public static final String TEMPLATE_ID = "template_id";
// public static final String CHAR_ID = JDBCCharacterDAO.CHAR_ID;
//
// public static final String LOCATION = "location";
// public static final String PAPERDOLL = "paperdoll";
// public static final String COUNT = "count";
// public static final String COORD_X = "coord_x";
// public static final String COORD_Y = "coord_y";
// public static final String COORD_Z = "coord_z";
return database.query(new InsertUpdateQuery<Item>(item) {
@Override
protected String query() {
@@ -285,16 +310,15 @@ public abstract class JDBCItemDAO extends AbstractJDBCDAO<Item, ItemID>
st.setInt(i++, item.getPoint().getY());
st.setInt(i++, item.getPoint().getZ());
} else {
st.setInt(i++, 0);
st.setInt(i++, 0);
st.setInt(i++, 0);
st.setNull(i++, Types.INTEGER);
st.setNull(i++, Types.INTEGER);
st.setNull(i++, Types.INTEGER);
}
// WHERE
st.setInt(i++, item.getID().getID());
}
}) > 0;
}
@Override

View File

@@ -52,6 +52,33 @@ public interface ItemService extends Service {
Item action(Item item, L2Character character, CharacterAction action)
throws ItemNotOnGroundServiceException, NotSpawnedServiceException;
/**
* Splits this item in two pieces
*
* @param item
* the item to be splitted
* @param count
* the amount of items that will be decreased from the argument
* {@link Item} and added to the result one.
* @return the splitted item
* @throws NotEnoughItemsServiceException
* if <code>count</code> 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 <code>actor</code> is not
* <code>null</code> 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 <code>null</code> if
* {@link Item#getPoint()} is set.
* @param actor
* the dropping actor. Can be <code>null</code>.
* @return <code>item</code> 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 <code>point</code> was <code>null</code> and
* {@link Item#getPoint()} was not set.
* @throws NotEnoughItemsServiceException
* if <code>count</code> 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 <code>actor</code> is not
* <code>null</code> he is flagged as the dropper actor.
@@ -86,8 +142,11 @@ public interface ItemService extends Service {
* @throws SpawnPointNotFoundServiceException
* if <code>point</code> was <code>null</code> and
* {@link Item#getPoint()} was not set.
* @throws NotEnoughItemsServiceException
* if <code>count</code> is bigger than {@link Item#getCount()}.
*/
void drop(Item item, Point3D point, Actor actor)
throws ItemAlreadyOnGroundServiceException,
AlreadySpawnedServiceException, SpawnPointNotFoundServiceException;
AlreadySpawnedServiceException, SpawnPointNotFoundServiceException,
NotEnoughItemsServiceException;
}

View File

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

View File

@@ -0,0 +1,59 @@
/*
* This file is part of l2jserver2 <l2jserver2.com>.
*
* l2jserver2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver2. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.game.item;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class NonStackableItemsServiceException extends ItemServiceException {
/**
* Java Serialization API ID
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance
*/
public NonStackableItemsServiceException() {
}
/**
* @param message
* the message
* @param cause
* the cause
*/
public NonStackableItemsServiceException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
* the message
*/
public NonStackableItemsServiceException(String message) {
super(message);
}
/**
* @param cause
* the cause
*/
public NonStackableItemsServiceException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,59 @@
/*
* This file is part of l2jserver2 <l2jserver2.com>.
*
* l2jserver2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver2. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.game.item;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class NotEnoughItemsServiceException extends ItemServiceException {
/**
* Java Serialization API ID
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance
*/
public NotEnoughItemsServiceException() {
}
/**
* @param message
* the message
* @param cause
* the cause
*/
public NotEnoughItemsServiceException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
* the message
*/
public NotEnoughItemsServiceException(String message) {
super(message);
}
/**
* @param cause
* the cause
*/
public NotEnoughItemsServiceException(Throwable cause) {
super(cause);
}
}

View File

@@ -30,7 +30,10 @@ import com.l2jserver.model.world.player.event.PlayerTeleportedEvent;
import com.l2jserver.service.Service;
import com.l2jserver.service.core.threading.AsyncFuture;
import com.l2jserver.service.core.threading.ThreadService;
import com.l2jserver.service.game.character.CharacterService;
import com.l2jserver.service.game.item.ItemService;
import com.l2jserver.service.game.npc.NPCService;
import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.util.geometry.Coordinate;
import com.l2jserver.util.geometry.Point3D;
@@ -52,6 +55,12 @@ import com.l2jserver.util.geometry.Point3D;
* do, the {@link NPC} will not be respawned. The only possible way to respawn
* it is through an forced spawn (manual) or server restart. See
* {@link NPCService} if you wish to correctly unspawn an {@link NPC}.
* <p>
* 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 <a href="http://www.rogiel.com">Rogiel</a>
*/

View File

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