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

Character Friend implementation

Signed-off-by: Rogiel <rogiel@rogiel.com>
This commit is contained in:
2011-05-13 15:46:33 -03:00
parent 632aaac548
commit bb3f24e8f4
23 changed files with 404 additions and 72 deletions

View File

@@ -0,0 +1,69 @@
package com.l2jserver.db.dao;
import java.util.List;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.character.CharacterFriendList;
import com.l2jserver.service.cache.Cacheable;
import com.l2jserver.service.cache.IgnoreCaching;
import com.l2jserver.service.database.DataAccessObject;
/**
* The {@link CharacterFriendDAO} is can load and save
* {@link CharacterFriendList character friend list}.
*
* @author Rogiel
*/
public interface CharacterFriendDAO extends DataAccessObject<CharacterID>,
Cacheable {
/**
* Load the friend list for character represented by <tt>id</tt> from the
* database
*
* @param id
* the id
*/
List<CharacterID> load(CharacterID id);
/**
* Load the friend list for character represented by <tt>character</tt> from
* the database
*
* @param character
* the character
*/
void load(L2Character character);
/**
* Save the instance to the database. If a new database entry was created
* returns true.
*
* @param friends
* the friend list
* @return true if created a new entry in database (i.e. insert), false if
* not created (i.e. update)
*/
@IgnoreCaching
boolean save(CharacterFriendList friends);
/**
* Delete an entire friend list
*
* @param friends
* the friend list
* @return true if at least 1 item was removed
*/
boolean delete(CharacterFriendList friends);
/**
* Delete an <tt>friend</tt> from an <tt>character</tt>
*
* @param character
* the character id
* @param friend
* the friend id
* @return true if the item was removed
*/
boolean delete(CharacterID character, CharacterID friend);
}

View File

