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.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.CharacterFriendDAO;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.db.dao.ClanDAO;
import com.l2jserver.db.dao.ItemDAO;
import com.l2jserver.db.dao.NPCDAO;
import com.l2jserver.db.dao.jdbc.h2.H2CharacterDAO;
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.H2ItemDAO;
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(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.l2jserver.db.dao.CharacterDAO;
import com.l2jserver.db.dao.CharacterFriendDAO;
import com.l2jserver.db.dao.ChatMessageDAO;
import com.l2jserver.db.dao.ClanDAO;
import com.l2jserver.db.dao.ItemDAO;
import com.l2jserver.db.dao.NPCDAO;
import com.l2jserver.db.dao.jdbc.mysql5.MySQL5CharacterDAO;
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.MySQL5ItemDAO;
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(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;
case CM_REQUEST_CHAR_TEMPLATE.OPCODE:
return CM_REQUEST_CHAR_TEMPLATE.class;
case 0xd0: // CM_EXTENDED
case 0xd0: // CM_REQ_**************
final int opcode2 = buffer.readUnsignedShort();
switch (opcode2) {
case CM_GOTO_LOBBY.OPCODE2:
@@ -152,7 +152,7 @@ public class Lineage2PacketReader extends OneToOneDecoder {
case CM_EXT_REQ_ALL_FORTRESS_INFO.OPCODE2:
return CM_EXT_REQ_ALL_FORTRESS_INFO.class;
default:
logger.warn("Unknown opcode2 for 0xd0: 0x{}",
logger.warn("Unknown packet for 0xd0{}",
Integer.toHexString(opcode2));
break;
}
@@ -188,7 +188,7 @@ public class Lineage2PacketReader extends OneToOneDecoder {
case CM_ATTACK.OPCODE:
return CM_ATTACK.class;
default:
logger.warn("Unknown opcode: 0x{}", Integer.toHexString(opcode));
logger.warn("Unknown packet for 0x{}", Integer.toHexString(opcode));
break;
}
return null;

View File

@@ -53,7 +53,7 @@ public class Lineage2PacketWriter extends OneToOneEncoder {
final ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(
ByteOrder.LITTLE_ENDIAN, 10);
final ServerPacket packet = (ServerPacket) msg;
buffer.writeShort(0);
buffer.writeShort(0); // wrap 2 bytes for packet length
buffer.writeByte(packet.getOpcode()); // packet opcode
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.service.game.chat.CannotChatToSelfChatServiceException;
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.ChatTargetOfflineServiceException;
import com.l2jserver.service.game.chat.TargetNotFoundChatServiceException;
@@ -50,7 +50,7 @@ public class CM_CHAT extends AbstractClientPacket {
private final ChatService chatService;
private String message;
private ChatMessageDestination destination;
private ChatMessageType destination;
private String target;
@@ -62,8 +62,8 @@ public class CM_CHAT extends AbstractClientPacket {
@Override
public void read(Lineage2Client conn, ChannelBuffer buffer) {
this.message = BufferUtils.readString(buffer);
this.destination = ChatMessageDestination.fromID(buffer.readInt());
if (this.destination == ChatMessageDestination.TELL) { // private
this.destination = ChatMessageType.fromID(buffer.readInt());
if (this.destination == ChatMessageType.TELL) { // private
// message
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.model.world.Actor;
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;
/**
@@ -44,7 +44,7 @@ public class SM_CHAT extends AbstractServerPacket {
/**
* The message destination
*/
private ChatMessageDestination destination;
private ChatMessageType destination;
/**
* The message
*/
@@ -54,7 +54,7 @@ public class SM_CHAT extends AbstractServerPacket {
*/
private int messageID = 0;
public SM_CHAT(Actor character, ChatMessageDestination destination,
public SM_CHAT(Actor character, ChatMessageType destination,
String message) {
super(OPCODE);
this.actor = character;
@@ -62,7 +62,7 @@ public class SM_CHAT extends AbstractServerPacket {
this.message = message;
}
public SM_CHAT(Actor actor, ChatMessageDestination destination,
public SM_CHAT(Actor actor, ChatMessageType destination,
int messageID) {
super(OPCODE);
this.actor = actor;

View File

@@ -18,6 +18,7 @@ package com.l2jserver.game.net.packet.server;
import org.jboss.netty.buffer.ChannelBuffer;
import com.google.common.base.Preconditions;
import com.l2jserver.game.net.Lineage2Client;
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 SM_GG_QUERY() {
super(OPCODE);
private final int[] key;
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
public void write(Lineage2Client conn, ChannelBuffer buffer) {
buffer.writeInt(0x27533DD9);
buffer.writeInt(0x2E72A51D);
buffer.writeInt(0x2017038B);
buffer.writeInt(0xC35B1EA3);
for (final int part : key) {
buffer.writeInt(part);
}
}
}

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.character.CharacterService;
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.DatabaseChatLoggingService;
import com.l2jserver.service.game.chat.SimpleChatService;
import com.l2jserver.service.game.map.pathing.MapperPathingService;
import com.l2jserver.service.game.map.pathing.PathingService;
@@ -104,6 +106,8 @@ public class ServiceModule extends AbstractModule {
bind(ChatService.class).to(SimpleChatService.class)
.in(Scopes.SINGLETON);
bind(ChatLoggingService.class).to(DatabaseChatLoggingService.class).in(
Scopes.SINGLETON);
bind(AdministratorService.class).to(AdministratorServiceImpl.class).in(
Scopes.SINGLETON);
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>
*/
public class TruncateToZipFileAppender extends FileAppender {
/**
* 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;
/**
* The database service implementation for MySQL database
* The database service implementation for JDBC database
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
@@ -325,6 +325,7 @@ public class JDBCDatabaseService extends AbstractService implements
this.iterator = iterator;
}
@SuppressWarnings("unchecked")
@Override
public Integer query(Connection conn) throws SQLException {
Preconditions.checkNotNull(conn, "conn");
@@ -336,15 +337,17 @@ public class JDBCDatabaseService extends AbstractService implements
rows += st.executeUpdate();
// update object desire --it has been realized
if (object instanceof Model)
if (object instanceof Model) {
((Model<?>) object).setObjectDesire(ObjectDesire.NONE);
final Mapper<T> mapper = keyMapper(object);
if (mapper == null)
continue;
final ResultSet rs = st.getGeneratedKeys();
while (rs.next()) {
mapper.map(rs);
final Mapper<? extends ID<?>> mapper = keyMapper();
if (mapper == null)
continue;
final ResultSet rs = st.getGeneratedKeys();
while (rs.next()) {
((Model<ID<?>>) object).setID(mapper.map(rs));
mapper.map(rs);
}
}
}
return rows;
@@ -377,7 +380,7 @@ public class JDBCDatabaseService extends AbstractService implements
* the object
* @return the key mapper
*/
protected Mapper<T> keyMapper(T object) {
protected Mapper<? extends ID<?>> keyMapper() {
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_TARGET;
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.ActorState;
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.chat.ChatChannel;
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.npc.NPCService;
import com.l2jserver.service.game.npc.NotAttackableNPCServiceException;
@@ -148,18 +149,16 @@ public class CharacterServiceImpl extends AbstractService implements
// chat listener
final ChatChannelListener globalChatListener = new ChatChannelListener() {
@Override
public void onMessage(ChatChannel channel, CharacterID source,
String message) {
conn.write(new SM_CHAT(source.getObject(),
ChatMessageDestination.ALL, message));
public void onMessage(ChatChannel channel, ChatMessage message) {
conn.write(new SM_CHAT(message.getSender().getObject(),
ChatMessageType.ALL, message.getMessage()));
}
};
final ChatChannelListener tradeChatListener = new ChatChannelListener() {
@Override
public void onMessage(ChatChannel channel, CharacterID source,
String message) {
conn.write(new SM_CHAT(source.getObject(),
ChatMessageDestination.TRADE, message));
public void onMessage(ChatChannel channel, ChatMessage message) {
conn.write(new SM_CHAT(message.getSender().getObject(),
ChatMessageType.TRADE, message.getMessage()));
}
};
@@ -205,7 +204,7 @@ public class CharacterServiceImpl extends AbstractService implements
// start broadcasting -- will broadcast all nearby objects
broadcastService.broadcast(conn);
conn.write(new SM_ITEM_GROUND());
// characters start in run mode

View File

@@ -17,6 +17,7 @@
package com.l2jserver.service.game.chat;
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.
@@ -29,7 +30,10 @@ import com.l2jserver.model.id.object.CharacterID;
*/
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
* the character sending the message
@@ -40,8 +44,10 @@ public interface ChatChannel {
* @throws ChatTargetOfflineServiceException
* if the target is offline. Will be be thrown in
* {@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,
ChatTargetOfflineServiceException;
@@ -61,4 +67,19 @@ public interface ChatChannel {
* the 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;
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
@@ -30,10 +30,8 @@ public interface ChatChannelListener {
*
* @param channel
* the chat channel
* @param source
* the character sending this message
* @param 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;
/**
* Enumeration of all possible message destinations
* Enumeration of all possible message types
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public enum ChatMessageDestination {
public enum ChatMessageType {
/**
* Everyone
*/
@@ -63,12 +63,12 @@ public enum ChatMessageDestination {
public final int id;
ChatMessageDestination(int id) {
ChatMessageType(int id) {
this.id = id;
}
public static ChatMessageDestination fromID(int id) {
for (final ChatMessageDestination dest : values()) {
public static ChatMessageType fromID(int id) {
for (final ChatMessageType dest : values()) {
if (dest.id == id)
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.ClanID;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.Service;
/**
* This service chatting in the server. Implementations can be local or can use
* another service like an IRC server.
* This service provides chatting in the server. Implementations can be local or
* can use another service like an IRC server.
*
* @author <a href="http://www.rogiel.com">Rogiel</a>
*/
public interface ChatService extends Service {
/**
* Sends a message to a public chat channel.
* <p>
* Messages sent will be automatically logged using
* {@link ChatLoggingService}.
*
* @param sender
* the sender
@@ -47,8 +51,10 @@ public interface ChatService extends Service {
* if there is chat ban active
* @throws ChatTargetOfflineServiceException
* 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,
CannotChatToSelfChatServiceException,
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.model.id.object.CharacterID;
import com.l2jserver.model.id.object.ClanID;
import com.l2jserver.model.server.ChatMessage;
import com.l2jserver.model.world.Clan;
import com.l2jserver.model.world.L2Character;
import com.l2jserver.service.AbstractService;
@@ -40,6 +41,8 @@ import com.l2jserver.util.factory.CollectionFactory;
*/
// @Depends(RegionService.class)
public class SimpleChatService extends AbstractService implements ChatService {
private final ChatLoggingService chatLoggingService;
/**
* The {@link RegionService}
*/
@@ -83,7 +86,9 @@ public class SimpleChatService extends AbstractService implements ChatService {
* the region service
*/
@Inject
public SimpleChatService(CharacterDAO charDao) {
public SimpleChatService(ChatLoggingService chatLogService,
CharacterDAO charDao) {
this.chatLoggingService = chatLogService;
// this.regionService = regionService;
this.regionService = null;
this.charDao = charDao;
@@ -100,11 +105,11 @@ public class SimpleChatService extends AbstractService implements ChatService {
}
@Override
public void send(CharacterID sender, ChatMessageDestination chat,
String message, String extra)
throws TargetNotFoundChatServiceException,
public ChatMessage send(CharacterID sender, ChatMessageType chat, String message,
String extra) throws TargetNotFoundChatServiceException,
CannotChatToSelfChatServiceException,
ChatBanActiveChatServiceException, ChatTargetOfflineServiceException {
ChatBanActiveChatServiceException,
ChatTargetOfflineServiceException {
Preconditions.checkNotNull(sender, "sender");
Preconditions.checkNotNull(message, "message");
@@ -131,9 +136,9 @@ public class SimpleChatService extends AbstractService implements ChatService {
channel = getAnnouncementChannel();
break;
default:
return;
return null;
}
channel.send(sender, message);
return channel.send(sender, message);
}
@Override
@@ -210,13 +215,20 @@ public class SimpleChatService extends AbstractService implements ChatService {
.newSet();
@Override
public void send(CharacterID sender, String message) {
public ChatMessage send(CharacterID sender, String textMessage) {
Preconditions.checkNotNull(sender, "sender");
Preconditions.checkNotNull(message, "message");
Preconditions.checkNotNull(textMessage, "message");
// 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) {
listener.onMessage(this, sender, message);
listener.onMessage(this, message);
}
return message;
}
@Override
@@ -230,6 +242,16 @@ public class SimpleChatService extends AbstractService implements ChatService {
Preconditions.checkNotNull(listener, "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() {
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
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
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
PublicChatChannel {
@Override
public ChatMessageType getMessageType() {
return ChatMessageType.ANNOUNCEMENT;
}
}
/**
@@ -301,6 +345,11 @@ public class SimpleChatService extends AbstractService implements ChatService {
Preconditions.checkNotNull(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");
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
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")
private static final byte[] VALID_KEY_SHA1 = { (byte) 0x88, 0x40, 0x1c,
(byte) 0xa7, (byte) 0x83, 0x42, (byte) 0xe9, 0x15, (byte) 0xde,
(byte) 0xc3, 0x68, (byte) 0xf6, 0x2d, 0x23, (byte) 0xf1, 0x3f,
(byte) 0xee, 0x68, 0x5b, (byte) 0xc5 };
private static final byte[] STATIC_KEY_VALIDATION = { (byte) 0x88, 0x40,
0x1c, (byte) 0xa7, (byte) 0x83, 0x42, (byte) 0xe9, 0x15,
(byte) 0xde, (byte) 0xc3, 0x68, (byte) 0xf6, 0x2d, 0x23,
(byte) 0xf1, 0x3f, (byte) 0xee, 0x68, 0x5b, (byte) 0xc5 };
/**
* The map containing all pending futures
@@ -75,15 +81,16 @@ public class GameGuardServiceImpl extends AbstractService implements
@Override
public Future<GameGuardResponse> query(final Lineage2Client conn) {
conn.write(new SM_GG_QUERY()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
if (future.getCause() != null) {
futures.remove(conn);
}
}
});
conn.write(new SM_GG_QUERY(STATIC_KEY)).addListener(
new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
if (future.getCause() != null) {
futures.remove(conn);
}
}
});
final GGFuture future = new GGFuture();
futures.put(conn, future);
return future;

View File

@@ -50,7 +50,8 @@ public class SecureBlowfishKeygenService extends AbstractService implements
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[9] = (byte) 0x27;
key[10] = (byte) 0x93;