1
0
mirror of https://github.com/Rogiel/l2jserver2 synced 2025-12-06 07:32:46 +00:00

Chat logging implementation and chat service improvements

Signed-off-by: Rogiel <rogiel@rogiel.com>
This commit is contained in:
2011-07-30 19:30:49 -03:00
parent 373ea43f3e
commit 9b25d29192
28 changed files with 863 additions and 77 deletions

9
dist/sql/log_chat.sql vendored Normal file
View File

@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS `log_chat` (
`message_id` int(12) NOT NULL AUTO_INCREMENT,
`type` enum('ALL','SHOUT','TELL','PARTY','CLAN','GM','PETITION_PLAYER','PETITION_GM','TRADE','ALLIANCE','ANNOUNCEMENT','BOAT','L2FRIEND','MSNCHAT','PARTYMATCH_ROOM','PARTYROOM_COMMANDER','PARTYROOM_ALL','HERO_VOICE','CRITICAL_ANNOUNCE','SCREEN_ANNOUNCE','BATTLEFIELD','MPCC_ROOM') NOT NULL,
`channel_id` int(12) NOT NULL,
`sender` int(12) NOT NULL,
`date` int(12) NOT NULL,
`message` text NOT NULL,
PRIMARY KEY (`message_id`)
) ENGINE=MyISAM;

View File

@@ -21,11 +21,13 @@ import com.google.inject.Module;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.CharacterFriendDAO; import com.l2jserver.db.dao.CharacterFriendDAO;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.db.dao.ClanDAO; import com.l2jserver.db.dao.ClanDAO;
import com.l2jserver.db.dao.ItemDAO; import com.l2jserver.db.dao.ItemDAO;
import com.l2jserver.db.dao.NPCDAO; import com.l2jserver.db.dao.NPCDAO;
import com.l2jserver.db.dao.jdbc.h2.H2CharacterDAO; import com.l2jserver.db.dao.jdbc.h2.H2CharacterDAO;
import com.l2jserver.db.dao.jdbc.h2.H2CharacterFriendDAO; import com.l2jserver.db.dao.jdbc.h2.H2CharacterFriendDAO;
import com.l2jserver.db.dao.jdbc.h2.H2ChatMessageDAO;
import com.l2jserver.db.dao.jdbc.h2.H2ClanDAO; import com.l2jserver.db.dao.jdbc.h2.H2ClanDAO;
import com.l2jserver.db.dao.jdbc.h2.H2ItemDAO; import com.l2jserver.db.dao.jdbc.h2.H2ItemDAO;
import com.l2jserver.db.dao.jdbc.h2.H2NPCDAO; import com.l2jserver.db.dao.jdbc.h2.H2NPCDAO;
@@ -46,5 +48,9 @@ public class H2DAOModule extends AbstractModule {
bind(ItemDAO.class).to(H2ItemDAO.class).in(Scopes.SINGLETON); bind(ItemDAO.class).to(H2ItemDAO.class).in(Scopes.SINGLETON);
bind(ClanDAO.class).to(H2ClanDAO.class).in(Scopes.SINGLETON); bind(ClanDAO.class).to(H2ClanDAO.class).in(Scopes.SINGLETON);
// logs
bind(ChatMessageDAO.class).to(H2ChatMessageDAO.class).in(
Scopes.SINGLETON);
} }
} }

View File

@@ -21,11 +21,13 @@ import com.google.inject.Module;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.CharacterFriendDAO; import com.l2jserver.db.dao.CharacterFriendDAO;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.db.dao.ClanDAO; import com.l2jserver.db.dao.ClanDAO;
import com.l2jserver.db.dao.ItemDAO; import com.l2jserver.db.dao.ItemDAO;
import com.l2jserver.db.dao.NPCDAO; import com.l2jserver.db.dao.NPCDAO;
import com.l2jserver.db.dao.jdbc.mysql5.MySQL5CharacterDAO; import com.l2jserver.db.dao.jdbc.mysql5.MySQL5CharacterDAO;
import com.l2jserver.db.dao.jdbc.mysql5.MySQL5CharacterFriendDAO; import com.l2jserver.db.dao.jdbc.mysql5.MySQL5CharacterFriendDAO;
import com.l2jserver.db.dao.jdbc.mysql5.MySQL5ChatMessageDAO;
import com.l2jserver.db.dao.jdbc.mysql5.MySQL5ClanDAO; import com.l2jserver.db.dao.jdbc.mysql5.MySQL5ClanDAO;
import com.l2jserver.db.dao.jdbc.mysql5.MySQL5ItemDAO; import com.l2jserver.db.dao.jdbc.mysql5.MySQL5ItemDAO;
import com.l2jserver.db.dao.jdbc.mysql5.MySQL5NPCDAO; import com.l2jserver.db.dao.jdbc.mysql5.MySQL5NPCDAO;
@@ -47,5 +49,9 @@ public class MySQL5DAOModule extends AbstractModule {
bind(ItemDAO.class).to(MySQL5ItemDAO.class).in(Scopes.SINGLETON); bind(ItemDAO.class).to(MySQL5ItemDAO.class).in(Scopes.SINGLETON);
bind(ClanDAO.class).to(MySQL5ClanDAO.class).in(Scopes.SINGLETON); bind(ClanDAO.class).to(MySQL5ClanDAO.class).in(Scopes.SINGLETON);
// logs
bind(ChatMessageDAO.class).to(MySQL5ChatMessageDAO.class).in(
Scopes.SINGLETON);
} }
} }

View File

@@ -0,0 +1,32 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.db.dao;
import com.l2jserver.model.id.ChatMessageID;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.service.cache.Cacheable;
import com.l2jserver.service.database.DataAccessObject;
/**
* The {@link ChatMessageDAO} is can load and save {@link ChatMessage chat
* messages}.
*
* @author Rogiel
*/
public interface ChatMessageDAO extends
DataAccessObject<ChatMessage, ChatMessageID>, Cacheable {
}