@@ -3,6 +3,7 @@ package com.l2jserver.db.dao;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
import com.l2jserver.db.dao.mysql5.MySQL5CharacterDAO;
import com.l2jserver.db.dao.mysql5.MySQL5CharacterFriendDAO;
import com.l2jserver.db.dao.mysql5.MySQL5ItemDAO;
public class DAOModuleMySQL5 extends AbstractModule {
@@ -10,6 +11,8 @@ public class DAOModuleMySQL5 extends AbstractModule {
protected void configure() {
bind(CharacterDAO.class).to(MySQL5CharacterDAO.class).in(
Scopes.SINGLETON);
bind(CharacterFriendDAO.class).to(MySQL5CharacterFriendDAO.class).in(
Scopes.SINGLETON);
bind(ItemDAO.class).to(MySQL5ItemDAO.class).in(Scopes.SINGLETON);
}
}

View File

@@ -71,6 +71,11 @@ public class MySQL5CharacterDAO extends AbstractMySQL5DAO<L2Character>
*/
private final CharacterMapper mapper = new CharacterMapper();
/**
* Character mapper class
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
private final class CharacterMapper implements Mapper<L2Character> {
@Override
public L2Character map(ResultSet rs) throws SQLException {
@@ -199,12 +204,12 @@ public class MySQL5CharacterDAO extends AbstractMySQL5DAO<L2Character>
return database.query(new InsertUpdateQuery<L2Character>(character) {
@Override
protected String query() {
return "INSERT INTO `" + TABLE + "` (`" + CHAR_ID + "`,`" + ACCOUNT_ID + "`,`"
+ NAME + "`,`" + RACE + "`,`" + CLASS + "`,`" + SEX
+ "`,`" + LEVEL + "`,`" + COORD_X + "`,`" + COORD_Y
+ "`,`" + COORD_Z + "`,`" + APPEARANCE_HAIR_STYLE
+ "`,`" + APPEARANCE_HAIR_COLOR + "`,`"
+ APPEARANCE_FACE
return "INSERT INTO `" + TABLE + "` (`" + CHAR_ID + "`,`"
+ ACCOUNT_ID + "`,`" + NAME + "`,`" + RACE + "`,`"
+ CLASS + "`,`" + SEX + "`,`" + LEVEL + "`,`" + COORD_X
+ "`,`" + COORD_Y + "`,`" + COORD_Z + "`,`"
+ APPEARANCE_HAIR_STYLE + "`,`" + APPEARANCE_HAIR_COLOR
+ "`,`" + APPEARANCE_FACE
+ "`) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)";
}
@@ -233,6 +238,6 @@ public class MySQL5CharacterDAO extends AbstractMySQL5DAO<L2Character>
st.setString(i++, appearance.getHairColor().name());
st.setString(i++, appearance.getFace().name());
}
});
}) > 0;
}
}

View File

@@ -0,0 +1,137 @@
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.CharacterFriendDAO;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.factory.CharacterIDFactory;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.model.world.character.CharacterFriendList;
import com.l2jserver.service.database.DatabaseService;
import com.l2jserver.service.database.MySQLDatabaseService.InsertUpdateQuery;
import com.l2jserver.service.database.MySQLDatabaseService.Mapper;
import com.l2jserver.service.database.MySQLDatabaseService.SelectListQuery;
public class MySQL5CharacterFriendDAO extends AbstractMySQL5DAO<CharacterID>
implements CharacterFriendDAO {
private final CharacterIDFactory idFactory;
/**
* Character table name
*/
public static final String TABLE = "character_friend";
// FIELDS
public static final String CHAR_ID = MySQL5CharacterDAO.CHAR_ID;
public static final String CHAR_ID_FRIEND = MySQL5CharacterDAO.CHAR_ID
+ "_friend";
@Inject
public MySQL5CharacterFriendDAO(DatabaseService database,
final CharacterIDFactory idFactory) {
super(database);
this.idFactory = idFactory;
}
/**
* The {@link Mapper} instance
*/
private final CharacterFriendMapper mapper = new CharacterFriendMapper();
/**
* The friend list mapper
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
private final class CharacterFriendMapper implements Mapper<CharacterID> {
@Override
public CharacterID map(ResultSet rs) throws SQLException {
return idFactory.createID(rs.getInt(CHAR_ID_FRIEND));
}
}
@Override
public List<CharacterID> load(final CharacterID id) {
return database.query(new SelectListQuery<CharacterID>() {
@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<CharacterID> mapper() {
return mapper;
}
});
}
@Override
public void load(L2Character character) {
final List<CharacterID> list = load(character.getID());
character.getFriendList().load(list);
}
@Override
public boolean save(final CharacterFriendList friends) {
return database.query(new InsertUpdateQuery<CharacterID>(friends
.idIterator()) {
@Override
protected String query() {
return "REPLACE INTO `" + TABLE + "` (`" + CHAR_ID + "`,`"
+ CHAR_ID_FRIEND + "`) VALUES(?,?)";
}
@Override
protected void parametize(PreparedStatement st, CharacterID id)
throws SQLException {
st.setInt(1, friends.getCharacter().getID().getID());
st.setInt(2, id.getID());
}
}) > 0;
}
@Override
public boolean delete(final CharacterFriendList friends) {
return database.query(new InsertUpdateQuery<CharacterFriendList>(
friends) {
@Override
protected String query() {
return "DELETE FROM `" + TABLE + "` WHERE `" + CHAR_ID
+ "` = ?";
}
@Override
protected void parametize(PreparedStatement st,
CharacterFriendList friends) throws SQLException {
st.setInt(1, friends.getCharacter().getID().getID());
}
}) > 0;
}
@Override
public boolean delete(final CharacterID character, final CharacterID friend) {
return database.query(new InsertUpdateQuery<Object>((Object) null) {
@Override
protected String query() {
return "DELETE FROM `" + TABLE + "` WHERE `" + CHAR_ID
+ "` = ?, `" + CHAR_ID_FRIEND + "` = ?";
}
@Override
protected void parametize(PreparedStatement st, Object friends)
throws SQLException {
st.setInt(1, character.getID());
st.setInt(2, friend.getID());
}
}) == 1;
}
}

View File

@@ -0,0 +1,26 @@
package com.l2jserver.model.id.object.iterator;
import java.util.Iterator;
import com.l2jserver.model.world.WorldObject;
/**
* This is a simple {@link Iterable} implementation that always return the same
* {@link Iterator}.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
* @param <T>
* the return object type
*/
public class WorldObjectIterable<T extends WorldObject> implements Iterable<T> {
private final Iterator<T> iterator;
public WorldObjectIterable(Iterator<T> iterator) {
this.iterator = iterator;
}
@Override
public Iterator<T> iterator() {
return iterator;
}
}

View File

@@ -0,0 +1,44 @@
package com.l2jserver.model.id.object.iterator;
import java.util.Iterator;
import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.world.WorldObject;
import com.l2jserver.util.ArrayIterator;
/**
* This {@link Iterator} will iterate trough another {@link Iterator} which
* return {@link ObjectID} instances. For each ID, the
* {@link ObjectID#getObject()} method will be called and its result will be
* returned.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
* @param <T>
* the object type
*/
public class WorldObjectIterator<T extends WorldObject> implements Iterator<T> {
private final Iterator<? extends ObjectID<T>> ids;
public WorldObjectIterator(ObjectID<T>... ids) {
this(new ArrayIterator<ObjectID<T>>(ids));
}
public WorldObjectIterator(Iterator<? extends ObjectID<T>> ids) {
this.ids = ids;
}
@Override
public boolean hasNext() {
return ids.hasNext();
}
@Override
public T next() {
return ids.next().getObject();
}
@Override
public void remove() {
ids.remove();
}
}

View File

@@ -1,24 +1,18 @@
package com.l2jserver.model.world;
import java.util.List;
import java.util.Iterator;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.ClanID;
import com.l2jserver.model.id.object.iterator.WorldObjectIterator;
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<ClanListener, ClanEvent>, Joinable<L2Character> {
/**
* This clan listeners
*/
private final List<ClanListener> listeners = CollectionFactory
.newList(ClanListener.class);
/**
* Clan leader
*/
@@ -68,4 +62,9 @@ public class Clan extends AbstractObject implements
public ClanID getID() {
return (ClanID) super.getID();
}
@Override
public Iterator<L2Character> iterator() {
return new WorldObjectIterator<L2Character>(members.iterator());
}
}

View File

@@ -10,6 +10,7 @@ import com.l2jserver.model.world.character.CharacterAttributes;
import com.l2jserver.model.world.character.CharacterBaseAttributes;
import com.l2jserver.model.world.character.CharacterCalculatedAttributes;
import com.l2jserver.model.world.character.CharacterClass;
import com.l2jserver.model.world.character.CharacterFriendList;
import com.l2jserver.model.world.character.CharacterInventory;
/**
@@ -59,6 +60,10 @@ public class L2Character extends Player {
* The attributes of this character
*/
private final CharacterAttributes attributes;
/**
* The list of friend of this character
*/
private final CharacterFriendList friendList = new CharacterFriendList(this);
/**
* Creates a new instance
@@ -211,4 +216,11 @@ public class L2Character extends Player {
public CharacterAttributes getAttributes() {
return attributes;
}
/**
* @return the friendList
*/
public CharacterFriendList getFriendList() {
return friendList;
}
}

