diff --git a/src/intents/PlayerEventIntent.java b/src/intents/PlayerEventIntent.java index 47b5fd02c..c854ee93e 100644 --- a/src/intents/PlayerEventIntent.java +++ b/src/intents/PlayerEventIntent.java @@ -10,6 +10,7 @@ public class PlayerEventIntent extends Intent { private Player player; private PlayerEvent event; + private String galaxy; public PlayerEventIntent(Player p, PlayerEvent event) { super(TYPE); @@ -17,6 +18,11 @@ public class PlayerEventIntent extends Intent { setEvent(event); } + public PlayerEventIntent(Player p, String galaxy, PlayerEvent event) { + this(p, event); + this.galaxy = galaxy; + } + public void setPlayer(Player p) { this.player = p; } @@ -33,4 +39,7 @@ public class PlayerEventIntent extends Intent { return event; } + public String getGalaxy() { + return galaxy; + } } diff --git a/src/intents/chat/PersistentMessageIntent.java b/src/intents/chat/PersistentMessageIntent.java new file mode 100644 index 000000000..76221e34c --- /dev/null +++ b/src/intents/chat/PersistentMessageIntent.java @@ -0,0 +1,24 @@ +package intents.chat; + +import resources.control.Intent; +import resources.encodables.player.Mail; +import resources.objects.SWGObject; + +public class PersistentMessageIntent extends Intent { + public static final String TYPE = "PersistentMessageIntent"; + + private Mail mail; + private SWGObject receiver; + private String galaxy; + + public PersistentMessageIntent(SWGObject receiver, Mail mail, String galaxy) { + super(TYPE); + this.receiver = receiver; + this.mail = mail; + this.galaxy = galaxy; + } + + public Mail getMail() { return this.mail; } + public SWGObject getReceiver() { return this.receiver; } + public String getGalaxy() { return this.galaxy; } +} diff --git a/src/resources/encodables/player/Mail.java b/src/resources/encodables/player/Mail.java new file mode 100644 index 000000000..7aac6ee40 --- /dev/null +++ b/src/resources/encodables/player/Mail.java @@ -0,0 +1,74 @@ +package resources.encodables.player; + +import resources.network.BaselineBuilder.Encodable; + +public class Mail implements Encodable { + private static final long serialVersionUID = 1L; + + private int id; + private String sender; + private long receiverId; + private String subject; + private String message; + private byte status; + private int timestamp; + // TODO: Waypoint attachments + + public static final byte NEW = 0x4E; + public static final byte READ = 0x52; + public static final byte UNREAD = 0x55; + + public Mail(String sender, String subject, String message, long receiverId) { + this.sender = sender; + this.subject = subject; + this.message = message; + this.receiverId = receiverId; + this.status = NEW; + } + + @Override + public byte[] encode() { + // TODO Auto-generated method stub + return null; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getSender() { + return sender; + } + + public long getReceiverId() { + return receiverId; + } + + public String getSubject() { + return subject; + } + + public String getMessage() { + return message; + } + + public byte getStatus() { + return status; + } + + public void setStatus(byte status) { + this.status = status; + } + + public int getTimestamp() { + return timestamp; + } + + public void setTimestamp(int timestamp) { + this.timestamp = timestamp; + } +} diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java index e7735deb1..3dfd859de 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -1,30 +1,58 @@ package services.chat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + import intents.GalacticPacketIntent; +import intents.PlayerEventIntent; +import intents.chat.PersistentMessageIntent; import intents.chat.SpatialChatIntent; import network.packets.Packet; import network.packets.swg.zone.ChatRequestRoomList; +import network.packets.swg.zone.chat.ChatDeletePersistentMessage; import network.packets.swg.zone.chat.ChatInstantMessageToCharacter; import network.packets.swg.zone.chat.ChatInstantMessageToClient; import network.packets.swg.zone.chat.ChatOnSendInstantMessage; +import network.packets.swg.zone.chat.ChatOnSendPersistentMessage; +import network.packets.swg.zone.chat.ChatPersistentMessageToClient; +import network.packets.swg.zone.chat.ChatPersistentMessageToServer; +import network.packets.swg.zone.chat.ChatRequestPersistentMessage; import network.packets.swg.zone.object_controller.ObjectController; import network.packets.swg.zone.object_controller.SpatialChat; import resources.control.Intent; import resources.control.Service; +import resources.encodables.player.Mail; import resources.objects.SWGObject; import resources.player.Player; +import resources.server_info.ObjectDatabase; +import resources.server_info.ObjectDatabase.Traverser; import services.player.PlayerManager; public class ChatService extends Service { + private ObjectDatabase mails; + private int maxMailId; + public ChatService() { - + mails = new ObjectDatabase("odb/mails.db"); + maxMailId = 1; } @Override public boolean initialize() { registerForIntent(GalacticPacketIntent.TYPE); registerForIntent(SpatialChatIntent.TYPE); + registerForIntent(PersistentMessageIntent.TYPE); + registerForIntent(PlayerEventIntent.TYPE); + mails.loadToCache(); + mails.traverse(new Traverser() { + @Override + public void process(Mail mail) { + if (mail.getId() >= maxMailId) + maxMailId = mail.getId() + 1; + } + }); return super.initialize(); } @@ -38,11 +66,30 @@ public class ChatService extends Service { handleChatRoomListRequest(player, (ChatRequestRoomList) p); else if (p instanceof ChatInstantMessageToCharacter) handleInstantMessage(((GalacticPacketIntent) i).getPlayerManager(), player, (ChatInstantMessageToCharacter) p); + else if (p instanceof ChatPersistentMessageToServer) + handleSendPersistentMessage(((GalacticPacketIntent) i).getPlayerManager(), player, + ((GalacticPacketIntent) i).getGalaxy().getName(), (ChatPersistentMessageToServer) p); + else if (p instanceof ChatRequestPersistentMessage) + handlePersistentMessageRequest(player, ((GalacticPacketIntent) i).getGalaxy().getName(), (ChatRequestPersistentMessage) p); + else if (p instanceof ChatDeletePersistentMessage) + deletePersistentMessage(((ChatDeletePersistentMessage) p).getMailId()); } } else if (i instanceof SpatialChatIntent) handleSpatialChat((SpatialChatIntent) i); - + else if (i instanceof PersistentMessageIntent) + handlePersistentMessageIntent((PersistentMessageIntent) i); + else if (i instanceof PlayerEventIntent) + handlePlayerEventIntent((PlayerEventIntent) i); + } + + private void handlePlayerEventIntent(PlayerEventIntent intent) { + switch(intent.getEvent()) { + case PE_ZONE_IN: + sendPersistentMessageHeaders(intent.getPlayer(), intent.getGalaxy()); + break; + default: break; + } } private void handleChatRoomListRequest(Player player, ChatRequestRoomList request) { @@ -95,4 +142,120 @@ public class ChatService extends Service { receiver.sendPacket(new ChatInstantMessageToClient(request.getGalaxy(), strSender, request.getMessage())); } + + private void handleSendPersistentMessage(PlayerManager playerMgr, Player sender, String galaxy, ChatPersistentMessageToServer request) { + + String recipientStr = request.getRecipient().toLowerCase(); + + if (recipientStr.contains(" ")) + recipientStr = recipientStr.split(" ")[0]; + + Player recipient = playerMgr.getPlayerByCreatureFirstName(recipientStr); + + long recId = (recipient == null ? playerMgr.getCharacterIdByName(request.getRecipient()) : recipient.getCreatureObject().getObjectId()); + + int errorCode = 0; + + if (recId == 0) + errorCode = 4; + + ChatOnSendPersistentMessage response = new ChatOnSendPersistentMessage(errorCode, request.getCounter()); + sender.sendPacket(response); + + Mail mail = new Mail(sender.getCreatureObject().getName(), request.getSubject(), request.getMessage(), recId); + mail.setId(maxMailId); + maxMailId++; + mail.setTimestamp((int) (new Date().getTime() / 1000)); + + mails.put(mail.getId(), mail); + + if (recipient != null) + sendPersistentMessage(recipient, mail, MailFlagType.HEADER_ONLY, galaxy); + } + + private void handlePersistentMessageIntent(PersistentMessageIntent intent) { + if (intent.getReceiver() == null) + return; + + Player recipient = intent.getReceiver().getOwner(); + + if (recipient == null) + return; + + Mail mail = intent.getMail(); + mail.setId(maxMailId); + maxMailId++; + mail.setTimestamp((int) (new Date().getTime() / 1000)); + + mails.put(mail.getId(), mail); + + sendPersistentMessage(recipient, mail, MailFlagType.HEADER_ONLY, intent.getGalaxy()); + } + + private void handlePersistentMessageRequest(Player player, String galaxy, ChatRequestPersistentMessage request) { + Mail mail = mails.get(request.getMailId()); + + if (mail == null) + return; + + if (mail.getReceiverId() != player.getCreatureObject().getObjectId()) + return; + + sendPersistentMessage(player, mail, MailFlagType.FULL_MESSAGE, galaxy); + } + + private void sendPersistentMessageHeaders(Player player, String galaxy) { + + if (player == null || player.getCreatureObject() == null) + return; + + final long receiverId = player.getCreatureObject().getObjectId(); + + final List playersMail = new ArrayList(); + + mails.traverse(new Traverser() { + @Override + public void process(Mail element) { + if (element.getReceiverId() == receiverId) + playersMail.add(element); + } + }); + + if (playersMail.isEmpty()) + return; + + for (Mail mail : playersMail) { sendPersistentMessage(player, mail, MailFlagType.HEADER_ONLY, galaxy); } + } + + private void sendPersistentMessage(Player receiver, Mail mail, MailFlagType requestType, String galaxy) { + if (receiver == null || receiver.getCreatureObject() == null) + return; + + ChatPersistentMessageToClient packet = null; + + switch(requestType) { + case FULL_MESSAGE: + packet = new ChatPersistentMessageToClient((byte) 0, mail.getSender(), galaxy, mail.getId(), mail.getSubject(), mail.getMessage(), mail.getTimestamp(), mail.getStatus()); + break; + + case HEADER_ONLY: + packet = new ChatPersistentMessageToClient((byte) 1, mail.getSender(), galaxy, mail.getId(), mail.getSubject(), "", mail.getTimestamp(), mail.getStatus()); + break; + + default: + packet = new ChatPersistentMessageToClient((byte) 1, mail.getSender(), galaxy, mail.getId(), mail.getSubject(), "", mail.getTimestamp(), mail.getStatus()); + break; + } + + receiver.sendPacket(packet); + } + + private void deletePersistentMessage(int mailId) { + mails.remove(mailId); + } + + private enum MailFlagType { + FULL_MESSAGE, + HEADER_ONLY; + } } diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index 2890279aa..e5593db21 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -1,6 +1,7 @@ package services.objects; import intents.GalacticPacketIntent; +import intents.PlayerEventIntent; import intents.swgobject_events.SWGObjectEventIntent; import java.util.ArrayList; @@ -37,6 +38,7 @@ import resources.objects.tangible.TangibleObject; import resources.objects.waypoint.WaypointObject; import resources.objects.weapon.WeaponObject; import resources.player.Player; +import resources.player.PlayerEvent; import resources.server_info.ObjectDatabase; import resources.server_info.ObjectDatabase.Traverser; import services.player.PlayerManager; @@ -109,7 +111,7 @@ public class ObjectManager extends Manager { if (i instanceof GalacticPacketIntent) { GalacticPacketIntent gpi = (GalacticPacketIntent) i; if (gpi.getPacket() instanceof SelectCharacter) { - zoneInCharacter(gpi.getPlayerManager(), gpi.getNetworkId(), ((SelectCharacter)gpi.getPacket()).getCharacterId()); + zoneInCharacter(gpi.getPlayerManager(), gpi.getGalaxy().getName(), gpi.getNetworkId(), ((SelectCharacter)gpi.getPacket()).getCharacterId()); } else if (gpi.getPacket() instanceof ObjectController) { ObjectController controller = (ObjectController) gpi.getPacket(); if (controller.getControllerData() instanceof DataTransform) { @@ -210,7 +212,7 @@ public class ObjectManager extends Manager { } } - private void zoneInCharacter(PlayerManager playerManager, long netId, long characterId) { + private void zoneInCharacter(PlayerManager playerManager, String galaxy, long netId, long characterId) { Player player = playerManager.getPlayerFromNetworkId(netId); if (player != null) { verifyPlayerObjectsSet(player, characterId); @@ -231,6 +233,7 @@ public class ObjectManager extends Manager { creature.clearAware(); moveObject(null, creature, creature.getLocation(), creature.getLocation()); updateAwarenessForObject(creature); + new PlayerEventIntent(player, galaxy, PlayerEvent.PE_ZONE_IN).broadcast(); } } diff --git a/src/services/player/LoginService.java b/src/services/player/LoginService.java index 60febea6c..187ccb9d0 100644 --- a/src/services/player/LoginService.java +++ b/src/services/player/LoginService.java @@ -111,6 +111,7 @@ public class LoginService extends Service { case "admin": player.setAccessLevel(AccessLevel.ADMIN); break; case "dev": player.setAccessLevel(AccessLevel.DEV); break; case "qa": player.setAccessLevel(AccessLevel.QA); break; + default: player.setAccessLevel(AccessLevel.PLAYER); break; } sendLoginSuccessPacket(player); System.out.println("LoginService: " + player.getUsername() + " has logged in."); @@ -160,6 +161,12 @@ public class LoginService extends Service { return getUser.executeQuery(); } + public ResultSet getCharacter(String character) throws SQLException { + PreparedStatement statement = getLocalDatabase().prepareStatement("SELECT * FROM characters WHERE lower(name) = ?"); + statement.setString(1, character.toLowerCase()); + return statement.executeQuery(); + } + private List getGalaxies(Player p) throws SQLException { Config c = getConfig(ConfigFile.PRIMARY); ResultSet set = getGalaxies.executeQuery(); diff --git a/src/services/player/PlayerManager.java b/src/services/player/PlayerManager.java index 604faa2e7..4421fc619 100644 --- a/src/services/player/PlayerManager.java +++ b/src/services/player/PlayerManager.java @@ -1,5 +1,7 @@ package services.player; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -87,6 +89,19 @@ public class PlayerManager extends Manager { return null; } + public long getCharacterIdByName(String name) { + try { + ResultSet result = loginService.getCharacter(name); + if (result.next()) { + return result.getLong(0); + } + } catch (SQLException e) { + e.printStackTrace(); + } + + return 0; + } + private Player transitionLoginToZone(final long networkId, final int galaxyId, ClientIdMsg clientId) { final byte [] nToken = clientId.getSessionToken(); synchronized (players) {