View File

@@ -0,0 +1,210 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.db.dao.jdbc;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import com.google.inject.Inject;
import com.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.model.id.ChatMessageID;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.provider.CharacterIDProvider;
import com.l2jserver.model.id.provider.ChatMessageIDProvider;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.service.database.DatabaseService;
import com.l2jserver.service.database.JDBCDatabaseService.CachedMapper;
import com.l2jserver.service.database.JDBCDatabaseService.InsertUpdateQuery;
import com.l2jserver.service.database.JDBCDatabaseService.Mapper;
import com.l2jserver.service.database.JDBCDatabaseService.SelectListQuery;
import com.l2jserver.service.database.JDBCDatabaseService.SelectSingleQuery;
import com.l2jserver.service.game.chat.ChatMessageType;
/**
* {@link CharacterDAO} implementation for JDBC
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public abstract class JDBCChatMessageDAO extends
AbstractJDBCDAO<ChatMessage, ChatMessageID> implements ChatMessageDAO {
/**
* The {@link ChatMessageID} factory
*/
private final ChatMessageIDProvider idFactory;
/**
* The {@link CharacterID} factory
*/
private final CharacterIDProvider charIdFactory;
/**
* Character table name
*/
public static final String TABLE = "log_chat";
// FIELDS
public static final String MESSAGE_ID = "message_id";
public static final String TYPE = "type";
public static final String CHANNEL_ID = "channel_id";
public static final String SENDER = "sender";
public static final String DATE = "date";
public static final String MESSAGE = "message";
@Inject
public JDBCChatMessageDAO(DatabaseService database,
ChatMessageIDProvider idFactory,
final CharacterIDProvider charIdFactory) {
super(database);
this.idFactory = idFactory;
this.charIdFactory = charIdFactory;
}
/**
* The {@link Mapper} for {@link ChatMessageID}
*/
private final Mapper<ChatMessageID> idMapper = new Mapper<ChatMessageID>() {
@Override
public ChatMessageID map(ResultSet rs) throws SQLException {
return idFactory.createID(rs.getInt(MESSAGE_ID));
}
};
/**
* The {@link Mapper} for {@link ChatMessage}
*/
private final Mapper<ChatMessage> mapper = new CachedMapper<ChatMessage, ChatMessageID>(
database, idMapper) {
@Override
protected ChatMessage map(ChatMessageID id, ResultSet rs)
throws SQLException {
final ChatMessage message = new ChatMessage();
message.setID(id);
message.setType(ChatMessageType.valueOf(rs.getString(TYPE)));
switch (message.getType()) {
case SHOUT:
message.setTarget(charIdFactory.createID(rs.getInt(CHANNEL_ID)));
break;
default:
message.setChannelID(rs.getInt(CHANNEL_ID));
break;
}
message.setSender(charIdFactory.createID(rs.getInt(SENDER)));
message.setDate(new Date(rs.getTimestamp(DATE).getTime()));
message.setMessage(rs.getString(MESSAGE));
return message;
}
};
@Override
public ChatMessage select(final ChatMessageID id) {
return database.query(new SelectSingleQuery<ChatMessage>() {
@Override
protected String query() {
return "SELECT * FROM `" + TABLE + "` WHERE `" + MESSAGE_ID
+ "` = ?";
}
@Override
protected void parametize(PreparedStatement st) throws SQLException {
st.setInt(1, id.getID());
}
@Override
protected Mapper<ChatMessage> mapper() {
return mapper;
}
});
}
@Override
public List<ChatMessageID> selectIDs() {
return database.query(new SelectListQuery<ChatMessageID>() {
@Override
protected String query() {
return "SELECT * FROM `" + TABLE + "`";
}
@Override
protected Mapper<ChatMessageID> mapper() {
return idMapper;
}
});
}
@Override
public boolean insert(ChatMessage message) {
return database.query(new InsertUpdateQuery<ChatMessage>(message) {
@Override
protected String query() {
return "INSERT INTO `" + TABLE + "` (`" + TYPE + "`,`"
+ CHANNEL_ID + "`,`" + SENDER + "`,`" + DATE + "`,`"
+ MESSAGE + "`) VALUES(?,?,?,?,?)";
}
@Override
protected void parametize(PreparedStatement st, ChatMessage message)
throws SQLException {
int i = 1;
st.setString(i++, message.getType().name());
switch (message.getType()) {
case SHOUT:
st.setInt(i++, message.getTarget().getID());
break;
default:
st.setInt(i++, message.getChannelID());
break;
}
st.setInt(i++, message.getSender().getID());
st.setTimestamp(i++, new Timestamp(message.getDate().getTime()));
st.setString(i++, message.getMessage());
}
@Override
protected Mapper<ChatMessageID> keyMapper() {
return idMapper;
}
}) > 0;
}
@Override
public boolean update(ChatMessage message) {
// cannot update chat message logs
return false;
}
@Override
public boolean delete(ChatMessage message) {
return database.query(new InsertUpdateQuery<ChatMessage>(message) {
@Override
protected String query() {
return "DELETE FROM `" + TABLE + "` WHERE `" + MESSAGE_ID
+ "` = ?";
}
@Override
protected void parametize(PreparedStatement st, ChatMessage message)
throws SQLException {
st.setInt(1, message.getID().getID());
}
}) > 0;
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.db.dao.jdbc.h2;
import com.google.inject.Inject;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.db.dao.jdbc.JDBCChatMessageDAO;
import com.l2jserver.model.id.object.provider.CharacterIDProvider;
import com.l2jserver.model.id.provider.ChatMessageIDProvider;
import com.l2jserver.service.database.DatabaseService;
/**
* {@link ChatMessageDAO} implementation for H2 database
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class H2ChatMessageDAO extends JDBCChatMessageDAO implements
ChatMessageDAO {
@Inject
public H2ChatMessageDAO(DatabaseService database,
ChatMessageIDProvider idFactory, CharacterIDProvider charIdFactory) {
super(database, idFactory, charIdFactory);
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.db.dao.jdbc.mysql5;
import com.google.inject.Inject;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.db.dao.jdbc.JDBCChatMessageDAO;
import com.l2jserver.model.id.object.provider.CharacterIDProvider;
import com.l2jserver.model.id.provider.ChatMessageIDProvider;
import com.l2jserver.service.database.DatabaseService;
/**
* {@link ChatMessageDAO} implementation for MySQL5
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class MySQL5ChatMessageDAO extends JDBCChatMessageDAO implements
ChatMessageDAO {
@Inject
public MySQL5ChatMessageDAO(DatabaseService database,
ChatMessageIDProvider idFactory, CharacterIDProvider charIdFactory) {
super(database, idFactory, charIdFactory);
}
}

View File

@@ -140,7 +140,7 @@ public class Lineage2PacketReader extends OneToOneDecoder {
return CM_CHAR_CREATE.class; return CM_CHAR_CREATE.class;
case CM_REQUEST_CHAR_TEMPLATE.OPCODE: case CM_REQUEST_CHAR_TEMPLATE.OPCODE:
return CM_REQUEST_CHAR_TEMPLATE.class; return CM_REQUEST_CHAR_TEMPLATE.class;
case 0xd0: // CM_EXTENDED case 0xd0: // CM_REQ_**************
final int opcode2 = buffer.readUnsignedShort(); final int opcode2 = buffer.readUnsignedShort();
switch (opcode2) { switch (opcode2) {
case CM_GOTO_LOBBY.OPCODE2: case CM_GOTO_LOBBY.OPCODE2:
@@ -152,7 +152,7 @@ public class Lineage2PacketReader extends OneToOneDecoder {
case CM_EXT_REQ_ALL_FORTRESS_INFO.OPCODE2: case CM_EXT_REQ_ALL_FORTRESS_INFO.OPCODE2:
return CM_EXT_REQ_ALL_FORTRESS_INFO.class; return CM_EXT_REQ_ALL_FORTRESS_INFO.class;
default: default:
logger.warn("Unknown opcode2 for 0xd0: 0x{}", logger.warn("Unknown packet for 0xd0{}",
Integer.toHexString(opcode2)); Integer.toHexString(opcode2));
break; break;
} }
@@ -188,7 +188,7 @@ public class Lineage2PacketReader extends OneToOneDecoder {
case CM_ATTACK.OPCODE: case CM_ATTACK.OPCODE:
return CM_ATTACK.class; return CM_ATTACK.class;
default: default:
logger.warn("Unknown opcode: 0x{}", Integer.toHexString(opcode)); logger.warn("Unknown packet for 0x{}", Integer.toHexString(opcode));
break; break;
} }
return null; return null;

View File

@@ -53,7 +53,7 @@ public class Lineage2PacketWriter extends OneToOneEncoder {
final ChannelBuffer buffer = ChannelBuffers.dynamicBuffer( final ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(
ByteOrder.LITTLE_ENDIAN, 10); ByteOrder.LITTLE_ENDIAN, 10);
final ServerPacket packet = (ServerPacket) msg; final ServerPacket packet = (ServerPacket) msg;
buffer.writeShort(0); buffer.writeShort(0); // wrap 2 bytes for packet length
buffer.writeByte(packet.getOpcode()); // packet opcode buffer.writeByte(packet.getOpcode()); // packet opcode
packet.write(connection, buffer); packet.write(connection, buffer);

View File

@@ -25,7 +25,7 @@ import com.l2jserver.game.net.packet.AbstractClientPacket;
import com.l2jserver.game.net.packet.server.SM_ACTION_FAILED; import com.l2jserver.game.net.packet.server.SM_ACTION_FAILED;
import com.l2jserver.service.game.chat.CannotChatToSelfChatServiceException; import com.l2jserver.service.game.chat.CannotChatToSelfChatServiceException;
import com.l2jserver.service.game.chat.ChatBanActiveChatServiceException; import com.l2jserver.service.game.chat.ChatBanActiveChatServiceException;
import com.l2jserver.service.game.chat.ChatMessageDestination; import com.l2jserver.service.game.chat.ChatMessageType;
import com.l2jserver.service.game.chat.ChatService; import com.l2jserver.service.game.chat.ChatService;
import com.l2jserver.service.game.chat.ChatTargetOfflineServiceException; import com.l2jserver.service.game.chat.ChatTargetOfflineServiceException;
import com.l2jserver.service.game.chat.TargetNotFoundChatServiceException; import com.l2jserver.service.game.chat.TargetNotFoundChatServiceException;
@@ -50,7 +50,7 @@ public class CM_CHAT extends AbstractClientPacket {
private final ChatService chatService; private final ChatService chatService;
private String message; private String message;
private ChatMessageDestination destination; private ChatMessageType destination;
private String target; private String target;
@@ -62,8 +62,8 @@ public class CM_CHAT extends AbstractClientPacket {
@Override @Override
public void read(Lineage2Client conn, ChannelBuffer buffer) { public void read(Lineage2Client conn, ChannelBuffer buffer) {
this.message = BufferUtils.readString(buffer); this.message = BufferUtils.readString(buffer);
this.destination = ChatMessageDestination.fromID(buffer.readInt()); this.destination = ChatMessageType.fromID(buffer.readInt());
if (this.destination == ChatMessageDestination.TELL) { // private if (this.destination == ChatMessageType.TELL) { // private
// message // message
this.target = BufferUtils.readString(buffer); this.target = BufferUtils.readString(buffer);
} }

View File

@@ -22,7 +22,7 @@ import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.AbstractServerPacket; import com.l2jserver.game.net.packet.AbstractServerPacket;
import com.l2jserver.model.world.Actor; import com.l2jserver.model.world.Actor;
import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.game.chat.ChatMessageDestination; import com.l2jserver.service.game.chat.ChatMessageType;
import com.l2jserver.util.BufferUtils; import com.l2jserver.util.BufferUtils;
/** /**
@@ -44,7 +44,7 @@ public class SM_CHAT extends AbstractServerPacket {
/** /**
* The message destination * The message destination
*/ */
private ChatMessageDestination destination; private ChatMessageType destination;
/** /**
* The message * The message
*/ */
@@ -54,7 +54,7 @@ public class SM_CHAT extends AbstractServerPacket {
*/ */
private int messageID = 0; private int messageID = 0;
public SM_CHAT(Actor character, ChatMessageDestination destination, public SM_CHAT(Actor character, ChatMessageType destination,
String message) { String message) {
super(OPCODE); super(OPCODE);
this.actor = character; this.actor = character;
@@ -62,7 +62,7 @@ public class SM_CHAT extends AbstractServerPacket {
this.message = message; this.message = message;
} }
public SM_CHAT(Actor actor, ChatMessageDestination destination, public SM_CHAT(Actor actor, ChatMessageType destination,
int messageID) { int messageID) {
super(OPCODE); super(OPCODE);
this.actor = actor; this.actor = actor;

View File

@@ -18,6 +18,7 @@ package com.l2jserver.game.net.packet.server;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.base.Preconditions;
import com.l2jserver.game.net.Lineage2Client; import com.l2jserver.game.net.Lineage2Client;
import com.l2jserver.game.net.packet.AbstractServerPacket; import com.l2jserver.game.net.packet.AbstractServerPacket;
@@ -33,16 +34,28 @@ public class SM_GG_QUERY extends AbstractServerPacket {
*/ */
public static final int OPCODE = 0x74; public static final int OPCODE = 0x74;
public SM_GG_QUERY() { private final int[] key;
super(OPCODE);
public SM_GG_QUERY(int[] key) {
super(OPCODE);
Preconditions.checkArgument(key.length == 4,
"key must by an 4-length array");
this.key = key;
}
public SM_GG_QUERY(int key1, int key2, int key3, int key4) {
super(OPCODE);
this.key = new int[4];
this.key[0] = key1;
this.key[1] = key2;
this.key[2] = key3;
this.key[3] = key4;
} }
@Override @Override
public void write(Lineage2Client conn, ChannelBuffer buffer) { public void write(Lineage2Client conn, ChannelBuffer buffer) {
buffer.writeInt(0x27533DD9); for (final int part : key) {
buffer.writeInt(0x2E72A51D); buffer.writeInt(part);
buffer.writeInt(0x2017038B); }
buffer.writeInt(0xC35B1EA3);
} }
} }

View File

@@ -0,0 +1,39 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.model.id;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.l2jserver.model.server.ChatMessage;
/**
* Each {@link ChatMessage} log entry is identified by an {@link ID}.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class ChatMessageID extends ID<Integer> {
/**
* Creates a new instance
*
* @param id
* the id
*/
@Inject
public ChatMessageID(@Assisted int id) {
super(id);
}
}

View File

@@ -0,0 +1,28 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.model.id.provider;
import com.l2jserver.model.id.ChatMessageID;
/**
* Creates a new {@link ChatMessageID}
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface ChatMessageIDProvider extends
IDProvider<Integer, ChatMessageID> {
}

View File

@@ -0,0 +1,155 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.model.server;
import java.util.Date;
import com.l2jserver.model.AbstractModel;
import com.l2jserver.model.Model;
import com.l2jserver.model.id.ChatMessageID;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.service.game.chat.ChatMessageType;
/**
* This is an chat message stored in the database for logging purposes. It can,
* however, be used as a form of flood-checking.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class ChatMessage extends AbstractModel<ChatMessageID> implements
Model<ChatMessageID> {
/**
* The chat message type.
* <p>
* If {@link ChatMessageType#SHOUT} <tt>target</tt> will be set and
* <tt>channelID</tt> will be <tt>null</tt>.<br>
* Otherwise, <tt>target</tt> is <tt>null</tt> and <tt>channelID</tt> will
* be set.
*/
private ChatMessageType type;
/**
* The channel numeric ID
*/
private int channelID;
/**
* The message target ID, if any.
*/
private CharacterID target;
/**
* The sender ID, if any.
*/
private CharacterID sender;
/**
* The message log date
*/
private Date date;
/**
* The message content
*/
private String message;
/**
* @return the type
*/
public ChatMessageType getType() {
return type;
}
/**
* @param type
* the type to set
*/
public void setType(ChatMessageType type) {
this.type = type;
}
/**
* @return the channelID
*/
public int getChannelID() {
return channelID;
}
/**
* @param channelID
* the channelID to set
*/
public void setChannelID(int channelID) {
this.channelID = channelID;
}
/**
* @return the target
*/
public CharacterID getTarget() {
return target;
}
/**
* @param target
* the target to set
*/
public void setTarget(CharacterID target) {
this.target = target;
}
/**
* @return the sender
*/
public CharacterID getSender() {
return sender;
}
/**
* @param sender
* the sender to set
*/
public void setSender(CharacterID sender) {
this.sender = sender;
}
/**
* @return the date
*/
public Date getDate() {
return date;
}
/**
* @param date
* the date to set
*/
public void setDate(Date date) {
this.date = date;
}
/**
* @return the message
*/
public String getMessage() {
return message;
}
/**
* @param message
* the message to set
*/
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -37,7 +37,9 @@ import com.l2jserver.service.game.admin.AdministratorService;
import com.l2jserver.service.game.admin.AdministratorServiceImpl; import com.l2jserver.service.game.admin.AdministratorServiceImpl;
import com.l2jserver.service.game.character.CharacterService; import com.l2jserver.service.game.character.CharacterService;
import com.l2jserver.service.game.character.CharacterServiceImpl; import com.l2jserver.service.game.character.CharacterServiceImpl;
import com.l2jserver.service.game.chat.ChatLoggingService;
import com.l2jserver.service.game.chat.ChatService; import com.l2jserver.service.game.chat.ChatService;
import com.l2jserver.service.game.chat.DatabaseChatLoggingService;
import com.l2jserver.service.game.chat.SimpleChatService; import com.l2jserver.service.game.chat.SimpleChatService;
import com.l2jserver.service.game.map.pathing.MapperPathingService; import com.l2jserver.service.game.map.pathing.MapperPathingService;
import com.l2jserver.service.game.map.pathing.PathingService; import com.l2jserver.service.game.map.pathing.PathingService;
@@ -104,6 +106,8 @@ public class ServiceModule extends AbstractModule {
bind(ChatService.class).to(SimpleChatService.class) bind(ChatService.class).to(SimpleChatService.class)
.in(Scopes.SINGLETON); .in(Scopes.SINGLETON);
bind(ChatLoggingService.class).to(DatabaseChatLoggingService.class).in(
Scopes.SINGLETON);
bind(AdministratorService.class).to(AdministratorServiceImpl.class).in( bind(AdministratorService.class).to(AdministratorServiceImpl.class).in(
Scopes.SINGLETON); Scopes.SINGLETON);
bind(SpawnService.class).to(SpawnServiceImpl.class) bind(SpawnService.class).to(SpawnServiceImpl.class)

View File

@@ -41,7 +41,6 @@ import org.apache.log4j.helpers.LogLog;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public class TruncateToZipFileAppender extends FileAppender { public class TruncateToZipFileAppender extends FileAppender {
/** /**
* String that points to root directory for backups * String that points to root directory for backups
*/ */

View File

@@ -67,7 +67,7 @@ import com.l2jserver.util.ClassUtils;
import com.l2jserver.util.factory.CollectionFactory; import com.l2jserver.util.factory.CollectionFactory;
/** /**
* The database service implementation for MySQL database * The database service implementation for JDBC database
* *
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
@@ -325,6 +325,7 @@ public class JDBCDatabaseService extends AbstractService implements
this.iterator = iterator; this.iterator = iterator;
} }
@SuppressWarnings("unchecked")
@Override @Override
public Integer query(Connection conn) throws SQLException { public Integer query(Connection conn) throws SQLException {
Preconditions.checkNotNull(conn, "conn"); Preconditions.checkNotNull(conn, "conn");
@@ -336,15 +337,17 @@ public class JDBCDatabaseService extends AbstractService implements
rows += st.executeUpdate(); rows += st.executeUpdate();
// update object desire --it has been realized // update object desire --it has been realized
if (object instanceof Model) if (object instanceof Model) {
((Model<?>) object).setObjectDesire(ObjectDesire.NONE); ((Model<?>) object).setObjectDesire(ObjectDesire.NONE);
final Mapper<T> mapper = keyMapper(object); final Mapper<? extends ID<?>> mapper = keyMapper();
if (mapper == null) if (mapper == null)
continue; continue;
final ResultSet rs = st.getGeneratedKeys(); final ResultSet rs = st.getGeneratedKeys();
while (rs.next()) { while (rs.next()) {
mapper.map(rs); ((Model<ID<?>>) object).setID(mapper.map(rs));
mapper.map(rs);
}
} }
} }
return rows; return rows;
@@ -377,7 +380,7 @@ public class JDBCDatabaseService extends AbstractService implements
* the object * the object
* @return the key mapper * @return the key mapper
*/ */
protected Mapper<T> keyMapper(T object) { protected Mapper<? extends ID<?>> keyMapper() {
return null; return null;
} }
} }

View File

@@ -30,6 +30,7 @@ import com.l2jserver.game.net.packet.server.SM_MOVE;
import com.l2jserver.game.net.packet.server.SM_MOVE_TYPE; import com.l2jserver.game.net.packet.server.SM_MOVE_TYPE;
import com.l2jserver.game.net.packet.server.SM_TARGET; import com.l2jserver.game.net.packet.server.SM_TARGET;
import com.l2jserver.model.id.object.CharacterID; import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.model.world.Actor; import com.l2jserver.model.world.Actor;
import com.l2jserver.model.world.Actor.ActorState; import com.l2jserver.model.world.Actor.ActorState;
import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.L2Character;
@@ -49,7 +50,7 @@ import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.game.AttackService; import com.l2jserver.service.game.AttackService;
import com.l2jserver.service.game.chat.ChatChannel; import com.l2jserver.service.game.chat.ChatChannel;
import com.l2jserver.service.game.chat.ChatChannelListener; import com.l2jserver.service.game.chat.ChatChannelListener;
import com.l2jserver.service.game.chat.ChatMessageDestination; import com.l2jserver.service.game.chat.ChatMessageType;
import com.l2jserver.service.game.chat.ChatService; import com.l2jserver.service.game.chat.ChatService;
import com.l2jserver.service.game.npc.NPCService; import com.l2jserver.service.game.npc.NPCService;
import com.l2jserver.service.game.npc.NotAttackableNPCServiceException; import com.l2jserver.service.game.npc.NotAttackableNPCServiceException;
@@ -148,18 +149,16 @@ public class CharacterServiceImpl extends AbstractService implements
// chat listener // chat listener
final ChatChannelListener globalChatListener = new ChatChannelListener() { final ChatChannelListener globalChatListener = new ChatChannelListener() {
@Override @Override
public void onMessage(ChatChannel channel, CharacterID source, public void onMessage(ChatChannel channel, ChatMessage message) {
String message) { conn.write(new SM_CHAT(message.getSender().getObject(),
conn.write(new SM_CHAT(source.getObject(), ChatMessageType.ALL, message.getMessage()));
ChatMessageDestination.ALL, message));
} }
}; };
final ChatChannelListener tradeChatListener = new ChatChannelListener() { final ChatChannelListener tradeChatListener = new ChatChannelListener() {
@Override @Override
public void onMessage(ChatChannel channel, CharacterID source, public void onMessage(ChatChannel channel, ChatMessage message) {
String message) { conn.write(new SM_CHAT(message.getSender().getObject(),
conn.write(new SM_CHAT(source.getObject(), ChatMessageType.TRADE, message.getMessage()));
ChatMessageDestination.TRADE, message));
} }
}; };
@@ -205,7 +204,7 @@ public class CharacterServiceImpl extends AbstractService implements
// start broadcasting -- will broadcast all nearby objects // start broadcasting -- will broadcast all nearby objects
broadcastService.broadcast(conn); broadcastService.broadcast(conn);
conn.write(new SM_ITEM_GROUND()); conn.write(new SM_ITEM_GROUND());
// characters start in run mode // characters start in run mode

View File

@@ -17,6 +17,7 @@
package com.l2jserver.service.game.chat; package com.l2jserver.service.game.chat;
import com.l2jserver.model.id.object.CharacterID; import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.server.ChatMessage;
/** /**
* The {@link ChatChannel} object is used to send messages to a channel. * The {@link ChatChannel} object is used to send messages to a channel.
@@ -29,7 +30,10 @@ import com.l2jserver.model.id.object.CharacterID;
*/ */
public interface ChatChannel { public interface ChatChannel {
/** /**
* Sends a message to this channel * Sends a message to this channel.
* <p>
* Unless otherwise stated, all messages sent will be automatically logged
* using {@link ChatLoggingService}.
* *
* @param sender * @param sender
* the character sending the message * the character sending the message
@@ -40,8 +44,10 @@ public interface ChatChannel {
* @throws ChatTargetOfflineServiceException * @throws ChatTargetOfflineServiceException
* if the target is offline. Will be be thrown in * if the target is offline. Will be be thrown in
* {@link PrivateChatChannel}. * {@link PrivateChatChannel}.
* @return the created {@link ChatMessage}. The object will be created by
* {@link ChatLoggingService}.
*/ */
void send(CharacterID sender, String message) ChatMessage send(CharacterID sender, String message)
throws ChatBanActiveChatServiceException, throws ChatBanActiveChatServiceException,
ChatTargetOfflineServiceException; ChatTargetOfflineServiceException;
@@ -61,4 +67,19 @@ public interface ChatChannel {
* the listener * the listener
*/ */
void removeChatChannelListener(ChatChannelListener listener); void removeChatChannelListener(ChatChannelListener listener);
/**
* @return the chat channel numeric ID
*/
int getChannelID();
/**
* @return the chat message type accepted by this channel
*/
ChatMessageType getMessageType();
/**
* @return the chat channel name
*/
String getChannelName();
} }

View File

@@ -16,7 +16,7 @@
*/ */
package com.l2jserver.service.game.chat; package com.l2jserver.service.game.chat;
import com.l2jserver.model.id.object.CharacterID; import com.l2jserver.model.server.ChatMessage;
/** /**
* This listener is used to received notifications once a new message is sent to * This listener is used to received notifications once a new message is sent to
@@ -30,10 +30,8 @@ public interface ChatChannelListener {
* *
* @param channel * @param channel
* the chat channel * the chat channel
* @param source
* the character sending this message
* @param message * @param message
* the message * the message
*/ */
void onMessage(ChatChannel channel, CharacterID source, String message); void onMessage(ChatChannel channel, ChatMessage message);
} }

View File

@@ -0,0 +1,42 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.game.chat;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.service.Service;
/**
* This service logs each message sent in the server. Implementarions may choose
* to store in a database, plain text, XML or any other form of logging.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface ChatLoggingService extends Service {
/**
* Sends a message to a public chat channel.
*
* @param sender
* the sender
* @param channel
* the chat channel
* @param message
* the message
* @return the new ChatMessage created
*/
ChatMessage log(CharacterID sender, ChatChannel channel, String message);
}

View File

@@ -17,11 +17,11 @@
package com.l2jserver.service.game.chat; package com.l2jserver.service.game.chat;
/** /**
* Enumeration of all possible message destinations * Enumeration of all possible message types
* *
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public enum ChatMessageDestination { public enum ChatMessageType {
/** /**
* Everyone * Everyone
*/ */
@@ -63,12 +63,12 @@ public enum ChatMessageDestination {
public final int id; public final int id;
ChatMessageDestination(int id) { ChatMessageType(int id) {
this.id = id; this.id = id;
} }
public static ChatMessageDestination fromID(int id) { public static ChatMessageType fromID(int id) {
for (final ChatMessageDestination dest : values()) { for (final ChatMessageType dest : values()) {
if (dest.id == id) if (dest.id == id)
return dest; return dest;
} }

View File

@@ -18,18 +18,22 @@ package com.l2jserver.service.game.chat;
import com.l2jserver.model.id.object.CharacterID; import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.ClanID; import com.l2jserver.model.id.object.ClanID;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.Service; import com.l2jserver.service.Service;
/** /**
* This service chatting in the server. Implementations can be local or can use * This service provides chatting in the server. Implementations can be local or
* another service like an IRC server. * can use another service like an IRC server.
* *
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public interface ChatService extends Service { public interface ChatService extends Service {
/** /**
* Sends a message to a public chat channel. * Sends a message to a public chat channel.
* <p>
* Messages sent will be automatically logged using
* {@link ChatLoggingService}.
* *
* @param sender * @param sender
* the sender * the sender
@@ -47,8 +51,10 @@ public interface ChatService extends Service {
* if there is chat ban active * if there is chat ban active
* @throws ChatTargetOfflineServiceException * @throws ChatTargetOfflineServiceException
* if the chat target is offline * if the chat target is offline
* @return the created {@link ChatMessage}. The object will be created by
* {@link ChatLoggingService}.
*/ */
void send(CharacterID sender, ChatMessageDestination chat, String message, ChatMessage send(CharacterID sender, ChatMessageType chat, String message,
String extra) throws TargetNotFoundChatServiceException, String extra) throws TargetNotFoundChatServiceException,
CannotChatToSelfChatServiceException, CannotChatToSelfChatServiceException,
ChatBanActiveChatServiceException, ChatBanActiveChatServiceException,

View File

@@ -0,0 +1,78 @@
/*
* This file is part of l2jserver <l2jserver.com>.
*
* l2jserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* l2jserver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with l2jserver. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.service.game.chat;
import java.util.Date;
import com.google.inject.Inject;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.provider.CharacterIDProvider;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.service.AbstractService;
/**
* {@link ChatLoggingService} implementation that stores logs in the database
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public class DatabaseChatLoggingService extends AbstractService implements
ChatLoggingService {
/**
* The {@link ChatMessage} DAO
*/
private final ChatMessageDAO chatMessageDao;
/**
* The {@link CharacterID} provider
*/
private final CharacterIDProvider charIdProvider;
@Inject
protected DatabaseChatLoggingService(ChatMessageDAO chatMessageDao,
CharacterIDProvider charIdProvider) {
this.chatMessageDao = chatMessageDao;
this.charIdProvider = charIdProvider;
}
@Override
public ChatMessage log(CharacterID sender, ChatChannel channel,
String messageText) {
final ChatMessage message = new ChatMessage();
// message type and destination
message.setType(channel.getMessageType());
switch (channel.getMessageType()) {
case SHOUT: // if type is SHOUT the ChannelID is the CharacterID
// (target)
message.setTarget(charIdProvider.createID(channel.getChannelID()));
break;
default:
message.setChannelID(channel.getChannelID());
break;
}
// message information
message.setSender(sender);
message.setDate(new Date());
message.setMessage(messageText);
// save in database
chatMessageDao.save(message, true);
return message;
}
}

View File

@@ -24,6 +24,7 @@ import com.google.inject.Inject;
import com.l2jserver.db.dao.CharacterDAO; import com.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.model.id.object.CharacterID; import com.l2jserver.model.id.object.CharacterID;
import com.l2jserver.model.id.object.ClanID; import com.l2jserver.model.id.object.ClanID;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.model.world.Clan; import com.l2jserver.model.world.Clan;
import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.AbstractService; import com.l2jserver.service.AbstractService;
@@ -40,6 +41,8 @@ import com.l2jserver.util.factory.CollectionFactory;
*/ */
// @Depends(RegionService.class) // @Depends(RegionService.class)
public class SimpleChatService extends AbstractService implements ChatService { public class SimpleChatService extends AbstractService implements ChatService {
private final ChatLoggingService chatLoggingService;
/** /**
* The {@link RegionService} * The {@link RegionService}
*/ */
@@ -83,7 +86,9 @@ public class SimpleChatService extends AbstractService implements ChatService {
* the region service * the region service
*/ */
@Inject @Inject
public SimpleChatService(CharacterDAO charDao) { public SimpleChatService(ChatLoggingService chatLogService,
CharacterDAO charDao) {
this.chatLoggingService = chatLogService;
// this.regionService = regionService; // this.regionService = regionService;
this.regionService = null; this.regionService = null;
this.charDao = charDao; this.charDao = charDao;
@@ -100,11 +105,11 @@ public class SimpleChatService extends AbstractService implements ChatService {
} }
@Override @Override
public void send(CharacterID sender, ChatMessageDestination chat, public ChatMessage send(CharacterID sender, ChatMessageType chat, String message,
String message, String extra) String extra) throws TargetNotFoundChatServiceException,
throws TargetNotFoundChatServiceException,
CannotChatToSelfChatServiceException, CannotChatToSelfChatServiceException,
ChatBanActiveChatServiceException, ChatTargetOfflineServiceException { ChatBanActiveChatServiceException,
ChatTargetOfflineServiceException {
Preconditions.checkNotNull(sender, "sender"); Preconditions.checkNotNull(sender, "sender");
Preconditions.checkNotNull(message, "message"); Preconditions.checkNotNull(message, "message");
@@ -131,9 +136,9 @@ public class SimpleChatService extends AbstractService implements ChatService {
channel = getAnnouncementChannel(); channel = getAnnouncementChannel();
break; break;
default: default:
return; return null;
} }
channel.send(sender, message); return channel.send(sender, message);
} }
@Override @Override
@@ -210,13 +215,20 @@ public class SimpleChatService extends AbstractService implements ChatService {
.newSet(); .newSet();
@Override @Override
public void send(CharacterID sender, String message) { public ChatMessage send(CharacterID sender, String textMessage) {
Preconditions.checkNotNull(sender, "sender"); Preconditions.checkNotNull(sender, "sender");
Preconditions.checkNotNull(message, "message"); Preconditions.checkNotNull(textMessage, "message");
// TODO throw exception if sender is banned from chat // TODO throw exception if sender is banned from chat
// log this chat message
ChatMessage message = chatLoggingService.log(sender, this,
textMessage);
for (final ChatChannelListener listener : listeners) { for (final ChatChannelListener listener : listeners) {
listener.onMessage(this, sender, message); listener.onMessage(this, message);
} }
return message;
} }
@Override @Override
@@ -230,6 +242,16 @@ public class SimpleChatService extends AbstractService implements ChatService {
Preconditions.checkNotNull(listener, "listener"); Preconditions.checkNotNull(listener, "listener");
listeners.remove(listener); listeners.remove(listener);
} }
@Override
public String getChannelName() {
return getMessageType().name();
}
@Override
public int getChannelID() {
return getMessageType().id;
}
} }
/** /**
@@ -250,6 +272,16 @@ public class SimpleChatService extends AbstractService implements ChatService {
public CharacterID getDestination() { public CharacterID getDestination() {
return character; return character;
} }
@Override
public int getChannelID() {
return character.getID();
}
@Override
public ChatMessageType getMessageType() {
return ChatMessageType.SHOUT;
}
} }
/** /**
@@ -259,6 +291,10 @@ public class SimpleChatService extends AbstractService implements ChatService {
*/ */
private class GlobalChatChannelImpl extends ChatChannelImpl implements private class GlobalChatChannelImpl extends ChatChannelImpl implements
PublicChatChannel { PublicChatChannel {
@Override
public ChatMessageType getMessageType() {
return ChatMessageType.ALL;
}
} }
/** /**
@@ -268,6 +304,10 @@ public class SimpleChatService extends AbstractService implements ChatService {
*/ */
private class TradeChatChannelImpl extends ChatChannelImpl implements private class TradeChatChannelImpl extends ChatChannelImpl implements
PublicChatChannel { PublicChatChannel {
@Override
public ChatMessageType getMessageType() {
return ChatMessageType.TRADE;
}
} }
/** /**
@@ -277,6 +317,10 @@ public class SimpleChatService extends AbstractService implements ChatService {
*/ */
private class AnnouncementChatChannelImpl extends ChatChannelImpl implements private class AnnouncementChatChannelImpl extends ChatChannelImpl implements
PublicChatChannel { PublicChatChannel {
@Override
public ChatMessageType getMessageType() {
return ChatMessageType.ANNOUNCEMENT;
}
} }
/** /**
@@ -301,6 +345,11 @@ public class SimpleChatService extends AbstractService implements ChatService {
Preconditions.checkNotNull(clanID, "clanID"); Preconditions.checkNotNull(clanID, "clanID");
this.clanID = clanID; this.clanID = clanID;
} }
@Override
public ChatMessageType getMessageType() {
return ChatMessageType.CLAN;
}
} }
/** /**
@@ -325,5 +374,10 @@ public class SimpleChatService extends AbstractService implements ChatService {
Preconditions.checkNotNull(region, "region"); Preconditions.checkNotNull(region, "region");
this.region = region; this.region = region;
} }
@Override
public ChatMessageType getMessageType() {
return ChatMessageType.ALL;
}
} }
} }

View File

@@ -43,13 +43,19 @@ import com.l2jserver.util.factory.CollectionFactory;
public class GameGuardServiceImpl extends AbstractService implements public class GameGuardServiceImpl extends AbstractService implements
GameGuardService { GameGuardService {
/** /**
* The valid GG SHA1 response * The static key used to validate game guards
*/
private static final int[] STATIC_KEY = { 0x27533DD9, 0x2E72A51D,
0x2017038B, 0xC35B1EA3 };
/**
* The valid GG SHA1 response -- for a single key, the answer must be always
* the same
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final byte[] VALID_KEY_SHA1 = { (byte) 0x88, 0x40, 0x1c, private static final byte[] STATIC_KEY_VALIDATION = { (byte) 0x88, 0x40,
(byte) 0xa7, (byte) 0x83, 0x42, (byte) 0xe9, 0x15, (byte) 0xde, 0x1c, (byte) 0xa7, (byte) 0x83, 0x42, (byte) 0xe9, 0x15,
(byte) 0xc3, 0x68, (byte) 0xf6, 0x2d, 0x23, (byte) 0xf1, 0x3f, (byte) 0xde, (byte) 0xc3, 0x68, (byte) 0xf6, 0x2d, 0x23,
(byte) 0xee, 0x68, 0x5b, (byte) 0xc5 }; (byte) 0xf1, 0x3f, (byte) 0xee, 0x68, 0x5b, (byte) 0xc5 };
/** /**
* The map containing all pending futures * The map containing all pending futures
@@ -75,15 +81,16 @@ public class GameGuardServiceImpl extends AbstractService implements
@Override @Override
public Future<GameGuardResponse> query(final Lineage2Client conn) { public Future<GameGuardResponse> query(final Lineage2Client conn) {
conn.write(new SM_GG_QUERY()).addListener(new ChannelFutureListener() { conn.write(new SM_GG_QUERY(STATIC_KEY)).addListener(
@Override new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) @Override
throws Exception { public void operationComplete(ChannelFuture future)
if (future.getCause() != null) { throws Exception {
futures.remove(conn); if (future.getCause() != null) {
} futures.remove(conn);
} }
}); }
});
final GGFuture future = new GGFuture(); final GGFuture future = new GGFuture();
futures.put(conn, future); futures.put(conn, future);
return future; return future;

View File

@@ -50,7 +50,8 @@ public class SecureBlowfishKeygenService extends AbstractService implements
key[i] = (byte) random.nextSecureInt(0, 255); key[i] = (byte) random.nextSecureInt(0, 255);
} }
// the last 8 bytes are static // the last 8 bytes are static and are assumed by the client, they are
// never sent in the SM_KEY packet
key[8] = (byte) 0xc8; key[8] = (byte) 0xc8;
key[9] = (byte) 0x27; key[9] = (byte) 0x27;
key[10] = (byte) 0x93; key[10] = (byte) 0x93;