From f454e3c35affceadd356e7531cb386d296ee47f9 Mon Sep 17 00:00:00 2001 From: rogiel Date: Sat, 30 Apr 2011 01:51:36 -0300 Subject: [PATCH] Change-Id: I0cca627373c68d94025647f802a7fa6b419e0aad --- .../com/l2jserver/db/dao/CharacterDAO.java | 38 ++- src/dao/com/l2jserver/db/dao/ClanDAO.java | 45 +++ src/dao/com/l2jserver/db/dao/ItemDAO.java | 56 ++++ src/dao/com/l2jserver/db/dao/PetDAO.java | 45 +++ .../db/dao/db4o/AbstractDB4ODAO.java | 2 +- .../db/dao/db4o/DB4OCharacterDAO.java | 14 +- .../db/dao/mysql5/AbstractMySQL5DAO.java | 16 + .../db/dao/mysql5/DAOModuleMySQL5.java | 15 + .../db/dao/mysql5/MySQL5CharacterDAO.java | 94 ++++++ .../db/dao/mysql5/MySQL5ItemDAO.java | 121 ++++++++ .../game/net/Lineage2Connection.java | 30 ++ .../server/CharSelectionInfoPacket.java | 5 +- .../com/l2jserver/model/id/CharacterID.java | 21 +- .../java/com/l2jserver/model/id/ClanID.java | 23 ++ src/main/java/com/l2jserver/model/id/ID.java | 52 +++- .../java/com/l2jserver/model/id/ItemID.java | 24 ++ .../java/com/l2jserver/model/id/ObjectID.java | 20 +- .../java/com/l2jserver/model/id/PetID.java | 23 ++ .../java/com/l2jserver/model/id/SimpleID.java | 5 - .../com/l2jserver/model/id/TemplateID.java | 13 +- .../model/id/allocator/BitSetIDAllocator.java | 114 +++++++ .../model/id/allocator/IDAllocator.java | 59 ++++ .../id/allocator/IDAllocatorException.java | 21 ++ .../model/id/factory/CharacterIDFactory.java | 62 ++++ .../model/id/factory/ClanIDFactory.java | 61 ++++ .../l2jserver/model/id/factory/IDFactory.java | 34 ++ .../model/id/factory/IDFactoryModule.java | 29 ++ .../model/id/factory/ItemIDFactory.java | 61 ++++ .../model/id/factory/ObjectIDFactory.java | 6 + .../model/id/factory/PetIDFactory.java | 61 ++++ .../model/template/capability/Attackable.java | 7 +- .../model/template/capability/Defendable.java | 7 +- .../l2jserver/model/world/AbstractActor.java | 18 -- .../l2jserver/model/world/AbstractObject.java | 8 +- .../java/com/l2jserver/model/world/Clan.java | 71 +++++ .../java/com/l2jserver/model/world/Item.java | 45 ++- .../l2jserver/model/world/L2Character.java | 131 +++++++- .../java/com/l2jserver/model/world/Party.java | 36 +++ .../java/com/l2jserver/model/world/Pet.java | 35 ++- .../com/l2jserver/model/world/Player.java | 26 +- .../l2jserver/model/world/WorldObject.java | 18 +- .../model/world/capability/Child.java | 13 - .../model/world/capability/Joinable.java | 26 ++ .../model/world/capability/Listenable.java | 23 -- .../model/world/capability/Parent.java | 12 - .../world/character/CharacterAppearance.java | 290 ++++++++++++++++++ .../world/character/CharacterFriendList.java | 37 +++ .../world/character/CharacterInventory.java | 38 +++ .../l2jserver/model/world/clan/ClanEvent.java | 8 + .../model/world/clan/ClanListener.java | 6 + .../model/world/clan/ClanMembers.java | 76 +++++ .../model/world/event/WorldEvent.java | 6 +- .../model/world/event/WorldListener.java | 8 +- .../model/world/filter/impl/IDFilter.java | 2 +- .../model/world/item/ItemDropEvent.java | 13 +- .../model/world/party/PartyEvent.java | 8 + .../model/world/party/PartyListener.java | 6 + .../model/world/player/PlayerListener.java | 8 +- .../model/world/player/PlayerSpawnEvent.java | 12 +- .../l2jserver/service/cache/CacheService.java | 20 ++ .../l2jserver/service/cache/Cacheable.java | 5 + .../service/cache/IgnoreCaching.java | 16 + .../service/cache/SimpleCacheService.java | 94 ++++++ .../game/world/WorldEventDispatcher.java | 63 ++++ .../game/world/WorldEventDispatcherImpl.java | 141 ++++++++- .../service/network/NettyNetworkService.java | 1 - .../service/network/NetworkService.java | 1 - .../java/com/l2jserver/util/PrimeFinder.java | 158 ++++++++++ .../java/com/l2jserver/util/RGBColor.java | 38 +++ .../util/factory/CollectionFactory.java | 59 ---- .../id/allocator/BitSetIDAllocatorTest.java | 64 ++++ .../model/id/factory/IDFactoryTest.java | 48 +++ .../service/cache/SimpleCacheServiceTest.java | 74 +++++ .../world/WorldEventDispatcherImplTest.java | 53 +++- 74 files changed, 2744 insertions(+), 255 deletions(-) create mode 100644 src/dao/com/l2jserver/db/dao/ClanDAO.java create mode 100644 src/dao/com/l2jserver/db/dao/ItemDAO.java create mode 100644 src/dao/com/l2jserver/db/dao/PetDAO.java create mode 100644 src/dao/mysql5/com/l2jserver/db/dao/mysql5/AbstractMySQL5DAO.java create mode 100644 src/dao/mysql5/com/l2jserver/db/dao/mysql5/DAOModuleMySQL5.java create mode 100644 src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5CharacterDAO.java create mode 100644 src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5ItemDAO.java create mode 100644 src/main/java/com/l2jserver/model/id/ClanID.java create mode 100644 src/main/java/com/l2jserver/model/id/ItemID.java create mode 100644 src/main/java/com/l2jserver/model/id/PetID.java delete mode 100644 src/main/java/com/l2jserver/model/id/SimpleID.java create mode 100644 src/main/java/com/l2jserver/model/id/allocator/BitSetIDAllocator.java create mode 100644 src/main/java/com/l2jserver/model/id/allocator/IDAllocator.java create mode 100644 src/main/java/com/l2jserver/model/id/allocator/IDAllocatorException.java create mode 100644 src/main/java/com/l2jserver/model/id/factory/CharacterIDFactory.java create mode 100644 src/main/java/com/l2jserver/model/id/factory/ClanIDFactory.java create mode 100644 src/main/java/com/l2jserver/model/id/factory/IDFactory.java create mode 100644 src/main/java/com/l2jserver/model/id/factory/IDFactoryModule.java create mode 100644 src/main/java/com/l2jserver/model/id/factory/ItemIDFactory.java create mode 100644 src/main/java/com/l2jserver/model/id/factory/ObjectIDFactory.java create mode 100644 src/main/java/com/l2jserver/model/id/factory/PetIDFactory.java create mode 100644 src/main/java/com/l2jserver/model/world/Clan.java create mode 100644 src/main/java/com/l2jserver/model/world/Party.java delete mode 100644 src/main/java/com/l2jserver/model/world/capability/Child.java create mode 100644 src/main/java/com/l2jserver/model/world/capability/Joinable.java delete mode 100644 src/main/java/com/l2jserver/model/world/capability/Parent.java create mode 100644 src/main/java/com/l2jserver/model/world/character/CharacterAppearance.java create mode 100644 src/main/java/com/l2jserver/model/world/character/CharacterFriendList.java create mode 100644 src/main/java/com/l2jserver/model/world/character/CharacterInventory.java create mode 100644 src/main/java/com/l2jserver/model/world/clan/ClanEvent.java create mode 100644 src/main/java/com/l2jserver/model/world/clan/ClanListener.java create mode 100644 src/main/java/com/l2jserver/model/world/clan/ClanMembers.java create mode 100644 src/main/java/com/l2jserver/model/world/party/PartyEvent.java create mode 100644 src/main/java/com/l2jserver/model/world/party/PartyListener.java create mode 100644 src/main/java/com/l2jserver/service/cache/CacheService.java create mode 100644 src/main/java/com/l2jserver/service/cache/Cacheable.java create mode 100644 src/main/java/com/l2jserver/service/cache/IgnoreCaching.java create mode 100644 src/main/java/com/l2jserver/service/cache/SimpleCacheService.java create mode 100644 src/main/java/com/l2jserver/util/PrimeFinder.java create mode 100644 src/main/java/com/l2jserver/util/RGBColor.java delete mode 100644 src/main/java/com/l2jserver/util/factory/CollectionFactory.java create mode 100644 src/test/java/com/l2jserver/model/id/allocator/BitSetIDAllocatorTest.java create mode 100644 src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java create mode 100644 src/test/java/com/l2jserver/service/cache/SimpleCacheServiceTest.java diff --git a/src/dao/com/l2jserver/db/dao/CharacterDAO.java b/src/dao/com/l2jserver/db/dao/CharacterDAO.java index f68e94d5d..8c35ec0a7 100644 --- a/src/dao/com/l2jserver/db/dao/CharacterDAO.java +++ b/src/dao/com/l2jserver/db/dao/CharacterDAO.java @@ -1,16 +1,46 @@ package com.l2jserver.db.dao; +import java.util.List; + import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.id.ID; import com.l2jserver.model.world.L2Character; -import com.l2jserver.model.world.Player; +import com.l2jserver.service.cache.Cacheable; +import com.l2jserver.service.cache.IgnoreCaching; import com.l2jserver.service.database.DataAccessObject; /** - * The {@link CharacterDAO} is can load and save {@link Player player instances}. + * The {@link CharacterDAO} is can load and save {@link Character character + * instances} . * * @author Rogiel */ -public interface CharacterDAO extends DataAccessObject { +public interface CharacterDAO extends DataAccessObject, Cacheable { + /** + * Load the instance represented by id from the database + * + * @param id + * the id + */ L2Character load(CharacterID id); - void save(L2Character character); + + /** + * Loads an List of all {@link ID}s in the database + * + * @return the list containing all ids + */ + @IgnoreCaching + List listIDs(); + + /** + * Save the instance to the database. If a new database entry was created + * returns true. + * + * @param id + * the id + * @return true if created a new entry in database (i.e. insert), false if + * not created (i.e. update) + */ + @IgnoreCaching + boolean save(L2Character character); } diff --git a/src/dao/com/l2jserver/db/dao/ClanDAO.java b/src/dao/com/l2jserver/db/dao/ClanDAO.java new file mode 100644 index 000000000..90a40872b --- /dev/null +++ b/src/dao/com/l2jserver/db/dao/ClanDAO.java @@ -0,0 +1,45 @@ +package com.l2jserver.db.dao; + +import java.util.List; + +import com.l2jserver.model.id.ClanID; +import com.l2jserver.model.id.ID; +import com.l2jserver.model.world.Clan; +import com.l2jserver.service.cache.Cacheable; +import com.l2jserver.service.cache.IgnoreCaching; +import com.l2jserver.service.database.DataAccessObject; + +/** + * The {@link ClanDAO} is can load and save {@link Clan clan instances}. + * + * @author Rogiel + */ +public interface ClanDAO extends DataAccessObject, Cacheable { + /** + * Load the instance represented by id from the database + * + * @param id + * the id + */ + Clan load(ClanID id); + + /** + * Loads an List of all {@link ID}s in the database + * + * @return the list containing all ids + */ + @IgnoreCaching + List listIDs(); + + /** + * Save the instance to the database. If a new database entry was created + * returns true. + * + * @param id + * the id + * @return true if created a new entry in database (i.e. insert), false if + * not created (i.e. update) + */ + @IgnoreCaching + boolean save(Clan character); +} diff --git a/src/dao/com/l2jserver/db/dao/ItemDAO.java b/src/dao/com/l2jserver/db/dao/ItemDAO.java new file mode 100644 index 000000000..da9b5bd0c --- /dev/null +++ b/src/dao/com/l2jserver/db/dao/ItemDAO.java @@ -0,0 +1,56 @@ +package com.l2jserver.db.dao; + +import java.util.List; + +import com.l2jserver.model.id.ID; +import com.l2jserver.model.id.ItemID; +import com.l2jserver.model.world.Item; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.service.cache.Cacheable; +import com.l2jserver.service.cache.IgnoreCaching; +import com.l2jserver.service.database.DataAccessObject; + +/** + * The {@link ItemDAO} is can load and save {@link Character character + * instances} . + * + * @author Rogiel + */ +public interface ItemDAO extends DataAccessObject, Cacheable { + /** + * Load the instance represented by id from the database + * + * @param id + * the id + */ + Item load(ItemID id); + + /** + * Load the inventory for an {@link L2Character character}. + * + * @param character + * the character + * @return amount of items loaded + */ + int loadInventory(L2Character character); + + /** + * Loads an List of all {@link ID}s in the database + * + * @return the list containing all ids + */ + @IgnoreCaching + List listIDs(); + + /** + * Save the instance to the database. If a new database entry was created + * returns true. + * + * @param id + * the id + * @return true if created a new entry in database (i.e. insert), false if + * not created (i.e. update) + */ + @IgnoreCaching + boolean save(Item character); +} diff --git a/src/dao/com/l2jserver/db/dao/PetDAO.java b/src/dao/com/l2jserver/db/dao/PetDAO.java new file mode 100644 index 000000000..ab7f0c019 --- /dev/null +++ b/src/dao/com/l2jserver/db/dao/PetDAO.java @@ -0,0 +1,45 @@ +package com.l2jserver.db.dao; + +import java.util.List; + +import com.l2jserver.model.id.ID; +import com.l2jserver.model.id.PetID; +import com.l2jserver.model.world.Pet; +import com.l2jserver.service.cache.Cacheable; +import com.l2jserver.service.cache.IgnoreCaching; +import com.l2jserver.service.database.DataAccessObject; + +/** + * The {@link PetDAO} is can load and save {@link Pet pet instances}. + * + * @author Rogiel + */ +public interface PetDAO extends DataAccessObject, Cacheable { + /** + * Load the instance represented by id from the database + * + * @param id + * the id + */ + Pet load(PetID id); + + /** + * Loads an List of all {@link ID}s in the database + * + * @return the list containing all ids + */ + @IgnoreCaching + List listIDs(); + + /** + * Save the instance to the database. If a new database entry was created + * returns true. + * + * @param id + * the id + * @return true if created a new entry in database (i.e. insert), false if + * not created (i.e. update) + */ + @IgnoreCaching + boolean save(Pet character); +} diff --git a/src/dao/db4o/com/l2jserver/db/dao/db4o/AbstractDB4ODAO.java b/src/dao/db4o/com/l2jserver/db/dao/db4o/AbstractDB4ODAO.java index 3000916fe..f9ba28382 100644 --- a/src/dao/db4o/com/l2jserver/db/dao/db4o/AbstractDB4ODAO.java +++ b/src/dao/db4o/com/l2jserver/db/dao/db4o/AbstractDB4ODAO.java @@ -4,7 +4,7 @@ import com.google.inject.Inject; import com.l2jserver.service.database.AbstractDAO; import com.l2jserver.service.database.DB4ODatabaseService; -public class AbstractDB4ODAO extends AbstractDAO implements BD4ODAO { +public class AbstractDB4ODAO extends AbstractDAO implements BD4ODAO { protected final DB4ODatabaseService database; @Inject diff --git a/src/dao/db4o/com/l2jserver/db/dao/db4o/DB4OCharacterDAO.java b/src/dao/db4o/com/l2jserver/db/dao/db4o/DB4OCharacterDAO.java index 95f2a99fe..90e6e5e08 100644 --- a/src/dao/db4o/com/l2jserver/db/dao/db4o/DB4OCharacterDAO.java +++ b/src/dao/db4o/com/l2jserver/db/dao/db4o/DB4OCharacterDAO.java @@ -1,12 +1,14 @@ package com.l2jserver.db.dao.db4o; +import java.util.List; + import com.google.inject.Inject; import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.model.id.CharacterID; import com.l2jserver.model.world.L2Character; import com.l2jserver.service.database.DB4ODatabaseService; -public class DB4OCharacterDAO extends AbstractDB4ODAO implements CharacterDAO { +public class DB4OCharacterDAO extends AbstractDB4ODAO implements CharacterDAO { @Inject protected DB4OCharacterDAO(DB4ODatabaseService database) { super(database); @@ -19,8 +21,14 @@ public class DB4OCharacterDAO extends AbstractDB4ODAO implements CharacterDAO { } @Override - public void save(L2Character character) { + public boolean save(L2Character character) { // TODO Auto-generated method stub - + return false; + } + + @Override + public List listIDs() { + // TODO Auto-generated method stub + return null; } } diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/AbstractMySQL5DAO.java b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/AbstractMySQL5DAO.java new file mode 100644 index 000000000..a3cf638bc --- /dev/null +++ b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/AbstractMySQL5DAO.java @@ -0,0 +1,16 @@ +package com.l2jserver.db.dao.mysql5; + +import com.google.inject.Inject; +import com.l2jserver.service.database.AbstractDAO; +import com.l2jserver.service.database.DatabaseService; +import com.l2jserver.service.database.MySQLDatabaseService; + +public class AbstractMySQL5DAO extends AbstractDAO { + protected final MySQLDatabaseService database; + + @Inject + protected AbstractMySQL5DAO(DatabaseService database) { + super(database); + this.database = (MySQLDatabaseService) database; + } +} diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/DAOModuleMySQL5.java b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/DAOModuleMySQL5.java new file mode 100644 index 000000000..5854d9d02 --- /dev/null +++ b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/DAOModuleMySQL5.java @@ -0,0 +1,15 @@ +package com.l2jserver.db.dao.mysql5; + +import com.google.inject.AbstractModule; +import com.google.inject.Scopes; +import com.l2jserver.db.dao.CharacterDAO; +import com.l2jserver.db.dao.ItemDAO; + +public class DAOModuleMySQL5 extends AbstractModule { + @Override + protected void configure() { + bind(CharacterDAO.class).to(MySQL5CharacterDAO.class).in( + Scopes.SINGLETON); + bind(ItemDAO.class).to(MySQL5ItemDAO.class).in(Scopes.SINGLETON); + } +} diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5CharacterDAO.java b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5CharacterDAO.java new file mode 100644 index 000000000..dc123a810 --- /dev/null +++ b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5CharacterDAO.java @@ -0,0 +1,94 @@ +package com.l2jserver.db.dao.mysql5; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import com.google.inject.Inject; +import com.l2jserver.db.dao.CharacterDAO; +import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.id.factory.CharacterIDFactory; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.service.database.DatabaseService; +import com.l2jserver.service.database.MySQLDatabaseService.Mapper; +import com.l2jserver.service.database.MySQLDatabaseService.SelectListQuery; +import com.l2jserver.service.database.MySQLDatabaseService.SelectSingleQuery; + +public class MySQL5CharacterDAO extends AbstractMySQL5DAO + implements CharacterDAO { + private final CharacterIDFactory idFactory; + + /** + * Character table name + */ + public static final String TABLE = "character"; + // FIELDS + public static final String CHAR_ID = "character_id"; + public static final String NAME = "name"; + + @Inject + public MySQL5CharacterDAO(DatabaseService database, + final CharacterIDFactory idFactory) { + super(database); + this.idFactory = idFactory; + } + + private final class CharacterMapper implements Mapper { + @Override + public L2Character map(ResultSet rs) throws SQLException { + final L2Character character = new L2Character(); + character.setID(idFactory.createID(rs.getInt(CHAR_ID))); + character.setName(rs.getString(NAME)); + return character; + } + } + + @Override + public L2Character load(final CharacterID id) { + return database.query(new SelectSingleQuery() { + @Override + protected String query() { + return "SELECT * FROM `" + TABLE + "` WHERE `" + CHAR_ID + + "` = ?"; + } + + @Override + protected void parametize(PreparedStatement st) throws SQLException { + st.setInt(1, id.getID()); + } + + @Override + protected Mapper mapper() { + return new CharacterMapper(); + } + }); + } + + @Override + public List listIDs() { + return database.query(new SelectListQuery() { + @Override + protected String query() { + return "SELECT * FROM `" + TABLE + "` WHERE `" + CHAR_ID + + "` = ?"; + } + + @Override + protected Mapper mapper() { + return new Mapper() { + @Override + public CharacterID map(ResultSet rs) throws SQLException { + return idFactory.createID(rs.getInt(CHAR_ID)); + } + }; + } + }); + } + + @Override + public boolean save(L2Character character) { + throw new UnsupportedOperationException( + "Saving characters is not yet implemented!"); + } +} diff --git a/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5ItemDAO.java b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5ItemDAO.java new file mode 100644 index 000000000..ddc1aed1f --- /dev/null +++ b/src/dao/mysql5/com/l2jserver/db/dao/mysql5/MySQL5ItemDAO.java @@ -0,0 +1,121 @@ +package com.l2jserver.db.dao.mysql5; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import com.google.inject.Inject; +import com.l2jserver.db.dao.ItemDAO; +import com.l2jserver.model.id.ItemID; +import com.l2jserver.model.id.factory.CharacterIDFactory; +import com.l2jserver.model.id.factory.ItemIDFactory; +import com.l2jserver.model.world.Item; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.model.world.character.CharacterInventory; +import com.l2jserver.service.database.DatabaseService; +import com.l2jserver.service.database.MySQLDatabaseService.Mapper; +import com.l2jserver.service.database.MySQLDatabaseService.SelectListQuery; +import com.l2jserver.service.database.MySQLDatabaseService.SelectSingleQuery; + +public class MySQL5ItemDAO extends AbstractMySQL5DAO implements ItemDAO { + private final ItemIDFactory idFactory; + private final CharacterIDFactory charIdFactory; + + /** + * Character table name + */ + public static final String TABLE = "item"; + // FIELDS + public static final String ITEM_ID = "item_id"; + public static final String CHAR_ID = MySQL5CharacterDAO.CHAR_ID; + + @Inject + public MySQL5ItemDAO(DatabaseService database, + final ItemIDFactory idFactory, CharacterIDFactory charIdFactory) { + super(database); + this.idFactory = idFactory; + this.charIdFactory = charIdFactory; + } + + private final class CharacterMapper implements Mapper { + @Override + public Item map(ResultSet rs) throws SQLException { + final Item item = new Item(); + item.setID(idFactory.createID(rs.getInt(ITEM_ID))); + item.setID(charIdFactory.createID(rs.getInt(CHAR_ID))); + return item; + } + } + + @Override + public Item load(final ItemID id) { + return database.query(new SelectSingleQuery() { + @Override + protected String query() { + return "SELECT * FROM `" + TABLE + "` WHERE `" + ITEM_ID + + "` = ?"; + } + + @Override + protected void parametize(PreparedStatement st) throws SQLException { + st.setInt(1, id.getID()); + } + + @Override + protected Mapper mapper() { + return new CharacterMapper(); + } + }); + } + + @Override + public int loadInventory(final L2Character character) { + final CharacterInventory inventory = character.getInventory(); + final List items = database.query(new SelectListQuery() { + @Override + protected String query() { + return "SELECT * FROM `" + TABLE + "` WHERE `" + CHAR_ID + + "` = ?"; + } + + @Override + protected void parametize(PreparedStatement st) throws SQLException { + st.setInt(1, character.getID().getID()); + } + + @Override + protected Mapper mapper() { + return new CharacterMapper(); + } + }); + inventory.load(items); + return items.size(); + } + + @Override + public List listIDs() { + return database.query(new SelectListQuery() { + @Override + protected String query() { + return "SELECT `" + CHAR_ID + "` FROM `" + TABLE + "`"; + } + + @Override + protected Mapper mapper() { + return new Mapper() { + @Override + public ItemID map(ResultSet rs) throws SQLException { + return idFactory.createID(rs.getInt(CHAR_ID)); + } + }; + } + }); + } + + @Override + public boolean save(Item item) { + throw new UnsupportedOperationException( + "Saving items is not yet implemented!"); + } +} diff --git a/src/main/java/com/l2jserver/game/net/Lineage2Connection.java b/src/main/java/com/l2jserver/game/net/Lineage2Connection.java index 9dcc3e67c..a196ed7ec 100644 --- a/src/main/java/com/l2jserver/game/net/Lineage2Connection.java +++ b/src/main/java/com/l2jserver/game/net/Lineage2Connection.java @@ -6,14 +6,44 @@ import org.jboss.netty.channel.ChannelFuture; import com.l2jserver.game.net.codec.Lineage2Decrypter; import com.l2jserver.game.net.codec.Lineage2Encrypter; import com.l2jserver.game.net.packet.ServerPacket; +import com.l2jserver.model.world.L2Character; +/** + * This object connects the model (structure objects normally stored in the + * database) to the controller (protocol stuff). + * + * @author Rogiel + */ public class Lineage2Connection { private final Channel channel; + private L2Character character; public Lineage2Connection(Channel channel) { this.channel = channel; } + /** + * @return the character + */ + public boolean hasCharacter() { + return character != null; + } + + /** + * @return the character + */ + public L2Character getCharacter() { + return character; + } + + /** + * @param character + * the character to set + */ + public void setCharacter(L2Character character) { + this.character = character; + } + public Channel getChannel() { return channel; } diff --git a/src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java b/src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java index 84162b2c5..2f77ac77e 100644 --- a/src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java +++ b/src/main/java/com/l2jserver/game/net/packet/server/CharSelectionInfoPacket.java @@ -3,6 +3,7 @@ package com.l2jserver.game.net.packet.server; import org.jboss.netty.buffer.ChannelBuffer; import com.l2jserver.game.net.packet.AbstractServerPacket; +import com.l2jserver.model.world.L2Character; public class CharSelectionInfoPacket extends AbstractServerPacket { public static final int OPCODE = 0x09; @@ -10,10 +11,10 @@ public class CharSelectionInfoPacket extends AbstractServerPacket { private final String loginName; private final int sessionId; private final int activeId; - private final Character[] characters; + private final L2Character[] characters; public CharSelectionInfoPacket(int opcode, String loginName, int sessionId, - int activeId, Character... characters) { + int activeId, L2Character... characters) { super(opcode); this.loginName = loginName; this.sessionId = sessionId; diff --git a/src/main/java/com/l2jserver/model/id/CharacterID.java b/src/main/java/com/l2jserver/model/id/CharacterID.java index 5f9a20d5e..4264f2f8f 100644 --- a/src/main/java/com/l2jserver/model/id/CharacterID.java +++ b/src/main/java/com/l2jserver/model/id/CharacterID.java @@ -1,5 +1,24 @@ package com.l2jserver.model.id; -public interface CharacterID extends ObjectID { +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.l2jserver.db.dao.CharacterDAO; +import com.l2jserver.model.world.L2Character; +public final class CharacterID extends ObjectID { + /** + * Data Access Object (DAO) for characters + */ + private final CharacterDAO characterDao; + + @Inject + public CharacterID(@Assisted int id, CharacterDAO characterDao) { + super(id); + this.characterDao = characterDao; + } + + @Override + public L2Character getObject() { + return characterDao.load(this); + } } diff --git a/src/main/java/com/l2jserver/model/id/ClanID.java b/src/main/java/com/l2jserver/model/id/ClanID.java new file mode 100644 index 000000000..f164a179d --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/ClanID.java @@ -0,0 +1,23 @@ +package com.l2jserver.model.id; + +import com.google.inject.Inject; +import com.l2jserver.db.dao.ClanDAO; +import com.l2jserver.model.world.Clan; + +public final class ClanID extends ObjectID { + /** + * Data Access Object (DAO) for clans + */ + private final ClanDAO clanDao; + + @Inject + protected ClanID(int id, ClanDAO clanDao) { + super(id); + this.clanDao = clanDao; + } + + @Override + public Clan getObject() { + return clanDao.load(this); + } +} diff --git a/src/main/java/com/l2jserver/model/id/ID.java b/src/main/java/com/l2jserver/model/id/ID.java index 9deba53f9..808cacd31 100644 --- a/src/main/java/com/l2jserver/model/id/ID.java +++ b/src/main/java/com/l2jserver/model/id/ID.java @@ -1,5 +1,55 @@ package com.l2jserver.model.id; -public interface ID { +import com.google.inject.Inject; +/** + * The ID interface. Each Object or Template must be represented by an unique + * ID. + * + * @author Rogiel + */ +public abstract class ID { + /** + * The id itself + */ + protected final int id; + + @Inject + protected ID(int id) { + this.id = id; + } + + /** + * @return the id + */ + public int getID() { + return id; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + " [id=" + id + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ID other = (ID) obj; + if (id != other.id) + return false; + return true; + } } diff --git a/src/main/java/com/l2jserver/model/id/ItemID.java b/src/main/java/com/l2jserver/model/id/ItemID.java new file mode 100644 index 000000000..cf31e579f --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/ItemID.java @@ -0,0 +1,24 @@ +package com.l2jserver.model.id; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.l2jserver.db.dao.ItemDAO; +import com.l2jserver.model.world.Item; + +public final class ItemID extends ObjectID { + /** + * Data Access Object (DAO) for items + */ + private final ItemDAO itemDao; + + @Inject + protected ItemID(@Assisted int id, ItemDAO itemDao) { + super(id); + this.itemDao = itemDao; + } + + @Override + public Item getObject() { + return itemDao.load(this); + } +} diff --git a/src/main/java/com/l2jserver/model/id/ObjectID.java b/src/main/java/com/l2jserver/model/id/ObjectID.java index 9b04b7dca..73149e7e1 100644 --- a/src/main/java/com/l2jserver/model/id/ObjectID.java +++ b/src/main/java/com/l2jserver/model/id/ObjectID.java @@ -1,5 +1,23 @@ package com.l2jserver.model.id; -public interface ObjectID extends ID { +import com.l2jserver.model.id.factory.IDFactory; +import com.l2jserver.model.world.WorldObject; +/** + * {@link ObjectID}s cannot be instantiated directly. This must be done through + * an {@link IDFactory}. The {@link ObjectID} provides a facility + * {@link #getObject() method} that allows easily fetch this object from + * database without the need to directly use DAOs. + * + * @author Rogiel + * + * @param + * the {@link WorldObject} type + */ +public abstract class ObjectID extends ID { + protected ObjectID(int id) { + super(id); + } + + public abstract T getObject(); } diff --git a/src/main/java/com/l2jserver/model/id/PetID.java b/src/main/java/com/l2jserver/model/id/PetID.java new file mode 100644 index 000000000..0d04e3ba1 --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/PetID.java @@ -0,0 +1,23 @@ +package com.l2jserver.model.id; + +import com.google.inject.Inject; +import com.l2jserver.db.dao.PetDAO; +import com.l2jserver.model.world.Pet; + +public final class PetID extends ObjectID { + /** + * Data Access Object (DAO) for pets + */ + private final PetDAO petDao; + + @Inject + protected PetID(int id, PetDAO petDao) { + super(id); + this.petDao = petDao; + } + + @Override + public Pet getObject() { + return petDao.load(this); + } +} diff --git a/src/main/java/com/l2jserver/model/id/SimpleID.java b/src/main/java/com/l2jserver/model/id/SimpleID.java deleted file mode 100644 index 84f13c087..000000000 --- a/src/main/java/com/l2jserver/model/id/SimpleID.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.l2jserver.model.id; - -public class SimpleID implements ID { - -} diff --git a/src/main/java/com/l2jserver/model/id/TemplateID.java b/src/main/java/com/l2jserver/model/id/TemplateID.java index 49cd4a865..01a878989 100644 --- a/src/main/java/com/l2jserver/model/id/TemplateID.java +++ b/src/main/java/com/l2jserver/model/id/TemplateID.java @@ -1,5 +1,14 @@ package com.l2jserver.model.id; -public interface TemplateID extends ID { - +/** + * Templates IDs, different from {@link ObjectID}s, can be repeated and are + * defined in the template class. + * + * @author Rogiel + * + */ +public final class TemplateID extends ID { + public TemplateID(int id) { + super(id); + } } diff --git a/src/main/java/com/l2jserver/model/id/allocator/BitSetIDAllocator.java b/src/main/java/com/l2jserver/model/id/allocator/BitSetIDAllocator.java new file mode 100644 index 000000000..3647f2d41 --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/allocator/BitSetIDAllocator.java @@ -0,0 +1,114 @@ +package com.l2jserver.model.id.allocator; + +import java.util.BitSet; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import com.l2jserver.util.PrimeFinder; + +public class BitSetIDAllocator implements IDAllocator { + /** + * Lock to guarantee synchronization + */ + private Lock lock = new ReentrantLock(); + + /** + * Available IDs + */ + private BitSet ids = new BitSet(); + /** + * Amount of free ids + */ + private AtomicInteger freeIdCount = new AtomicInteger(); + /** + * Next free ID + */ + private AtomicInteger nextId = new AtomicInteger(); + + public void init() { + ids = new BitSet(PrimeFinder.nextPrime(100000)); + ids.clear(); + freeIdCount = new AtomicInteger(ALLOCABLE_IDS); + + nextId = new AtomicInteger(ids.nextClearBit(0)); + } + + @Override + public void allocate(int id) { + if (ids.get(id - FIRST_ID)) + throw new IDAllocatorException("ID not allocated"); + lock.lock(); + try { + if (id < FIRST_ID) + return; + ids.set(id - FIRST_ID); + nextId = new AtomicInteger(ids.nextClearBit(0)); + } finally { + lock.unlock(); + } + } + + @Override + public int allocate() { + lock.lock(); + try { + final int newID = nextId.get(); + ids.set(newID); + freeIdCount.decrementAndGet(); + + int nextFree = ids.nextClearBit(newID); + + if (nextFree < 0) { + nextFree = ids.nextClearBit(0); + } + if (nextFree < 0) { + if (ids.size() < ALLOCABLE_IDS) { + increaseBitSetCapacity(); + } else { + throw new IDAllocatorException("ID exhaustion"); + } + } + + nextId.set(nextFree); + + return newID + FIRST_ID; + } finally { + lock.unlock(); + } + } + + @Override + public void release(int id) { + if (id < FIRST_ID) + throw new IDAllocatorException( + "Can't release ID, smaller then initial ID"); + if (!ids.get(id - FIRST_ID)) + throw new IDAllocatorException("ID not allocated"); + + lock.lock(); + try { + ids.clear(id - FIRST_ID); + freeIdCount.incrementAndGet(); + } finally { + lock.unlock(); + } + } + + private void increaseBitSetCapacity() { + BitSet newBitSet = new BitSet( + PrimeFinder.nextPrime((getAllocatedIDs() * 11) / 10)); + newBitSet.or(ids); + ids = newBitSet; + } + + @Override + public int getAllocatedIDs() { + return ALLOCABLE_IDS - getFreeIDs(); + } + + @Override + public int getFreeIDs() { + return freeIdCount.get(); + } +} diff --git a/src/main/java/com/l2jserver/model/id/allocator/IDAllocator.java b/src/main/java/com/l2jserver/model/id/allocator/IDAllocator.java new file mode 100644 index 000000000..c6a056b7b --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/allocator/IDAllocator.java @@ -0,0 +1,59 @@ +package com.l2jserver.model.id.allocator; + +/** + * The ID allocator is used to alloc new ID and to release IDs that aren't used + * anymore. + * + * @author Rogiel + */ +public interface IDAllocator { + /** + * The first ID ever allocated + */ + public final static int FIRST_ID = 0x10000000; + /** + * The last ID ever allocated + */ + public final static int LAST_ID = 0x7FFFFFFF; + /** + * Total of available IDs for allocation + */ + public final static int ALLOCABLE_IDS = LAST_ID - FIRST_ID; + + /** + * This is method is used to register IDs as used at startup time. + * + * @param id + * the id + */ + void allocate(int id); + + /** + * Allocates a new ID + * + * @return the allocated ID value + */ + int allocate(); + + /** + * Release an ID + * + * @param id + * the id + */ + void release(int id); + + /** + * Get the amount of already allocated IDs + * + * @return allocated ids count + */ + int getAllocatedIDs(); + + /** + * Get the amount of IDs remaining to be allocated + * + * @return free ids count + */ + int getFreeIDs(); +} diff --git a/src/main/java/com/l2jserver/model/id/allocator/IDAllocatorException.java b/src/main/java/com/l2jserver/model/id/allocator/IDAllocatorException.java new file mode 100644 index 000000000..7bf75b03e --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/allocator/IDAllocatorException.java @@ -0,0 +1,21 @@ +package com.l2jserver.model.id.allocator; + +public class IDAllocatorException extends RuntimeException { + private static final long serialVersionUID = 111195059766878062L; + + public IDAllocatorException() { + super(); + } + + public IDAllocatorException(String message, Throwable cause) { + super(message, cause); + } + + public IDAllocatorException(String message) { + super(message); + } + + public IDAllocatorException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/l2jserver/model/id/factory/CharacterIDFactory.java b/src/main/java/com/l2jserver/model/id/factory/CharacterIDFactory.java new file mode 100644 index 000000000..c52253c7d --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/factory/CharacterIDFactory.java @@ -0,0 +1,62 @@ +package com.l2jserver.model.id.factory; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.id.allocator.IDAllocator; + +/** + * {@link IDFactory} for {@link CharacterID}. + * + * @author Rogiel + */ +public class CharacterIDFactory implements ObjectIDFactory { + /** + * The ID allocator + */ + private final IDAllocator allocator; + /** + * The Guice Factory + */ + private final CharacterIDGuiceFactory factory; + + @Inject + public CharacterIDFactory(IDAllocator allocator, + CharacterIDGuiceFactory factory) { + super(); + this.allocator = allocator; + this.factory = factory; + } + + @Override + public CharacterID createID() { + return createID(allocator.allocate()); + } + + @Override + public CharacterID createID(int id) { + return factory.create(id); + } + + @Override + public void destroy(CharacterID id) { + allocator.release(id.getID()); + } + + /** + * This is an Google Guice factory. Assistect Inject extension will + * automatically implement it and create the injected instances. + * + * @author Rogiel + */ + public interface CharacterIDGuiceFactory { + /** + * Creates a new ID instance + * + * @param id + * the numeric ID + * @return the new ID created by injection + */ + public CharacterID create(@Assisted int id); + } +} diff --git a/src/main/java/com/l2jserver/model/id/factory/ClanIDFactory.java b/src/main/java/com/l2jserver/model/id/factory/ClanIDFactory.java new file mode 100644 index 000000000..d18676b0b --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/factory/ClanIDFactory.java @@ -0,0 +1,61 @@ +package com.l2jserver.model.id.factory; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.l2jserver.model.id.ClanID; +import com.l2jserver.model.id.allocator.IDAllocator; + +/** + * {@link IDFactory} for {@link ClanID}. + * + * @author Rogiel + */ +public class ClanIDFactory implements ObjectIDFactory { + /** + * The ID allocator + */ + private final IDAllocator allocator; + /** + * The Guice factory + */ + private final ClanIDGuiceFactory factory; + + @Inject + public ClanIDFactory(IDAllocator allocator, ClanIDGuiceFactory factory) { + super(); + this.allocator = allocator; + this.factory = factory; + } + + @Override + public ClanID createID() { + return createID(allocator.allocate()); + } + + @Override + public ClanID createID(int id) { + return factory.create(id); + } + + @Override + public void destroy(ClanID id) { + allocator.release(id.getID()); + } + + /** + * This is an Google Guice factory. Assistect Inject extension will + * automatically implement it and create the injected instances. + * + * @author Rogiel + */ + public interface ClanIDGuiceFactory { + /** + * Creates a new ID instance + * + * @param id + * the numeric ID + * @return the new ID created by injection + */ + public ClanID create(@Assisted int id); + } +} diff --git a/src/main/java/com/l2jserver/model/id/factory/IDFactory.java b/src/main/java/com/l2jserver/model/id/factory/IDFactory.java new file mode 100644 index 000000000..f39dc24de --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/factory/IDFactory.java @@ -0,0 +1,34 @@ +package com.l2jserver.model.id.factory; + +import com.l2jserver.model.id.ID; + +/** + * The ID factory is used to create instances of IDs. It will automatically make + * sure the ID is free before allocating it. + * + * @author Rogiel + */ +public interface IDFactory { + /** + * Generated a new ID + * + * @return the new ID + */ + T createID(); + + /** + * Creates the ID object for an EXISTING ID. + * + * @param id + * @return + */ + T createID(int id); + + /** + * Destroy this ID. Releases this value to be used once again. + * + * @param id + * the id to be destroyed. + */ + void destroy(T id); +} diff --git a/src/main/java/com/l2jserver/model/id/factory/IDFactoryModule.java b/src/main/java/com/l2jserver/model/id/factory/IDFactoryModule.java new file mode 100644 index 000000000..7cdb922dc --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/factory/IDFactoryModule.java @@ -0,0 +1,29 @@ +package com.l2jserver.model.id.factory; + +import com.google.inject.AbstractModule; +import com.google.inject.Scopes; +import com.google.inject.assistedinject.FactoryModuleBuilder; +import com.l2jserver.model.id.allocator.BitSetIDAllocator; +import com.l2jserver.model.id.allocator.IDAllocator; +import com.l2jserver.model.id.factory.CharacterIDFactory.CharacterIDGuiceFactory; +import com.l2jserver.model.id.factory.ItemIDFactory.ItemIDGuiceFactory; + +public class IDFactoryModule extends AbstractModule { + @Override + protected void configure() { + bind(IDAllocator.class).to(BitSetIDAllocator.class) + .in(Scopes.SINGLETON); + + bind(CharacterIDFactory.class).in(Scopes.SINGLETON); + install(new FactoryModuleBuilder().build(CharacterIDGuiceFactory.class)); + + bind(ItemIDFactory.class).in(Scopes.SINGLETON); + install(new FactoryModuleBuilder().build(ItemIDGuiceFactory.class)); + + // bind(ClanIDFactory.class).in(Scopes.SINGLETON); + // install(new FactoryModuleBuilder().build(ClanIDGuiceFactory.class)); + // + // bind(PetIDFactory.class).in(Scopes.SINGLETON); + // install(new FactoryModuleBuilder().build(PetIDGuiceFactory.class)); + } +} diff --git a/src/main/java/com/l2jserver/model/id/factory/ItemIDFactory.java b/src/main/java/com/l2jserver/model/id/factory/ItemIDFactory.java new file mode 100644 index 000000000..9b00413e8 --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/factory/ItemIDFactory.java @@ -0,0 +1,61 @@ +package com.l2jserver.model.id.factory; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.l2jserver.model.id.ItemID; +import com.l2jserver.model.id.allocator.IDAllocator; + +/** + * {@link IDFactory} for {@link ItemID}. + * + * @author Rogiel + */ +public class ItemIDFactory implements ObjectIDFactory { + /** + * The ID allocator + */ + private final IDAllocator allocator; + /** + * The Guice factory + */ + private final ItemIDGuiceFactory factory; + + @Inject + public ItemIDFactory(IDAllocator allocator, ItemIDGuiceFactory factory) { + super(); + this.allocator = allocator; + this.factory = factory; + } + + @Override + public ItemID createID() { + return createID(allocator.allocate()); + } + + @Override + public ItemID createID(int id) { + return factory.create(id); + } + + @Override + public void destroy(ItemID id) { + allocator.release(id.getID()); + } + + /** + * This is an Google Guice factory. Assistect Inject extension will + * automatically implement it and create the injected instances. + * + * @author Rogiel + */ + public interface ItemIDGuiceFactory { + /** + * Creates a new ID instance + * + * @param id + * the numeric ID + * @return the new ID created by injection + */ + public ItemID create(@Assisted int id); + } +} diff --git a/src/main/java/com/l2jserver/model/id/factory/ObjectIDFactory.java b/src/main/java/com/l2jserver/model/id/factory/ObjectIDFactory.java new file mode 100644 index 000000000..bcac1248e --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/factory/ObjectIDFactory.java @@ -0,0 +1,6 @@ +package com.l2jserver.model.id.factory; + +import com.l2jserver.model.id.ObjectID; + +public interface ObjectIDFactory> extends IDFactory { +} diff --git a/src/main/java/com/l2jserver/model/id/factory/PetIDFactory.java b/src/main/java/com/l2jserver/model/id/factory/PetIDFactory.java new file mode 100644 index 000000000..bcdbaa5f8 --- /dev/null +++ b/src/main/java/com/l2jserver/model/id/factory/PetIDFactory.java @@ -0,0 +1,61 @@ +package com.l2jserver.model.id.factory; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.l2jserver.model.id.PetID; +import com.l2jserver.model.id.allocator.IDAllocator; + +/** + * {@link IDFactory} for {@link PetID}. + * + * @author Rogiel + */ +public class PetIDFactory implements ObjectIDFactory { + /** + * The ID allocator + */ + private final IDAllocator allocator; + /** + * The Guice factory + */ + private final PetIDGuiceFactory factory; + + @Inject + public PetIDFactory(IDAllocator allocator, PetIDGuiceFactory factory) { + super(); + this.allocator = allocator; + this.factory = factory; + } + + @Override + public PetID createID() { + return createID(allocator.allocate()); + } + + @Override + public PetID createID(int id) { + return factory.create(id); + } + + @Override + public void destroy(PetID id) { + allocator.release(id.getID()); + } + + /** + * This is an Google Guice factory. Assistect Inject extension will + * automatically implement it and create the injected instances. + * + * @author Rogiel + */ + public interface PetIDGuiceFactory { + /** + * Creates a new ID instance + * + * @param id + * the numeric ID + * @return the new ID created by injection + */ + public PetID create(@Assisted int id); + } +} diff --git a/src/main/java/com/l2jserver/model/template/capability/Attackable.java b/src/main/java/com/l2jserver/model/template/capability/Attackable.java index 36c381ec3..341a3d80e 100644 --- a/src/main/java/com/l2jserver/model/template/capability/Attackable.java +++ b/src/main/java/com/l2jserver/model/template/capability/Attackable.java @@ -5,7 +5,8 @@ import com.l2jserver.model.world.capability.Attacker; public interface Attackable extends TemplateCapability { void attack(Attacker source, com.l2jserver.model.world.capability.Attackable target); - - public int getPhysicalDamage(); - public int getMagicalDamage(); + + int getPhysicalDamage(); + + int getMagicalDamage(); } diff --git a/src/main/java/com/l2jserver/model/template/capability/Defendable.java b/src/main/java/com/l2jserver/model/template/capability/Defendable.java index 8ab0ac43c..61271f844 100644 --- a/src/main/java/com/l2jserver/model/template/capability/Defendable.java +++ b/src/main/java/com/l2jserver/model/template/capability/Defendable.java @@ -5,7 +5,8 @@ import com.l2jserver.model.world.capability.Attacker; public interface Defendable extends TemplateCapability { void defend(Attacker source, com.l2jserver.model.world.capability.Attackable target); - - public int getPhysicalDefense(); - public int getMagicalDefense(); + + int getPhysicalDefense(); + + int getMagicalDefense(); } diff --git a/src/main/java/com/l2jserver/model/world/AbstractActor.java b/src/main/java/com/l2jserver/model/world/AbstractActor.java index 22478bd17..356db6628 100644 --- a/src/main/java/com/l2jserver/model/world/AbstractActor.java +++ b/src/main/java/com/l2jserver/model/world/AbstractActor.java @@ -4,7 +4,6 @@ import java.util.List; import com.l2jserver.model.template.SkillTemplate; import com.l2jserver.model.template.capability.Attackable; -import com.l2jserver.model.world.actor.ActorEvent; import com.l2jserver.model.world.actor.ActorListener; import com.l2jserver.model.world.capability.Actor; import com.l2jserver.model.world.capability.Attacker; @@ -124,21 +123,4 @@ public abstract class AbstractActor extends AbstractObject implements Actor { public void equip(Equiper equiper) { // TODO } - - @Override - public void addListener(ActorListener listener) { - listeners.add(listener); - } - - @Override - public void removeListener(ActorListener listener) { - listeners.remove(listener); - } - - @Override - public void dispatch(ActorEvent e) { - for (final ActorListener listener : listeners) { - listener.dispatch(e); - } - } } diff --git a/src/main/java/com/l2jserver/model/world/AbstractObject.java b/src/main/java/com/l2jserver/model/world/AbstractObject.java index 51e3b4372..b8f451448 100644 --- a/src/main/java/com/l2jserver/model/world/AbstractObject.java +++ b/src/main/java/com/l2jserver/model/world/AbstractObject.java @@ -8,13 +8,15 @@ import com.l2jserver.model.id.ObjectID; * @author Rogiel */ public abstract class AbstractObject implements WorldObject { - protected ObjectID id; + protected ObjectID id; - public ObjectID getId() { + public ObjectID getID() { return id; } - public void setId(ObjectID id) { + public void setID(ObjectID id) { + if (this.id != null) + throw new IllegalStateException("ID is already set!"); this.id = id; } diff --git a/src/main/java/com/l2jserver/model/world/Clan.java b/src/main/java/com/l2jserver/model/world/Clan.java new file mode 100644 index 000000000..9b4865110 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/Clan.java @@ -0,0 +1,71 @@ +package com.l2jserver.model.world; + +import java.util.List; + +import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.id.ClanID; +import com.l2jserver.model.world.capability.Joinable; +import com.l2jserver.model.world.capability.Listenable; +import com.l2jserver.model.world.clan.ClanEvent; +import com.l2jserver.model.world.clan.ClanListener; +import com.l2jserver.model.world.clan.ClanMembers; +import com.l2jserver.util.factory.CollectionFactory; + +public class Clan extends AbstractObject implements + Listenable, Joinable { + /** + * This clan listeners + */ + private final List listeners = CollectionFactory + .newList(ClanListener.class); + + /** + * Clan leader + */ + private CharacterID leaderID; + + /** + * Members in the clan + */ + private final ClanMembers members = new ClanMembers(this); + + /** + * Remember to save your clan! + */ + @Override + public void join(L2Character member) { + members.add(member); + } + + @Override + public void leave(L2Character member) { + members.remove(member); + } + + /** + * @return the leaderID + */ + public CharacterID getLeaderID() { + return leaderID; + } + + /** + * @return the leader + */ + public L2Character getLeader() { + return leaderID.getObject(); + } + + /** + * @param leaderID + * the leaderID to set + */ + public void setLeaderID(CharacterID leaderID) { + this.leaderID = leaderID; + } + + @Override + public ClanID getID() { + return (ClanID) super.getID(); + } +} diff --git a/src/main/java/com/l2jserver/model/world/Item.java b/src/main/java/com/l2jserver/model/world/Item.java index 89e4256fb..cc2b03924 100644 --- a/src/main/java/com/l2jserver/model/world/Item.java +++ b/src/main/java/com/l2jserver/model/world/Item.java @@ -2,7 +2,7 @@ package com.l2jserver.model.world; import java.util.List; -import com.l2jserver.model.world.capability.Child; +import com.l2jserver.model.id.CharacterID; import com.l2jserver.model.world.capability.Listenable; import com.l2jserver.model.world.capability.Playable; import com.l2jserver.model.world.capability.Spawnable; @@ -12,43 +12,23 @@ import com.l2jserver.util.Coordinate; import com.l2jserver.util.factory.CollectionFactory; public class Item extends AbstractObject implements Playable, Spawnable, - Child, Listenable { + Listenable { private final List listeners = CollectionFactory .newList(ItemListener.class); + private CharacterID ownerID; + @Override public void spawn(Coordinate coordinate) { } - @Override - public void addListener(ItemListener listener) { - listeners.add(listener); - } - - @Override - public void removeListener(ItemListener listener) { - listeners.remove(listener); - } - - @Override - public void dispatch(ItemEvent e) { - for (final ItemListener listener : listeners) { - listener.dispatch(e); - } - } - @Override public boolean isSpawned() { // TODO Auto-generated method stub return false; } - @Override - public Player getParent() { - return null; - } - @Override public Coordinate getPosition() { // TODO Auto-generated method stub @@ -57,6 +37,21 @@ public class Item extends AbstractObject implements Playable, Spawnable, @Override public void setPosition(Coordinate coord) { - + + } + + /** + * @return the ownerID + */ + public CharacterID getOwnerID() { + return ownerID; + } + + /** + * @param ownerID + * the ownerID to set + */ + public void setOwnerID(CharacterID ownerID) { + this.ownerID = ownerID; } } diff --git a/src/main/java/com/l2jserver/model/world/L2Character.java b/src/main/java/com/l2jserver/model/world/L2Character.java index 71d0769b3..6fdbb01d3 100644 --- a/src/main/java/com/l2jserver/model/world/L2Character.java +++ b/src/main/java/com/l2jserver/model/world/L2Character.java @@ -1,10 +1,137 @@ package com.l2jserver.model.world; import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.id.ClanID; +import com.l2jserver.model.id.PetID; +import com.l2jserver.model.world.character.CharacterAppearance; +import com.l2jserver.model.world.character.CharacterInventory; +/** + * This class represents a playable character in Lineage II world. + * + * @author Rogiel + */ public class L2Character extends Player { + /** + * The clan id + */ + private ClanID clanID; + /** + * The pet id + */ + private PetID petID; + /** + * The character name + */ + private String name; + /** + * The character's status + */ + private boolean online; + + /** + * This character's inventory + */ + private final CharacterInventory inventory = new CharacterInventory(this); + /** + * The appearance of this character + */ + private final CharacterAppearance appearance = new CharacterAppearance(this); + @Override - public CharacterID getId() { - return (CharacterID) super.getId(); + public CharacterID getID() { + return (CharacterID) super.getID(); + } + + /** + * @return the clanID + */ + public ClanID getClanID() { + return clanID; + } + + /** + * @return the clan + */ + public Clan getClan() { + if (clanID == null) + return null; + return clanID.getObject(); + } + + /** + * @param clanID + * the clanID to set + */ + public void setClanID(ClanID clanID) { + this.clanID = clanID; + } + + /** + * @return the petID + */ + public PetID getPetID() { + return petID; + } + + /** + * @return the pet + */ + public Pet getPet() { + if (petID == null) + return null; + return petID.getObject(); + } + + /** + * @param petID + * the petID to set + */ + public void setPetID(PetID petID) { + this.petID = petID; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the online + */ + public boolean isOnline() { + return online; + } + + /** + * @param online + * the online to set + */ + public void setOnline(boolean online) { + this.online = online; + } + + /** + * @return the inventory + */ + public CharacterInventory getInventory() { + return inventory; + } + + /** + * @return the appearance + */ + public CharacterAppearance getAppearance() { + return appearance; } } diff --git a/src/main/java/com/l2jserver/model/world/Party.java b/src/main/java/com/l2jserver/model/world/Party.java new file mode 100644 index 000000000..2f5195e80 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/Party.java @@ -0,0 +1,36 @@ +package com.l2jserver.model.world; + +import java.util.List; + +import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.id.ClanID; +import com.l2jserver.model.world.capability.Joinable; +import com.l2jserver.model.world.capability.Listenable; +import com.l2jserver.model.world.party.PartyEvent; +import com.l2jserver.model.world.party.PartyListener; +import com.l2jserver.util.factory.CollectionFactory; + +public class Party extends AbstractObject implements + Listenable, Joinable { + private final List listeners = CollectionFactory + .newList(PartyListener.class); + + private final List members = CollectionFactory + .newList(CharacterID.class); + + @Override + public void join(L2Character member) { + members.add(member.getID()); + } + + @Override + public ClanID getID() { + return (ClanID) super.getID(); + } + + @Override + public void leave(L2Character member) { + // TODO Auto-generated method stub + + } +} diff --git a/src/main/java/com/l2jserver/model/world/Pet.java b/src/main/java/com/l2jserver/model/world/Pet.java index eacef9580..89593e98b 100644 --- a/src/main/java/com/l2jserver/model/world/Pet.java +++ b/src/main/java/com/l2jserver/model/world/Pet.java @@ -1,25 +1,22 @@ package com.l2jserver.model.world; -import com.l2jserver.model.world.capability.Child; +import com.l2jserver.model.id.CharacterID; import com.l2jserver.model.world.capability.Summonable; import com.l2jserver.util.Coordinate; -public class Pet extends Player implements Child, Summonable { - @Override - public L2Character getParent() { - return null; - } +public class Pet extends Player implements Summonable { + private CharacterID ownerID; @Override public void teleport(Coordinate coordinate) { // TODO Auto-generated method stub - + } @Override public void summon(Coordinate coordinate) { // TODO Auto-generated method stub - + } @Override @@ -27,4 +24,26 @@ public class Pet extends Player implements Child, Summonable { // TODO Auto-generated method stub return false; } + + /** + * @return the ownerID + */ + public CharacterID getOwnerID() { + return ownerID; + } + + /** + * @return the owner + */ + public L2Character getOwner() { + return ownerID.getObject(); + } + + /** + * @param ownerID + * the ownerID to set + */ + public void setOwnerID(CharacterID ownerID) { + this.ownerID = ownerID; + } } diff --git a/src/main/java/com/l2jserver/model/world/Player.java b/src/main/java/com/l2jserver/model/world/Player.java index a10d5232e..a98e03b14 100644 --- a/src/main/java/com/l2jserver/model/world/Player.java +++ b/src/main/java/com/l2jserver/model/world/Player.java @@ -1,8 +1,6 @@ package com.l2jserver.model.world; -import com.l2jserver.game.net.Lineage2Connection; import com.l2jserver.model.world.capability.Actor; -import com.l2jserver.model.world.capability.Parent; import com.l2jserver.model.world.capability.Playable; import com.l2jserver.model.world.capability.Teleportable; import com.l2jserver.model.world.player.PlayerTeleportEvent; @@ -15,28 +13,12 @@ import com.l2jserver.util.Coordinate; * @author Rogiel */ public abstract class Player extends AbstractActor implements Playable, Actor, - Teleportable, Parent { - protected Lineage2Connection connection; - + Teleportable { @Override public void teleport(Coordinate coordinate) { - final PlayerTeleportEvent event = new PlayerTeleportEvent(this, coordinate); + final PlayerTeleportEvent event = new PlayerTeleportEvent(this, + coordinate); this.setPosition(coordinate); - event.dispatch(); - } - - /** - * @return the connection - */ - public Lineage2Connection getConnection() { - return connection; - } - - /** - * @param connection - * the connection to set - */ - public void setConnection(Lineage2Connection connection) { - this.connection = connection; + // event.dispatch(); } } diff --git a/src/main/java/com/l2jserver/model/world/WorldObject.java b/src/main/java/com/l2jserver/model/world/WorldObject.java index 274eb5b2e..e541097b5 100644 --- a/src/main/java/com/l2jserver/model/world/WorldObject.java +++ b/src/main/java/com/l2jserver/model/world/WorldObject.java @@ -3,7 +3,21 @@ package com.l2jserver.model.world; import com.l2jserver.model.id.ObjectID; public interface WorldObject { - ObjectID getId(); + /** + * Get the object's ID + * + * @return the object id + */ + ObjectID getID(); - void setId(ObjectID id); + /** + * Set this object ID. Note that the ID can only be set once. Truing to + * change an ID will thrown an {@link IllegalStateException}. + * + * @param id + * the id + * @throws IllegalStateException + * if ID is already set + */ + void setID(ObjectID id) throws IllegalStateException; } diff --git a/src/main/java/com/l2jserver/model/world/capability/Child.java b/src/main/java/com/l2jserver/model/world/capability/Child.java deleted file mode 100644 index 30b7bed46..000000000 --- a/src/main/java/com/l2jserver/model/world/capability/Child.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.l2jserver.model.world.capability; - -import com.l2jserver.model.world.AbstractObject; - -/** - * Defines an {@link AbstractObject} that is a child of another - * {@link AbstractObject}. - * - * @author Rogiel - */ -public interface Child

extends ObjectCapability { - public P getParent(); -} diff --git a/src/main/java/com/l2jserver/model/world/capability/Joinable.java b/src/main/java/com/l2jserver/model/world/capability/Joinable.java new file mode 100644 index 000000000..64e30fcdb --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/capability/Joinable.java @@ -0,0 +1,26 @@ +package com.l2jserver.model.world.capability; + +import com.l2jserver.model.world.AbstractObject; + +/** + * Defines an {@link AbstractObject} that other objects can join to. + * + * @author Rogiel + */ +public interface Joinable extends ObjectCapability { + /** + * Join an member to this object. + * + * @param member + * the entering member + */ + void join(T member); + + /** + * Removes the joined member from this object + * + * @param member + * the exiting member + */ + void leave(T member); +} diff --git a/src/main/java/com/l2jserver/model/world/capability/Listenable.java b/src/main/java/com/l2jserver/model/world/capability/Listenable.java index 2fc667fcd..b98accbc2 100644 --- a/src/main/java/com/l2jserver/model/world/capability/Listenable.java +++ b/src/main/java/com/l2jserver/model/world/capability/Listenable.java @@ -17,27 +17,4 @@ import com.l2jserver.model.world.event.WorldListener; */ public interface Listenable, E extends WorldEvent> extends ObjectCapability { - /** - * Adds a new listener - * - * @param listener - * the listener - */ - void addListener(L listener); - - /** - * Removes an listener - * - * @param listener - * the listener - */ - void removeListener(L listener); - - /** - * Don't use this method directly. It is called by the event dispatcher. - * - * @param e - * the event - */ - void dispatch(E e); } diff --git a/src/main/java/com/l2jserver/model/world/capability/Parent.java b/src/main/java/com/l2jserver/model/world/capability/Parent.java deleted file mode 100644 index e201f3bd8..000000000 --- a/src/main/java/com/l2jserver/model/world/capability/Parent.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.l2jserver.model.world.capability; - -import com.l2jserver.model.world.AbstractObject; - -/** - * Defines an {@link AbstractObject} that is the parent of another - * {@link AbstractObject}. - * - * @author Rogiel - */ -public interface Parent extends ObjectCapability { -} diff --git a/src/main/java/com/l2jserver/model/world/character/CharacterAppearance.java b/src/main/java/com/l2jserver/model/world/character/CharacterAppearance.java new file mode 100644 index 000000000..e55786f5e --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/character/CharacterAppearance.java @@ -0,0 +1,290 @@ +package com.l2jserver.model.world.character; + +import com.l2jserver.model.world.L2Character; +import com.l2jserver.util.RGBColor; + +/** + * Defines how an character looks in-game. + * + * @author Rogiel + */ +public class CharacterAppearance { + /** + * The parent character + */ + private final L2Character character; + + /** + * The character face + */ + private CharacterFace face; + + /** + * Character possible faces + * + * @author Rogiel + */ + public enum CharacterFace { + FACE1((byte) 0x00), + + FACE2((byte) 0x01), + + FACE3((byte) 0x02), + + FACE4((byte) 0x03); + + public final byte option; + + CharacterFace(byte option) { + this.option = option; + } + + public static CharacterFace fromOption(byte option) { + for (CharacterFace face : values()) { + if (face.option == option) + return face; + } + return null; + } + } + + /** + * The character hair color + */ + private CharacterHairColor hairColor; + + /** + * Character possible hair colors + * + * @author Rogiel + */ + public enum CharacterHairColor { + COLOR1((byte) 0x00), + + COLOR2((byte) 0x01), + + COLOR3((byte) 0x02), + + COLOR4((byte) 0x03); + + public final byte option; + + CharacterHairColor(byte option) { + this.option = option; + } + + public static CharacterHairColor fromOption(byte option) { + for (CharacterHairColor color : values()) { + if (color.option == option) + return color; + } + return null; + } + } + + /** + * The character hair style + */ + private CharacterHairStyle hairStyle; + + /** + * Character possible hair styles + * + * @author Rogiel + */ + public enum CharacterHairStyle { + STYLE1((byte) 0x00), + + STYLE2((byte) 0x01), + + STYLE3((byte) 0x02), + + STYLE4((byte) 0x03); + + public final byte option; + + CharacterHairStyle(byte option) { + this.option = option; + } + + public static CharacterHairStyle fromOption(byte option) { + for (CharacterHairStyle style : values()) { + if (style.option == option) + return style; + } + return null; + } + } + + /** + * The character sex + */ + private CharacterSex sex; + + /** + * Represent the sex of an character. + *

+ * TODO this will be moved soon: not only characters have sex, NPC can + * have'em too. + * + * @author Rogiel + */ + public enum CharacterSex { + MALE, FEMALE; + } + + /** + * An alternative name. It will be displayed in-game. + *

+ * This is not persisted! + */ + private String alternativeName; + /** + * An alternative title. It will be displayed in-game. + *

+ * This is not persisted! + */ + private String alternativeTitle; + + /** + * The name color + */ + private RGBColor nameColor = new RGBColor((byte) 0xFF, (byte) 0xFF, + (byte) 0xFF); + /** + * The title color + */ + private RGBColor titleColor = new RGBColor((byte) 0xFF, (byte) 0xFF, + (byte) 0x77); + + public CharacterAppearance(L2Character character) { + this.character = character; + } + + /** + * @return the character face + */ + public CharacterFace getFace() { + return face; + } + + /** + * @param face + * the character face to set + */ + public void setFace(CharacterFace face) { + this.face = face; + } + + /** + * @return the hair color + */ + public CharacterHairColor getHairColor() { + return hairColor; + } + + /** + * @param hairColor + * the hair color to set + */ + public void setHairColor(CharacterHairColor hairColor) { + this.hairColor = hairColor; + } + + /** + * @return the hair style + */ + public CharacterHairStyle getHairStyle() { + return hairStyle; + } + + /** + * @param hairStyle + * the hair style to set + */ + public void setHairStyle(CharacterHairStyle hairStyle) { + this.hairStyle = hairStyle; + } + + /** + * @return the character sex + */ + public CharacterSex getSex() { + return sex; + } + + /** + * @param sex + * the character sex to set + */ + public void setSex(CharacterSex sex) { + this.sex = sex; + } + + /** + * @return the alternative name + */ + public String getAlternativeName() { + return alternativeName; + } + + /** + * @param alternativeName + * the alternative name to set + */ + public void setAlternativeName(String alternativeName) { + this.alternativeName = alternativeName; + } + + /** + * @return the alternative title + */ + public String getAlternativeTitle() { + return alternativeTitle; + } + + /** + * @param alternativeTitle + * the alternative title to set + */ + public void setAlternativeTitle(String alternativeTitle) { + this.alternativeTitle = alternativeTitle; + } + + /** + * @return the name color + */ + public RGBColor getNameColor() { + return nameColor; + } + + /** + * @param nameColor + * the name color to set + */ + public void setNameColor(RGBColor nameColor) { + this.nameColor = nameColor; + } + + /** + * @return the title color + */ + public RGBColor getTitleColor() { + return titleColor; + } + + /** + * @param titleColor + * the title color to set + */ + public void setTitleColor(RGBColor titleColor) { + this.titleColor = titleColor; + } + + /** + * @return the character + */ + public L2Character getCharacter() { + return character; + } +} diff --git a/src/main/java/com/l2jserver/model/world/character/CharacterFriendList.java b/src/main/java/com/l2jserver/model/world/character/CharacterFriendList.java new file mode 100644 index 000000000..f7e1f125a --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/character/CharacterFriendList.java @@ -0,0 +1,37 @@ +package com.l2jserver.model.world.character; + +import java.util.Iterator; +import java.util.Set; + +import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.util.factory.CollectionFactory; + +/** + * Defines how an character looks in-game. + * + * @author Rogiel + */ +public class CharacterFriendList implements Iterable { + private final L2Character character; + + private final Set friends = CollectionFactory + .newSet(CharacterID.class); + + public CharacterFriendList(L2Character character) { + this.character = character; + } + + /** + * @return the character + */ + public L2Character getCharacter() { + return character; + } + + @Override + public Iterator iterator() { + // TODO + return null; + } +} diff --git a/src/main/java/com/l2jserver/model/world/character/CharacterInventory.java b/src/main/java/com/l2jserver/model/world/character/CharacterInventory.java new file mode 100644 index 000000000..77b60c0b6 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/character/CharacterInventory.java @@ -0,0 +1,38 @@ +package com.l2jserver.model.world.character; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.l2jserver.model.world.Item; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.util.factory.CollectionFactory; + +public class CharacterInventory implements Iterable { + private final L2Character character; + + /** + * The items in this character inventory + */ + private final Set items = CollectionFactory.newSet(Item.class); + + public CharacterInventory(L2Character character) { + this.character = character; + } + + public void load(List items) { + items.addAll(items); + } + + /** + * @return the character + */ + public L2Character getCharacter() { + return character; + } + + @Override + public Iterator iterator() { + return items.iterator(); + } +} diff --git a/src/main/java/com/l2jserver/model/world/clan/ClanEvent.java b/src/main/java/com/l2jserver/model/world/clan/ClanEvent.java new file mode 100644 index 000000000..021326a1b --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/clan/ClanEvent.java @@ -0,0 +1,8 @@ +package com.l2jserver.model.world.clan; + +import com.l2jserver.model.world.Clan; +import com.l2jserver.model.world.event.WorldEvent; + +public interface ClanEvent extends WorldEvent { + Clan getClan(); +} diff --git a/src/main/java/com/l2jserver/model/world/clan/ClanListener.java b/src/main/java/com/l2jserver/model/world/clan/ClanListener.java new file mode 100644 index 000000000..1c753aff5 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/clan/ClanListener.java @@ -0,0 +1,6 @@ +package com.l2jserver.model.world.clan; + +import com.l2jserver.model.world.event.WorldListener; + +public interface ClanListener extends WorldListener { +} diff --git a/src/main/java/com/l2jserver/model/world/clan/ClanMembers.java b/src/main/java/com/l2jserver/model/world/clan/ClanMembers.java new file mode 100644 index 000000000..33b7e3b05 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/clan/ClanMembers.java @@ -0,0 +1,76 @@ +package com.l2jserver.model.world.clan; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.world.Clan; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.util.factory.CollectionFactory; + +/** + * This class handles members inside an clan + * + * @author Rogiel + */ +public class ClanMembers implements Iterable { + /** + * The parent {@link Clan} + */ + private final Clan clan; + + /** + * The list of active members + */ + private final Set members = CollectionFactory + .newSet(CharacterID.class); + + public ClanMembers(Clan clan) { + this.clan = clan; + } + + /** + * Effectively add this character as a clan member + * + * @param character + * the character + * @return true if add, false otherwise + */ + public boolean add(L2Character character) { + return members.add(character.getID()); + } + + /** + * Effectively add this character as a clan member + * + * @param character + * the character + * @return true if add, false otherwise + */ + public boolean remove(L2Character character) { + return members.remove(character.getID()); + } + + /** + * Load an list of members to this clan + * + * @param members + * the list of members ids + */ + public void load(List members) { + this.members.addAll(members); + } + + /** + * @return the clan + */ + public Clan getClan() { + return clan; + } + + @Override + public Iterator iterator() { + return members.iterator(); + } +} diff --git a/src/main/java/com/l2jserver/model/world/event/WorldEvent.java b/src/main/java/com/l2jserver/model/world/event/WorldEvent.java index 92e3412ff..e580ffd90 100644 --- a/src/main/java/com/l2jserver/model/world/event/WorldEvent.java +++ b/src/main/java/com/l2jserver/model/world/event/WorldEvent.java @@ -1,12 +1,10 @@ package com.l2jserver.model.world.event; import com.l2jserver.model.world.WorldObject; +import com.l2jserver.model.world.capability.Listenable; public interface WorldEvent { WorldObject getObject(); - /** - * Dispatch this event to all the objects - */ - void dispatch(); + Listenable[] getDispatchableObjects(); } diff --git a/src/main/java/com/l2jserver/model/world/event/WorldListener.java b/src/main/java/com/l2jserver/model/world/event/WorldListener.java index 61302deab..9545d469e 100644 --- a/src/main/java/com/l2jserver/model/world/event/WorldListener.java +++ b/src/main/java/com/l2jserver/model/world/event/WorldListener.java @@ -10,11 +10,13 @@ package com.l2jserver.model.world.event; */ public interface WorldListener { /** - * Once the event call is dispatched, the listener WILL NOT be - * removed. You must manually remove it from the event object. + * Once the event call is dispatched the listener WILL be removed if + * false is returned. If you wish to keep this listener, you must return + * true. * * @param e * the event + * @return true to keep listener alive */ - void dispatch(E e); + boolean dispatch(E e); } diff --git a/src/main/java/com/l2jserver/model/world/filter/impl/IDFilter.java b/src/main/java/com/l2jserver/model/world/filter/impl/IDFilter.java index 0293848e7..ca379cd02 100644 --- a/src/main/java/com/l2jserver/model/world/filter/impl/IDFilter.java +++ b/src/main/java/com/l2jserver/model/world/filter/impl/IDFilter.java @@ -15,6 +15,6 @@ public class IDFilter implements WorldObjectFilter { public boolean accept(Positionable other) { if (other == null) return false; - return other.getId().equals(id); + return other.getID().equals(id); } } diff --git a/src/main/java/com/l2jserver/model/world/item/ItemDropEvent.java b/src/main/java/com/l2jserver/model/world/item/ItemDropEvent.java index d9df73ff7..3d5b944f5 100644 --- a/src/main/java/com/l2jserver/model/world/item/ItemDropEvent.java +++ b/src/main/java/com/l2jserver/model/world/item/ItemDropEvent.java @@ -4,6 +4,7 @@ import com.l2jserver.model.world.Item; import com.l2jserver.model.world.Player; import com.l2jserver.model.world.WorldObject; import com.l2jserver.model.world.capability.Actor; +import com.l2jserver.model.world.capability.Listenable; import com.l2jserver.model.world.player.PlayerEvent; public class ItemDropEvent implements ItemEvent, PlayerEvent { @@ -30,15 +31,13 @@ public class ItemDropEvent implements ItemEvent, PlayerEvent { return item; } - @Override - public void dispatch() { - item.dispatch(this); - if (player != null) - player.dispatch(this); - } - @Override public Actor getActor() { return player; } + + @Override + public Listenable[] getDispatchableObjects() { + return new Listenable[] { player, item }; + } } diff --git a/src/main/java/com/l2jserver/model/world/party/PartyEvent.java b/src/main/java/com/l2jserver/model/world/party/PartyEvent.java new file mode 100644 index 000000000..29f232275 --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/party/PartyEvent.java @@ -0,0 +1,8 @@ +package com.l2jserver.model.world.party; + +import com.l2jserver.model.world.Clan; +import com.l2jserver.model.world.event.WorldEvent; + +public interface PartyEvent extends WorldEvent { + Clan getClan(); +} diff --git a/src/main/java/com/l2jserver/model/world/party/PartyListener.java b/src/main/java/com/l2jserver/model/world/party/PartyListener.java new file mode 100644 index 000000000..d0739e43e --- /dev/null +++ b/src/main/java/com/l2jserver/model/world/party/PartyListener.java @@ -0,0 +1,6 @@ +package com.l2jserver.model.world.party; + +import com.l2jserver.model.world.event.WorldListener; + +public interface PartyListener extends WorldListener { +} diff --git a/src/main/java/com/l2jserver/model/world/player/PlayerListener.java b/src/main/java/com/l2jserver/model/world/player/PlayerListener.java index 8fa3f4e7c..fbd7ef079 100644 --- a/src/main/java/com/l2jserver/model/world/player/PlayerListener.java +++ b/src/main/java/com/l2jserver/model/world/player/PlayerListener.java @@ -5,10 +5,10 @@ import com.l2jserver.model.world.actor.ActorListener; public abstract class PlayerListener implements ActorListener { @Override - public void dispatch(ActorEvent e) { + public boolean dispatch(ActorEvent e) { if (!(e instanceof PlayerEvent)) - return; - dispatch((PlayerEvent) e); + return false; + return dispatch((PlayerEvent) e); } /** @@ -18,5 +18,5 @@ public abstract class PlayerListener implements ActorListener { * @param e * the event */ - protected abstract void dispatch(PlayerEvent e); + protected abstract boolean dispatch(PlayerEvent e); } diff --git a/src/main/java/com/l2jserver/model/world/player/PlayerSpawnEvent.java b/src/main/java/com/l2jserver/model/world/player/PlayerSpawnEvent.java index 32f72f428..ba42efc6e 100644 --- a/src/main/java/com/l2jserver/model/world/player/PlayerSpawnEvent.java +++ b/src/main/java/com/l2jserver/model/world/player/PlayerSpawnEvent.java @@ -2,6 +2,7 @@ package com.l2jserver.model.world.player; import com.l2jserver.model.world.Player; import com.l2jserver.model.world.capability.Actor; +import com.l2jserver.model.world.capability.Listenable; import com.l2jserver.model.world.capability.Spawnable; import com.l2jserver.model.world.event.SpawnEvent; import com.l2jserver.util.Coordinate; @@ -14,12 +15,6 @@ public class PlayerSpawnEvent implements PlayerEvent, SpawnEvent { this.player = player; this.coordinate = coordinate; } - - @Override - public void dispatch() { - if (player != null) - player.dispatch(this); - } @Override public Spawnable getObject() { @@ -40,4 +35,9 @@ public class PlayerSpawnEvent implements PlayerEvent, SpawnEvent { public Actor getActor() { return player; } + + @Override + public Listenable[] getDispatchableObjects() { + return new Listenable[] { player }; + } } diff --git a/src/main/java/com/l2jserver/service/cache/CacheService.java b/src/main/java/com/l2jserver/service/cache/CacheService.java new file mode 100644 index 000000000..dd4d3dc43 --- /dev/null +++ b/src/main/java/com/l2jserver/service/cache/CacheService.java @@ -0,0 +1,20 @@ +package com.l2jserver.service.cache; + +import com.l2jserver.service.Service; + +/** + * This is an transparent Cache system. It proxies an interface implementing + * {@link Cacheable}. Once the first call is done through the proxy, the result + * is cached in the underlying cache engine. When the second and sucedind calls + * are made the cache is looked up, if a match (method and arguments pair) is + * found, this result is returned. + *

+ * If you do not desire to cache an method, annotate it with + * {@link IgnoreCaching} + * + * @author Rogiel + * + */ +public interface CacheService extends Service { + T decorate(Class interfaceType, T instance); +} diff --git a/src/main/java/com/l2jserver/service/cache/Cacheable.java b/src/main/java/com/l2jserver/service/cache/Cacheable.java new file mode 100644 index 000000000..7c310a54e --- /dev/null +++ b/src/main/java/com/l2jserver/service/cache/Cacheable.java @@ -0,0 +1,5 @@ +package com.l2jserver.service.cache; + +public interface Cacheable { + +} diff --git a/src/main/java/com/l2jserver/service/cache/IgnoreCaching.java b/src/main/java/com/l2jserver/service/cache/IgnoreCaching.java new file mode 100644 index 000000000..c8533afca --- /dev/null +++ b/src/main/java/com/l2jserver/service/cache/IgnoreCaching.java @@ -0,0 +1,16 @@ +package com.l2jserver.service.cache; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +/** + * Indicate to the proxy that this method should not be cached. + */ +public @interface IgnoreCaching { +} diff --git a/src/main/java/com/l2jserver/service/cache/SimpleCacheService.java b/src/main/java/com/l2jserver/service/cache/SimpleCacheService.java new file mode 100644 index 000000000..98c18d5aa --- /dev/null +++ b/src/main/java/com/l2jserver/service/cache/SimpleCacheService.java @@ -0,0 +1,94 @@ +package com.l2jserver.service.cache; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.Map; + +import com.l2jserver.service.ServiceStartException; +import com.l2jserver.service.ServiceStopException; +import com.l2jserver.util.factory.CollectionFactory; + +public class SimpleCacheService implements CacheService { + private final Map cache = CollectionFactory + .newWeakMap(MethodInvocation.class, Object.class); + + @Override + public void start() throws ServiceStartException { + // TODO Auto-generated method stub + + } + + @Override + public T decorate(final Class interfaceType, + final T instance) { + if (!interfaceType.isInterface()) + return null; + @SuppressWarnings("unchecked") + final T proxy = (T) Proxy.newProxyInstance(this.getClass() + .getClassLoader(), new Class[] { interfaceType }, + new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, + Object[] args) throws Throwable { + if (method.isAnnotationPresent(IgnoreCaching.class)) + return method.invoke(instance, args); + final MethodInvocation invocation = new MethodInvocation( + method, args); + Object result = cache.get(invocation); + if (result == null) { + result = method.invoke(instance, args); + cache.put(invocation, result); + } + return result; + } + }); + return proxy; + } + + @Override + public void stop() throws ServiceStopException { + // TODO Auto-generated method stub + + } + + private class MethodInvocation { + private final Method method; + private final Object[] args; + + public MethodInvocation(Method method, Object[] args) { + this.method = method; + this.args = args; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(args); + result = prime * result + + ((method == null) ? 0 : method.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MethodInvocation other = (MethodInvocation) obj; + if (!Arrays.equals(args, other.args)) + return false; + if (method == null) { + if (other.method != null) + return false; + } else if (!method.equals(other.method)) + return false; + return true; + } + } +} diff --git a/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java b/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java index ba734d385..029d6f2da 100644 --- a/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java +++ b/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcher.java @@ -1,6 +1,9 @@ package com.l2jserver.service.game.world; +import com.l2jserver.model.id.ObjectID; +import com.l2jserver.model.world.capability.Listenable; import com.l2jserver.model.world.event.WorldEvent; +import com.l2jserver.model.world.event.WorldListener; /** * This event dispatcher notify listeners that an certain event occured in their @@ -18,4 +21,64 @@ public interface WorldEventDispatcher { * the event */ void dispatch(WorldEvent event); + + /** + * Adds a new listener to object + * + * @param + * the event type + * @param + * the listener type + * @param object + * the object to listen to + * @param listener + * the listener + */ + > void addListener( + Listenable object, WorldListener listener); + + /** + * Adds a new listener to object with id id + * + * @param + * the event type + * @param + * the listener type + * @param id + * the object id to listen to + * @param listener + * the listener + */ + > void addListener( + ObjectID> id, WorldListener listener); + + /** + * Removes an existing listener from object + * + * @param + * the event type + * @param + * the listener type + * @param object + * the object to listen to + * @param listener + * the listener + */ + > void removeListener( + Listenable object, WorldListener listener); + + /** + * Removes an existing listener from the object with id id + * + * @param + * the event type + * @param + * the listener type + * @param id + * the object id to listen to + * @param listener + * the listener + */ + > void removeListener( + ObjectID> id, WorldListener listener); } diff --git a/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcherImpl.java b/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcherImpl.java index a9bbad153..a11dc35a1 100644 --- a/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcherImpl.java +++ b/src/main/java/com/l2jserver/service/game/world/WorldEventDispatcherImpl.java @@ -1,6 +1,14 @@ package com.l2jserver.service.game.world; +import java.util.Queue; +import java.util.Timer; +import java.util.TimerTask; + +import com.l2jserver.model.id.ObjectID; +import com.l2jserver.model.world.capability.Listenable; import com.l2jserver.model.world.event.WorldEvent; +import com.l2jserver.model.world.event.WorldListener; +import com.l2jserver.util.factory.CollectionFactory; /** * {@link WorldEventDispatcher} implementation @@ -8,8 +16,137 @@ import com.l2jserver.model.world.event.WorldEvent; * @author Rogiel */ public class WorldEventDispatcherImpl implements WorldEventDispatcher { + private final Timer timer = new Timer(); + + private Queue listeners = CollectionFactory + .newConcurrentQueue(ListenerIDPair.class); + private Queue events = CollectionFactory + .newConcurrentQueue(WorldEvent.class); + + public WorldEventDispatcherImpl() { + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + final WorldEvent event = events.poll(); + if (event == null) + return; + try { + doDispatch(event); + } catch (Throwable t) { + } + } + }, 0, 50); + } + public void dispatch(WorldEvent event) { - // TODO implement threaded model - event.dispatch(); + events.add(event); + } + + public void doDispatch(WorldEvent event) { + final Listenable[] objects = event.getDispatchableObjects(); + for (final ListenerIDPair pair : listeners) { + for (Listenable obj : objects) { + if (obj == null) + continue; + if (!pair.testDispatch(obj.getID())) + continue; + try { + if (pair.dispatch(event)) + continue; + } catch (ClassCastException e) { + } + listeners.remove(pair); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public > void addListener( + Listenable object, WorldListener listener) { + listeners.add(new ListenerIDPair(object.getID(), + (WorldListener) listener)); + } + + @Override + @SuppressWarnings("unchecked") + public > void addListener( + ObjectID> id, WorldListener listener) { + listeners.add(new ListenerIDPair(id, + (WorldListener) listener)); + } + + @Override + @SuppressWarnings("unchecked") + public > void removeListener( + Listenable object, WorldListener listener) { + listeners.remove(new ListenerIDPair(object.getID(), + (WorldListener) listener)); + } + + @Override + @SuppressWarnings("unchecked") + public > void removeListener( + ObjectID> id, WorldListener listener) { + listeners.remove(new ListenerIDPair(id, + (WorldListener) listener)); + } + + private class ListenerIDPair { + private ObjectID ID; + private WorldListener listener; + + public ListenerIDPair(ObjectID ID, WorldListener listener) { + super(); + this.ID = ID; + this.listener = listener; + } + + public boolean testDispatch(ObjectID id) { + return id.equals(this.ID); + } + + public boolean dispatch(WorldEvent e) { + return listener.dispatch(e); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + getOuterType().hashCode(); + result = prime * result + ((ID == null) ? 0 : ID.hashCode()); + result = prime * result + + ((listener == null) ? 0 : listener.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ListenerIDPair other = (ListenerIDPair) obj; + if (!getOuterType().equals(other.getOuterType())) + return false; + if (ID == null) { + if (other.ID != null) + return false; + } else if (!ID.equals(other.ID)) + return false; + if (listener == null) { + if (other.listener != null) + return false; + } else if (!listener.equals(other.listener)) + return false; + return true; + } + + private WorldEventDispatcherImpl getOuterType() { + return WorldEventDispatcherImpl.this; + } } } diff --git a/src/main/java/com/l2jserver/service/network/NettyNetworkService.java b/src/main/java/com/l2jserver/service/network/NettyNetworkService.java index 86668ac24..111cae205 100644 --- a/src/main/java/com/l2jserver/service/network/NettyNetworkService.java +++ b/src/main/java/com/l2jserver/service/network/NettyNetworkService.java @@ -8,7 +8,6 @@ import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import com.google.inject.Inject; import com.google.inject.Injector; -import com.l2jserver.game.net.Lineage2Connection; import com.l2jserver.game.net.Lineage2PipelineFactory; import com.l2jserver.service.configuration.ConfigurationService; diff --git a/src/main/java/com/l2jserver/service/network/NetworkService.java b/src/main/java/com/l2jserver/service/network/NetworkService.java index 20cbedc20..584f2e69b 100644 --- a/src/main/java/com/l2jserver/service/network/NetworkService.java +++ b/src/main/java/com/l2jserver/service/network/NetworkService.java @@ -1,6 +1,5 @@ package com.l2jserver.service.network; -import com.l2jserver.game.net.Lineage2Connection; import com.l2jserver.service.Service; public interface NetworkService extends Service { diff --git a/src/main/java/com/l2jserver/util/PrimeFinder.java b/src/main/java/com/l2jserver/util/PrimeFinder.java new file mode 100644 index 000000000..a22f11ee7 --- /dev/null +++ b/src/main/java/com/l2jserver/util/PrimeFinder.java @@ -0,0 +1,158 @@ +// Copyright (c) 1999 CERN - European Organization for Nuclear Research. + +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear in +// supporting documentation. CERN makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without expressed or implied warranty. +package com.l2jserver.util; + +import java.util.Arrays; + +/* + * Modified for Trove to use the java.util.Arrays sort/search + * algorithms instead of those provided with colt. + */ + +/** + * Used to keep hash table capacities prime numbers. + * Not of interest for users; only for implementors of hashtables. + * + *

Choosing prime numbers as hash table capacities is a good idea + * to keep them working fast, particularly under hash table + * expansions. + * + *

However, JDK 1.2, JGL 3.1 and many other toolkits do nothing to + * keep capacities prime. This class provides efficient means to + * choose prime capacities. + * + *

Choosing a prime is O(log 300) (binary search in a list + * of 300 ints). Memory requirements: 1 KB static memory. + * + * @author wolfgang.hoschek@cern.ch + * @version 1.0, 09/24/99 + */ +public final class PrimeFinder { + /** + * The largest prime this class can generate; currently equal to + * Integer.MAX_VALUE. + */ + public static final int LARGEST_PRIME = Integer.MAX_VALUE; //yes, it is prime. + + /** + * The prime number list consists of 11 chunks. + * + * Each chunk contains prime numbers. + * + * A chunk starts with a prime P1. The next element is a prime + * P2. P2 is the smallest prime for which holds: P2 >= 2*P1. + * + * The next element is P3, for which the same holds with respect + * to P2, and so on. + * + * Chunks are chosen such that for any desired capacity >= 1000 + * the list includes a prime number <= desired capacity * 1.11. + * + * Therefore, primes can be retrieved which are quite close to any + * desired capacity, which in turn avoids wasting memory. + * + * For example, the list includes + * 1039,1117,1201,1277,1361,1439,1523,1597,1759,1907,2081. + * + * So if you need a prime >= 1040, you will find a prime <= + * 1040*1.11=1154. + * + * Chunks are chosen such that they are optimized for a hashtable + * growthfactor of 2.0; + * + * If your hashtable has such a growthfactor then, after initially + * "rounding to a prime" upon hashtable construction, it will + * later expand to prime capacities such that there exist no + * better primes. + * + * In total these are about 32*10=320 numbers -> 1 KB of static + * memory needed. + * + * If you are stingy, then delete every second or fourth chunk. + */ + + private static final int[] PRIME_CAPACITIES = { + //chunk #0 + LARGEST_PRIME, + + //chunk #1 + 5,11,23,47,97,197,397,797,1597,3203,6421,12853,25717,51437,102877,205759, + 411527,823117,1646237,3292489,6584983,13169977,26339969,52679969,105359939, + 210719881,421439783,842879579,1685759167, + + //chunk #2 + 433,877,1759,3527,7057,14143,28289,56591,113189,226379,452759,905551,1811107, + 3622219,7244441,14488931,28977863,57955739,115911563,231823147,463646329,927292699, + 1854585413, + + //chunk #3 + 953,1907,3821,7643,15287,30577,61169,122347,244703,489407,978821,1957651,3915341, + 7830701,15661423,31322867,62645741,125291483,250582987,501165979,1002331963, + 2004663929, + + //chunk #4 + 1039,2081,4177,8363,16729,33461,66923,133853,267713,535481,1070981,2141977,4283963, + 8567929,17135863,34271747,68543509,137087021,274174111,548348231,1096696463, + + //chunk #5 + 31,67,137,277,557,1117,2237,4481,8963,17929,35863,71741,143483,286973,573953, + 1147921,2295859,4591721,9183457,18366923,36733847,73467739,146935499,293871013, + 587742049,1175484103, + + //chunk #6 + 599,1201,2411,4831,9677,19373,38747,77509,155027,310081,620171,1240361,2480729, + 4961459,9922933,19845871,39691759,79383533,158767069,317534141,635068283,1270136683, + + //chunk #7 + 311,631,1277,2557,5119,10243,20507,41017,82037,164089,328213,656429,1312867, + 2625761,5251529,10503061,21006137,42012281,84024581,168049163,336098327,672196673, + 1344393353, + + //chunk #8 + 3,7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899, + 701819,1403641,2807303,5614657,11229331,22458671,44917381,89834777,179669557, + 359339171,718678369,1437356741, + + //chunk #9 + 43,89,179,359,719,1439,2879,5779,11579,23159,46327,92657,185323,370661,741337, + 1482707,2965421,5930887,11861791,23723597,47447201,94894427,189788857,379577741, + 759155483,1518310967, + + //chunk #10 + 379,761,1523,3049,6101,12203,24407,48817,97649,195311,390647,781301,1562611, + 3125257,6250537,12501169,25002389,50004791,100009607,200019221,400038451,800076929, + 1600153859 + }; + + static { //initializer + // The above prime numbers are formatted for human readability. + // To find numbers fast, we sort them once and for all. + + Arrays.sort(PRIME_CAPACITIES); + } + + /** + * Returns a prime number which is >= desiredCapacity + * and very close to desiredCapacity (within 11% if + * desiredCapacity >= 1000). + * + * @param desiredCapacity the capacity desired by the user. + * @return the capacity which should be used for a hashtable. + */ + public static final int nextPrime(int desiredCapacity) { + int i = Arrays.binarySearch(PRIME_CAPACITIES, desiredCapacity); + if (i<0) { + // desired capacity not found, choose next prime greater + // than desired capacity + i = -i -1; // remember the semantics of binarySearch... + } + return PRIME_CAPACITIES[i]; + } +} \ No newline at end of file diff --git a/src/main/java/com/l2jserver/util/RGBColor.java b/src/main/java/com/l2jserver/util/RGBColor.java new file mode 100644 index 000000000..2cfae2dc0 --- /dev/null +++ b/src/main/java/com/l2jserver/util/RGBColor.java @@ -0,0 +1,38 @@ +package com.l2jserver.util; + +public class RGBColor { + private final byte red; + private final byte green; + private final byte blue; + + public RGBColor(byte r, byte g, byte b) { + this.red = r; + this.green = g; + this.blue = b; + } + + /** + * @return the red + */ + public byte getR() { + return red; + } + + /** + * @return the green + */ + public byte getG() { + return green; + } + + /** + * @return the blue + */ + public byte getB() { + return blue; + } + + public byte[] toByteArray() { + return new byte[] { red, green, blue }; + } +} diff --git a/src/main/java/com/l2jserver/util/factory/CollectionFactory.java b/src/main/java/com/l2jserver/util/factory/CollectionFactory.java deleted file mode 100644 index fa3cb73d2..000000000 --- a/src/main/java/com/l2jserver/util/factory/CollectionFactory.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.l2jserver.util.factory; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; - -/** - * Factory class to create {@link Collection} instances. - * - * @author Rogiel - */ -public class CollectionFactory { - /** - * Creates a new list of type T - * - * @param - * the type - * @param type - * the type - * @return the created list - */ - public static final List newList(Class type) { - return new ArrayList(); - } - - /** - * Creates a new set of type T - * - * @param - * the type - * @param type - * the type - * @return the created set - */ - public static final Set newSet(Class type) { - return new HashSet(); - } - - /** - * Creates a new weak map. - * - * @param - * the key type - * @param - * the value type - * @param key - * the key type class - * @param value - * the value type class - * @return the new map - */ - public static final Map newWeakMap(Class key, Class value) { - return new WeakHashMap(); - } -} diff --git a/src/test/java/com/l2jserver/model/id/allocator/BitSetIDAllocatorTest.java b/src/test/java/com/l2jserver/model/id/allocator/BitSetIDAllocatorTest.java new file mode 100644 index 000000000..0bb2f15d7 --- /dev/null +++ b/src/test/java/com/l2jserver/model/id/allocator/BitSetIDAllocatorTest.java @@ -0,0 +1,64 @@ +package com.l2jserver.model.id.allocator; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; + +import org.junit.Before; +import org.junit.Test; + +public class BitSetIDAllocatorTest { + private final BitSetIDAllocator allocator = new BitSetIDAllocator(); + + @Before + public void tearUp() { + allocator.init(); + } + + @Test + public void testAllocate() { + final int id1 = allocator.allocate(); + final int id2 = allocator.allocate(); + assertFalse(id1 == id2); + assertEquals(IDAllocator.FIRST_ID, id1); + assertEquals(IDAllocator.FIRST_ID + 1, id2); + } + + @Test + public void testAllocateRestore() { + final int id1 = IDAllocator.FIRST_ID; + final int id2 = IDAllocator.FIRST_ID + 1; + + allocator.allocate(id1); + allocator.allocate(id2); + + int id3 = allocator.allocate(); + + assertFalse(id1 == id3); + assertFalse(id2 == id3); + } + + @Test + public void testAllocateMany() { + for (int i = 0; i < 100 * 1000; i++) { + allocator.allocate(); + } + assertEquals(100000, allocator.getAllocatedIDs()); + } + + @Test(expected = IDAllocatorException.class) + public void testAllocateAlreadyAllocated() { + final int id1 = allocator.allocate(); + allocator.allocate(id1); + } + + @Test + public void testRelease() { + final int id = allocator.allocate(); + allocator.release(id); + } + + @Test(expected = IDAllocatorException.class) + public void testReleaseUnalloc() { + allocator.release(IDAllocator.FIRST_ID); + } +} diff --git a/src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java b/src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java new file mode 100644 index 000000000..b1a0a81af --- /dev/null +++ b/src/test/java/com/l2jserver/model/id/factory/IDFactoryTest.java @@ -0,0 +1,48 @@ +package com.l2jserver.model.id.factory; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.l2jserver.db.dao.mysql5.DAOModuleMySQL5; +import com.l2jserver.model.id.CharacterID; +import com.l2jserver.model.id.ID; +import com.l2jserver.model.world.L2Character; +import com.l2jserver.service.BasicServiceModule; +import com.l2jserver.service.ServiceStartException; +import com.l2jserver.service.database.DatabaseService; + +public class IDFactoryTest { + private final Injector injector = Guice.createInjector( + new BasicServiceModule(), new DAOModuleMySQL5(), + new IDFactoryModule()); + private final CharacterIDFactory charIdFactory = injector + .getInstance(CharacterIDFactory.class); + + @Test + public void testCreateID() { + final ID id1 = charIdFactory.createID(); + final ID id2 = charIdFactory.createID(); + Assert.assertNotNull(id1); + Assert.assertFalse(id1.equals(id2)); + } + + @Test + public void testDestroy() { + final CharacterID id1 = charIdFactory.createID(); + Assert.assertNotNull(id1); + charIdFactory.destroy(id1); + } + + @Test + public void testGetObject() throws ServiceStartException { + injector.getInstance(DatabaseService.class).start(); + final CharacterID id1 = charIdFactory.createID(268435456); + final L2Character character = id1.getObject(); + + Assert.assertNotNull(character); + Assert.assertEquals(id1, character.getID()); + } +} diff --git a/src/test/java/com/l2jserver/service/cache/SimpleCacheServiceTest.java b/src/test/java/com/l2jserver/service/cache/SimpleCacheServiceTest.java new file mode 100644 index 000000000..408964047 --- /dev/null +++ b/src/test/java/com/l2jserver/service/cache/SimpleCacheServiceTest.java @@ -0,0 +1,74 @@ +package com.l2jserver.service.cache; + +import java.util.Random; + +import junit.framework.Assert; + +import org.junit.Test; + +public class SimpleCacheServiceTest { + private final SimpleCacheService cacheService = new SimpleCacheService(); + + @Test + public void testNoArgs() { + final TestCacheable cached = cacheService.decorate(TestCacheable.class, + new TestCacheableInstance()); + int output1 = cached.random(); + int output2 = cached.random(); + Assert.assertEquals(output1, output2); + } + + @Test + public void testSameArgs() { + final TestCacheable cached = cacheService.decorate(TestCacheable.class, + new TestCacheableInstance()); + int output1 = cached.random(10); + int output2 = cached.random(10); + Assert.assertEquals(output1, output2); + } + + @Test + public void testDifferentArgs() { + final TestCacheable cached = cacheService.decorate(TestCacheable.class, + new TestCacheableInstance()); + int output1 = cached.random(10); + int output2 = cached.random(20); + Assert.assertFalse(output1 == output2); + } + + @Test + public void testIgnoreCaching() { + final TestCacheable cached = cacheService.decorate(TestCacheable.class, + new TestCacheableInstance()); + int output1 = cached.notCached(); + int output2 = cached.notCached(); + Assert.assertFalse(output1 == output2); + } + + public interface TestCacheable extends Cacheable { + public int random(); + public int random(int arg); + + @IgnoreCaching + public int notCached(); + } + + public static class TestCacheableInstance implements TestCacheable { + private final Random random = new Random(); + + @Override + public int random() { + return random.nextInt(Integer.MAX_VALUE); + } + + @Override + public int random(int arg) { + return random.nextInt(Integer.MAX_VALUE); + } + + @Override + public int notCached() { + return random.nextInt(Integer.MAX_VALUE); + } + } +} diff --git a/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java b/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java index e298fa2f8..4fbda3f3f 100644 --- a/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java +++ b/src/test/java/com/l2jserver/service/world/WorldEventDispatcherImplTest.java @@ -11,8 +11,12 @@ import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Scopes; -import com.l2jserver.model.world.L2Character; +import com.l2jserver.db.dao.mysql5.DAOModuleMySQL5; +import com.l2jserver.model.id.factory.CharacterIDFactory; +import com.l2jserver.model.id.factory.IDFactoryModule; +import com.l2jserver.model.id.factory.ItemIDFactory; import com.l2jserver.model.world.Item; +import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.item.ItemDropEvent; import com.l2jserver.model.world.item.ItemEvent; import com.l2jserver.model.world.item.ItemListener; @@ -30,9 +34,13 @@ public class WorldEventDispatcherImplTest { private WorldService world; private WorldEventDispatcher dispatcher; + private CharacterIDFactory cidFactory; + private ItemIDFactory iidFactory; + @Before public void tearUp() throws ServiceStartException { Injector injector = Guice.createInjector(new BasicServiceModule(), + new DAOModuleMySQL5(), new IDFactoryModule(), new AbstractModule() { @Override protected void configure() { @@ -44,6 +52,9 @@ public class WorldEventDispatcherImplTest { } }); + cidFactory = injector.getInstance(CharacterIDFactory.class); + iidFactory = injector.getInstance(ItemIDFactory.class); + world = injector.getInstance(WorldService.class); dispatcher = injector.getInstance(WorldEventDispatcher.class); Assert.assertNotNull(world); @@ -52,44 +63,56 @@ public class WorldEventDispatcherImplTest { } @Test - public void testListeners1() { + public void testListeners1() throws InterruptedException { final L2Character character1 = new L2Character(); + character1.setID(cidFactory.createID()); final L2Character character2 = new L2Character(); + character2.setID(cidFactory.createID()); final Item item1 = new Item(); + item1.setID(iidFactory.createID()); world.add(character1); world.add(character2); world.add(item1); final AtomicBoolean bool = new AtomicBoolean(); Assert.assertFalse(bool.get()); - character1.addListener(new PlayerListener() { + + dispatcher.addListener(character1, new PlayerListener() { @Override - protected void dispatch(PlayerEvent e) { + protected boolean dispatch(PlayerEvent e) { bool.set(true); - e.getPlayer().removeListener(this); + return false; } }); - character1.addListener(new PlayerListener() { + dispatcher.addListener(character1, new PlayerListener() { @Override - protected void dispatch(PlayerEvent e) { - // bool.set(true); + protected boolean dispatch(PlayerEvent e) { + bool.set(true); + return false; } }); + dispatcher.dispatch(new PlayerSpawnEvent(character1, null)); + Thread.sleep(100); // wait a bit for dispatching to happen Assert.assertTrue(bool.get()); bool.set(false); dispatcher.dispatch(new PlayerSpawnEvent(character1, null)); + Thread.sleep(100); // wait a bit for dispatching to happen Assert.assertFalse(bool.get()); } @Test - public void testListeners2() { + public void testListeners2() throws InterruptedException { final L2Character character1 = new L2Character(); + character1.setID(cidFactory.createID()); final L2Character character2 = new L2Character(); + character2.setID(cidFactory.createID()); final Item item1 = new Item(); + item1.setID(iidFactory.createID()); final Item item2 = new Item(); + item2.setID(iidFactory.createID()); world.add(character1); world.add(character2); world.add(item1); @@ -101,20 +124,24 @@ public class WorldEventDispatcherImplTest { Assert.assertFalse(bool1.get()); Assert.assertFalse(bool2.get()); - character1.addListener(new PlayerListener() { + dispatcher.addListener(character1, new PlayerListener() { @Override - public void dispatch(PlayerEvent e) { + public boolean dispatch(PlayerEvent e) { bool1.set(true); + return true; } }); - item1.addListener(new ItemListener() { + dispatcher.addListener(item1, new ItemListener() { @Override - public void dispatch(ItemEvent e) { + public boolean dispatch(ItemEvent e) { bool2.set(true); + return true; } }); dispatcher.dispatch(new ItemDropEvent(character1, item1)); + Thread.sleep(100); // wait a bit for dispatching to happen + Assert.assertTrue(bool1.get()); Assert.assertTrue(bool2.get()); }