View File

@@ -1,9 +1,11 @@
package com.l2jserver.model.world;
import java.util.Iterator;
import java.util.List;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.ClanID;
import com.l2jserver.model.id.object.iterator.WorldObjectIterator;
import com.l2jserver.model.world.capability.Joinable;
import com.l2jserver.model.world.capability.Listenable;
import com.l2jserver.model.world.party.PartyEvent;
@@ -30,4 +32,9 @@ public class Party extends AbstractObject implements
// TODO Auto-generated method stub
}
@Override
public Iterator<L2Character> iterator() {
return new WorldObjectIterator<L2Character>(members.iterator());
}
}

View File

@@ -7,7 +7,7 @@ import com.l2jserver.model.world.AbstractObject;
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface Joinable<T> extends ObjectCapability {
public interface Joinable<T> extends ObjectCapability, Iterable<T> {
/**
* Join an <tt>member</tt> to this object.
*

View File

@@ -1,27 +0,0 @@
package com.l2jserver.model.world.capability;
import com.l2jserver.model.world.AbstractObject;
import com.l2jserver.service.game.scripting.Script;
/**
* Defines an {@link AbstractObject} that can be controller by an {@link Script}
* implementation.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface Scriptable extends ObjectCapability {
/**
* The the current script attached to this object
*
* @return the attached script
*/
Script<Scriptable> getScript();
/**
* Set the attached script to this object
*
* @param script
* the script
*/
void setScript(Script<Scriptable> script);
}

View File

@@ -1,9 +1,11 @@
package com.l2jserver.model.world.character;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.iterator.WorldObjectIterator;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.util.factory.CollectionFactory;
@@ -29,9 +31,21 @@ public class CharacterFriendList implements Iterable<L2Character> {
return character;
}
/**
* Iterator containing all friends IDs
*
* @return an iterator with friend ids
*/
public Iterator<CharacterID> idIterator() {
return friends.iterator();
}
@Override
public Iterator<L2Character> iterator() {
// TODO
return null;
return new WorldObjectIterator<L2Character>(friends.iterator());
}
public void load(Collection<CharacterID> list) {
friends.addAll(list);
}
}

View File

@@ -6,10 +6,10 @@ import com.l2jserver.service.game.scripting.ScriptingService;
import com.l2jserver.service.game.scripting.ScriptingServiceImpl;
import com.l2jserver.service.game.template.StaticTemplateService;
import com.l2jserver.service.game.template.TemplateService;
import com.l2jserver.service.game.world.WorldEventDispatcher;
import com.l2jserver.service.game.world.WorldEventDispatcherImpl;
import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.game.world.WorldServiceImpl;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.service.game.world.event.WorldEventDispatcherImpl;
import com.l2jserver.service.network.NettyNetworkService;
import com.l2jserver.service.network.NetworkService;

View File

@@ -1,16 +0,0 @@
package com.l2jserver.service.game.scripting;
import com.l2jserver.model.world.capability.Scriptable;
public interface Script<O extends Scriptable> extends Runnable {
/**
* Load this script for <tt>object</tt>
*
* @param object
*/
void load(O object);
void unload();
O getObject();
}

View File

@@ -6,6 +6,7 @@ import java.util.List;
import com.l2jserver.model.world.WorldObject;
import com.l2jserver.model.world.filter.WorldObjectFilter;
import com.l2jserver.service.Service;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
/**
* Service responsible for managing {@link WorldObject} and dispatch events.

View File

@@ -15,6 +15,7 @@ import com.l2jserver.model.world.iterator.FilterIterator;
import com.l2jserver.service.AbstractService;
import com.l2jserver.service.ServiceStartException;
import com.l2jserver.service.ServiceStopException;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.util.factory.CollectionFactory;
public class WorldServiceImpl extends AbstractService implements WorldService {

View File

@@ -1,4 +1,4 @@
package com.l2jserver.service.game.world;
package com.l2jserver.service.game.world.event;
import com.l2jserver.model.id.ObjectID;
import com.l2jserver.model.world.capability.Listenable;

View File

@@ -1,4 +1,4 @@
package com.l2jserver.service.game.world;
package com.l2jserver.service.game.world.event;
import java.util.Queue;
import java.util.Timer;

View File

@@ -2,7 +2,7 @@ CREATE TABLE `character` (
`character_id` int(12) NOT NULL,
`account_id` varchar(50) NOT NULL,
`name` varchar(50) NOT NULL,
`race` enum('HUMAN') NOT NULL,
`race` enum('HUMAN', 'ELF', 'DARK_ELF', 'ORC', 'DWARF', 'KAMAEL') NOT NULL,
`class` enum('HUMAN_FIGHTER','WARRIOR','GLADIATOR','WARLORD','KNIGHT','PALADIN','DARK_AVENGER','ROGUE','TREASURE_HUNTER','HAWKEYE','DUELIST','DREADNOUGHT','phoenixKnight','hellKnight','sagittarius','adventurer','HUMAN_MYSTIC','WIZARD','SORCEROR','NECROMANCER','WARLOCK','CLERIC','BISHOP','PROPHET','ARCHMAGE','SOULTAKER','ARCANA_LORD','CARDINAL','HIEROPHANT','ELVEN_FIGHTER','ELVEN_KNIGHT','TEMPLE_KNIGHT','SWORD_SINGER','ELVEN_SCOUT','PLAINS_WALKER','SILVER_RANGER','EVA_TEMPLAR','SWORD_MUSE','WIND_RIDER','MOONLIGHT_SENTINEL','ELVEN_MYSTIC','ELVEN_WIZARD','SPELLSINGER','ELEMENTAL_SUMMONER','ORACLE','ELDER','MYSTIC_MUSE','ELEMENTAL_MASTER','EVA_SAINT','DARK_FIGHTER','PALUS_KNIGHT','SHILLIEN_KNIGHT','BLADEDANCER','ASSASSIN','ABYSS_WALKER','PHANTOM_RANGER','SHILLIEN_TEMPLAR','spectralDancer','ghostHunter','ghostSentinel','DARK_MYSTIC','DARK_WIZARD','SPELLHOWLER','PHANTOM_SUMMONER','SHILLIEN_ORACLE','SHILLIEN_ELDER','STORM_SCREAMER','SPECTRAL_MASTER','SHILLIEAN_SAINT','ORC_FIGHTER','ORC_RAIDER','DESTROYER','ORC_MONK','TYRANT','TITAN','GRAND_KHAUATARI','ORC_MYSTIC','ORC_SHAMAN','OVERLORD','WARCRYER','DOMINATOR','DOOMCRYER','DWARVEN_FIGHTER','SCAVENGER','BOUNTY_HUNTER','ARTISAN','WARSMITH','FORTUNE_SEEKER','MAESTRO','MALE_SOLDIER','TROOPER','BERSEKER','MALE_SOULBREAKER','DOOMBRINGER','MALE_SOULDHOUND','FEMALE_SOLDIER','WARDER','FEMALE_SOULBREAKER','ARBALESTER','FEMALE_SOULDHOUND','TRICKSTER','INSPECTOR','JUDICATOR') NOT NULL DEFAULT 'HUMAN_FIGHTER',
`sex` enum('MALE','FEMALE') NOT NULL,
`level` int(3) NOT NULL,

View File

@@ -0,0 +1,5 @@
CREATE TABLE `character_friend` (
`character_id` int(10) NOT NULL,
`character_id_friend` int(10) NOT NULL,
PRIMARY KEY (`character_id`,`character_id_friend`)
) ENGINE=MyISAM;

View File

@@ -0,0 +1,51 @@
package com.l2jserver.model.world.character;
import junit.framework.Assert;
import org.apache.log4j.BasicConfigurator;
import org.junit.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.l2jserver.db.dao.CharacterFriendDAO;
import com.l2jserver.db.dao.DAOModuleMySQL5;
import com.l2jserver.model.id.factory.IDFactoryModule;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.factory.CharacterIDFactory;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.BasicServiceModule;
import com.l2jserver.service.ServiceModule;
import com.l2jserver.service.ServiceStartException;
import com.l2jserver.service.database.DatabaseService;
import com.l2jserver.service.game.scripting.ScriptingService;
import com.l2jserver.service.game.template.TemplateService;
public class CharacterFriendListTest {
private final Injector injector = Guice.createInjector(new ServiceModule(),
new BasicServiceModule(), new DAOModuleMySQL5(),
new IDFactoryModule());
private final CharacterIDFactory charIdFactory = injector
.getInstance(CharacterIDFactory.class);
@Test
public void testIterator() throws ServiceStartException {
BasicConfigurator.configure();
injector.getInstance(ScriptingService.class).start();
injector.getInstance(TemplateService.class).start();
injector.getInstance(DatabaseService.class).start();
final CharacterID id = charIdFactory.createID(268437456);
final L2Character character = id.getObject();
final CharacterFriendDAO friendDao = injector
.getInstance(CharacterFriendDAO.class);
friendDao.load(character);
for (final L2Character friend : character.getFriendList()) {
Assert.assertNotNull(friend);
Assert.assertNotSame(friend.getID(), character.getID());
Assert.assertFalse(friend.getID().equals(character.getID()));
}
}
}

View File

@@ -24,11 +24,12 @@ import com.l2jserver.model.world.player.PlayerEvent;
import com.l2jserver.model.world.player.PlayerListener;
import com.l2jserver.model.world.player.PlayerSpawnEvent;
import com.l2jserver.service.BasicServiceModule;
import com.l2jserver.service.ServiceModule;
import com.l2jserver.service.ServiceStartException;
import com.l2jserver.service.game.world.WorldEventDispatcher;
import com.l2jserver.service.game.world.WorldEventDispatcherImpl;
import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.game.world.WorldServiceImpl;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.service.game.world.event.WorldEventDispatcherImpl;
public class WorldEventDispatcherImplTest {
private WorldService world;
@@ -40,8 +41,8 @@ public class WorldEventDispatcherImplTest {
@Before
public void tearUp() throws ServiceStartException {
Injector injector = Guice.createInjector(new BasicServiceModule(),
new DAOModuleMySQL5(), new IDFactoryModule(),
new AbstractModule() {
new ServiceModule(), new DAOModuleMySQL5(),
new IDFactoryModule(), new AbstractModule() {
@Override
protected void configure() {
bind(WorldService.class).to(WorldServiceImpl.class).in(

View File

@@ -15,10 +15,10 @@ import com.l2jserver.model.world.WorldObject;
import com.l2jserver.model.world.filter.impl.InstanceFilter;
import com.l2jserver.service.BasicServiceModule;
import com.l2jserver.service.ServiceStartException;
import com.l2jserver.service.game.world.WorldEventDispatcher;
import com.l2jserver.service.game.world.WorldEventDispatcherImpl;
import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.game.world.WorldServiceImpl;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.service.game.world.event.WorldEventDispatcherImpl;
public class WorldServiceImplTest {
private WorldService world;