mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-10-10 00:13:42 -04:00
Second iteration of the chat refactor
This commit is contained in:
@@ -33,6 +33,7 @@ import resources.encodables.ProsePackage;
|
||||
import resources.player.Player;
|
||||
|
||||
public class ChatBroadcastIntent extends Intent {
|
||||
|
||||
public static final String TYPE = "ChatBroadcastIntent";
|
||||
|
||||
private BroadcastType broadcastType;
|
||||
@@ -53,26 +54,36 @@ public class ChatBroadcastIntent extends Intent {
|
||||
this(null, receiver, null, BroadcastType.PERSONAL);
|
||||
this.prose = prose;
|
||||
}
|
||||
|
||||
public ChatBroadcastIntent(String message, BroadcastType type) {
|
||||
this(message, null, null, type);
|
||||
}
|
||||
|
||||
public ChatBroadcastIntent(Player receiver, String message) {
|
||||
this(message, receiver, null, BroadcastType.PERSONAL);
|
||||
}
|
||||
public ChatBroadcastIntent(String message) {
|
||||
this(message, null, null, BroadcastType.GALAXY);
|
||||
|
||||
public BroadcastType getBroadcastType() {
|
||||
return broadcastType;
|
||||
}
|
||||
|
||||
public BroadcastType getBroadcastType() { return broadcastType; }
|
||||
public Player getBroadcaster() { return broadcaster; }
|
||||
public Terrain getTerrain() { return terrain; }
|
||||
public String getMessage() { return message; }
|
||||
public ProsePackage getProse() { return prose; }
|
||||
public Player getBroadcaster() {
|
||||
return broadcaster;
|
||||
}
|
||||
|
||||
public Terrain getTerrain() {
|
||||
return terrain;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public ProsePackage getProse() {
|
||||
return prose;
|
||||
}
|
||||
|
||||
public enum BroadcastType {
|
||||
AREA,
|
||||
PLANET,
|
||||
GALAXY,
|
||||
PERSONAL
|
||||
AREA, PLANET, GALAXY, PERSONAL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,60 +29,52 @@ package network.packets.swg.zone.chat;
|
||||
|
||||
import network.packets.swg.SWGPacket;
|
||||
import resources.chat.ChatAvatar;
|
||||
import resources.chat.ChatResult;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class ChatOnEnteredRoom extends SWGPacket {
|
||||
|
||||
public static final int CRC = getCrc("ChatOnEnteredRoom");
|
||||
|
||||
|
||||
private ChatAvatar avatar;
|
||||
private int result;
|
||||
private ChatResult result;
|
||||
private int chatRoomId;
|
||||
private int sequence;
|
||||
|
||||
public ChatOnEnteredRoom() {
|
||||
|
||||
}
|
||||
|
||||
public ChatOnEnteredRoom(ChatAvatar avatar, int chatRoomId, int sequence) {
|
||||
this.avatar = avatar;
|
||||
this.chatRoomId = chatRoomId;
|
||||
this.sequence = sequence;
|
||||
this(avatar, ChatResult.NONE, chatRoomId, sequence);
|
||||
}
|
||||
|
||||
public ChatOnEnteredRoom(ChatAvatar avatar, int result, int chatRoomId, int sequence) {
|
||||
|
||||
public ChatOnEnteredRoom(ChatAvatar avatar, ChatResult result, int chatRoomId, int sequence) {
|
||||
this.avatar = avatar;
|
||||
this.result = result;
|
||||
this.chatRoomId = chatRoomId;
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
|
||||
public ChatOnEnteredRoom(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
if (!super.decode(data, CRC))
|
||||
return;
|
||||
avatar = getEncodable(data, ChatAvatar.class);
|
||||
result = getInt(data);
|
||||
chatRoomId = getInt(data);
|
||||
sequence = getInt(data);
|
||||
avatar = getEncodable(data, ChatAvatar.class);
|
||||
result = ChatResult.fromInteger(getInt(data));
|
||||
chatRoomId = getInt(data);
|
||||
sequence = getInt(data);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer data = ByteBuffer.allocate(avatar.getSize() + 18);
|
||||
addShort(data, 5);
|
||||
addInt (data, CRC);
|
||||
addInt(data, CRC);
|
||||
addEncodable(data, avatar);
|
||||
addInt(data, result);
|
||||
addInt (data, chatRoomId);
|
||||
addInt (data, sequence);
|
||||
addInt(data, result.getCode());
|
||||
addInt(data, chatRoomId);
|
||||
addInt(data, sequence);
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setResult(int result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -26,160 +26,121 @@
|
||||
******************************************************************************/
|
||||
package resources.chat;
|
||||
|
||||
import network.packets.Packet;
|
||||
import resources.encodables.CachedEncode;
|
||||
import resources.encodables.Encodable;
|
||||
import resources.network.NetBuffer;
|
||||
import resources.network.NetBufferStream;
|
||||
import resources.persistable.Persistable;
|
||||
import resources.player.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Locale;
|
||||
|
||||
import services.CoreManager;
|
||||
|
||||
/**
|
||||
* @author Waverunner
|
||||
*/
|
||||
public class ChatAvatar implements Encodable, Persistable {
|
||||
|
||||
private long networkId;
|
||||
private final CachedEncode cache;
|
||||
|
||||
private Player player;
|
||||
private String name;
|
||||
private String game = "SWG";
|
||||
private String galaxy;
|
||||
|
||||
// Instances of the class will hardly ever change, so we can just pre-build the data.
|
||||
private transient byte[] data;
|
||||
private transient boolean modified;
|
||||
private transient int size = 0;
|
||||
|
||||
|
||||
public ChatAvatar() {
|
||||
modified = true;
|
||||
data = null;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public ChatAvatar(long networkId, String name, String galaxy) {
|
||||
this();
|
||||
this.networkId = networkId;
|
||||
this.name = name;
|
||||
this.galaxy = galaxy;
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
modified = true;
|
||||
data = null;
|
||||
size = 0;
|
||||
public ChatAvatar(Player player, String name) {
|
||||
this.cache = new CachedEncode(() -> encodeImpl());
|
||||
this.player = player;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
modified = true;
|
||||
this.cache.clearCached();
|
||||
}
|
||||
|
||||
public String getGame() {
|
||||
return game;
|
||||
}
|
||||
|
||||
public void setGame(String game) {
|
||||
this.game = game;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
|
||||
public String getGalaxy() {
|
||||
return galaxy;
|
||||
return getCoreGalaxy();
|
||||
}
|
||||
|
||||
public void setGalaxy(String galaxy) {
|
||||
this.galaxy = galaxy;
|
||||
modified = true;
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public long getNetworkId() {
|
||||
return networkId;
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
|
||||
private byte [] encodeImpl() {
|
||||
NetBuffer buffer = NetBuffer.allocate(getSize());
|
||||
buffer.addAscii("SWG");
|
||||
buffer.addAscii(getCoreGalaxy());
|
||||
buffer.addAscii(name);
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
if (size == 0)
|
||||
size = 6 + game.length() + name.length() + galaxy.length();
|
||||
|
||||
return size;
|
||||
return 9 + name.length() + getCoreGalaxy().length();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] encode() {
|
||||
if (!modified && data != null)
|
||||
return data;
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(getSize());
|
||||
Packet.addAscii(buffer, game);
|
||||
Packet.addAscii(buffer, galaxy);
|
||||
Packet.addAscii(buffer, name);
|
||||
|
||||
data = buffer.array();
|
||||
modified = false;
|
||||
|
||||
return data;
|
||||
return cache.encode();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuffer data) {
|
||||
game = Packet.getAscii(data);
|
||||
galaxy = Packet.getAscii(data);
|
||||
name = Packet.getAscii(data).toLowerCase(Locale.US);
|
||||
public void decode(ByteBuffer bb) {
|
||||
NetBuffer data = NetBuffer.wrap(bb);
|
||||
data.getAscii(); // SWG
|
||||
data.getAscii();
|
||||
name = data.getAscii().toLowerCase(Locale.US);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(NetBufferStream stream) {
|
||||
stream.addByte(0);
|
||||
stream.addAscii(galaxy);
|
||||
stream.addByte(1);
|
||||
stream.addAscii(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(NetBufferStream stream) {
|
||||
stream.getByte();
|
||||
galaxy = stream.getAscii();
|
||||
byte ver = stream.getByte();
|
||||
if (ver == 0)
|
||||
stream.getAscii();
|
||||
name = stream.getAscii();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChatAvatar[networkId=" + networkId +
|
||||
", name='" + name + '\'' + ", game='" + game + '\'' + ", galaxy='" + galaxy + "']";
|
||||
return String.format("ChatAvatar[name='%s']", name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null) return false;
|
||||
|
||||
if (getClass() != o.getClass())
|
||||
if (!(o instanceof ChatAvatar))
|
||||
return false;
|
||||
|
||||
// NetworkId will be 0 if decoded from a packet
|
||||
if (networkId != 0) return ((ChatAvatar) o).getNetworkId() == networkId;
|
||||
else return ((ChatAvatar) o).getName().equals(getName());
|
||||
return ((ChatAvatar) o).getName().equals(getName());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// NetworkId will be 0 if decoded from a packet
|
||||
int result = (networkId != 0 ? (int) (networkId ^ (networkId >>> 32)) : 0);
|
||||
result = 31 * result + name.hashCode();
|
||||
return result;
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
|
||||
public static ChatAvatar getFromPlayer(Player player) {
|
||||
return new ChatAvatar(player.getNetworkId(), player.getCharacterName().split(" ")[0].toLowerCase(Locale.US), CoreManager.getGalaxy().getName());
|
||||
return new ChatAvatar(player, player.getCharacterFirstName().toLowerCase(Locale.US));
|
||||
}
|
||||
|
||||
public static ChatAvatar getSystemAvatar(String galaxy) {
|
||||
return new ChatAvatar(-1, "system", galaxy);
|
||||
|
||||
public static ChatAvatar getSystemAvatar() {
|
||||
return new ChatAvatar(null, "system");
|
||||
}
|
||||
|
||||
private static String getCoreGalaxy() {
|
||||
return CoreManager.getGalaxy().getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,41 +27,51 @@
|
||||
|
||||
package resources.chat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Waverunner
|
||||
*/
|
||||
public enum ChatResult {
|
||||
NONE(-1), // The client will just display an "unknown error code" if this is used.
|
||||
SUCCESS(0),
|
||||
TARGET_AVATAR_DOESNT_EXIST(4),
|
||||
ROOM_INVALID_ID(5),
|
||||
ROOM_INVALID_NAME(6),
|
||||
CUSTOM_FAILURE(9),
|
||||
ROOM_AVATAR_BANNED(12),
|
||||
ROOM_PRIVATE(13),
|
||||
ROOM_AVATAR_NO_PERMISSION(16),
|
||||
IGNORED(23),
|
||||
ROOM_ALREADY_EXISTS(24),
|
||||
ROOM_ALREADY_JOINED(36),
|
||||
CHAT_SERVER_UNAVAILABLE(1000000),
|
||||
ROOM_DIFFERENT_FACTION(1000001),
|
||||
ROOM_NOT_GCW_DEFENDER_FACTION(1000005);
|
||||
|
||||
|
||||
NONE (-1), // The client will just display an "unknown error code" if this is used.
|
||||
SUCCESS (0),
|
||||
TARGET_AVATAR_DOESNT_EXIST (4),
|
||||
ROOM_INVALID_ID (5),
|
||||
ROOM_INVALID_NAME (6),
|
||||
CUSTOM_FAILURE (9),
|
||||
ROOM_AVATAR_BANNED (12),
|
||||
ROOM_PRIVATE (13),
|
||||
ROOM_AVATAR_NO_PERMISSION (16),
|
||||
IGNORED (23),
|
||||
ROOM_ALREADY_EXISTS (24),
|
||||
ROOM_ALREADY_JOINED (36),
|
||||
CHAT_SERVER_UNAVAILABLE (1000000),
|
||||
ROOM_DIFFERENT_FACTION (1000001),
|
||||
ROOM_NOT_GCW_DEFENDER_FACTION (1000005);
|
||||
|
||||
private static final Map<Integer, ChatResult> RESULT_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (ChatResult result : values()) {
|
||||
RESULT_MAP.put(result.getCode(), result);
|
||||
}
|
||||
}
|
||||
|
||||
private final int code;
|
||||
|
||||
ChatResult(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
public static ChatResult fromInteger(int code) {
|
||||
for (ChatResult result : ChatResult.values()) {
|
||||
if (code == result.getCode())
|
||||
return result;
|
||||
}
|
||||
return NONE;
|
||||
ChatResult result = RESULT_MAP.get(code);
|
||||
if (result == null)
|
||||
return NONE;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,7 @@ import network.packets.swg.zone.chat.ChatRoomMessage;
|
||||
import resources.encodables.Encodable;
|
||||
import resources.encodables.OutOfBandPackage;
|
||||
import resources.network.NetBufferStream;
|
||||
import resources.objects.player.PlayerObject;
|
||||
import resources.persistable.Persistable;
|
||||
import resources.player.Player;
|
||||
import services.player.PlayerManager;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -43,9 +41,6 @@ import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Waverunner
|
||||
*/
|
||||
public class ChatRoom implements Encodable, Persistable {
|
||||
|
||||
private int id;
|
||||
@@ -61,7 +56,7 @@ public class ChatRoom implements Encodable, Persistable {
|
||||
// Members are only actually apart of a room when they're "in the room", so we don't need to save this info
|
||||
// as each player will automatically re-join the room based on their joined channels list
|
||||
private transient List<ChatAvatar> members;
|
||||
|
||||
|
||||
// Large amount of data that's sent frequently, best if we can pre-encode everything and save it for later
|
||||
private transient boolean modified = true;
|
||||
private transient byte[] data;
|
||||
@@ -233,31 +228,17 @@ public class ChatRoom implements Encodable, Persistable {
|
||||
|
||||
public void sendMessage(ChatAvatar sender, String message, OutOfBandPackage oob, PlayerManager playerManager) {
|
||||
ChatRoomMessage chatRoomMessage = new ChatRoomMessage(sender, getId(), message, oob);
|
||||
|
||||
String senderName = sender.getName();
|
||||
for (ChatAvatar member : members) {
|
||||
Player player = playerManager.getPlayerFromNetworkId(member.getNetworkId());
|
||||
if (player == null)
|
||||
if (member.getPlayer().getPlayerObject().isIgnored(sender.getName()))
|
||||
continue;
|
||||
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
continue;
|
||||
|
||||
if (ghost.isIgnored(senderName))
|
||||
continue;
|
||||
|
||||
player.sendPacket(chatRoomMessage);
|
||||
|
||||
member.getPlayer().sendPacket(chatRoomMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendPacketToMembers(PlayerManager manager, SWGPacket... packets) {
|
||||
for (ChatAvatar member : members) {
|
||||
Player player = manager.getPlayerFromNetworkId(member.getNetworkId());
|
||||
if (player == null)
|
||||
continue;
|
||||
|
||||
player.sendPacket(packets);
|
||||
member.getPlayer().sendPacket(packets);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/************************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package resources.encodables;
|
||||
|
||||
public class CachedEncode {
|
||||
|
||||
private final EncodeOnly encodable;
|
||||
|
||||
private byte [] cached;
|
||||
|
||||
public CachedEncode(EncodeOnly encodable) {
|
||||
this.encodable = encodable;
|
||||
this.cached = null;
|
||||
}
|
||||
|
||||
public void clearCached() {
|
||||
this.cached = null;
|
||||
}
|
||||
|
||||
public byte[] encode() {
|
||||
if (cached == null)
|
||||
cached = encodable.encode();
|
||||
return cached;
|
||||
}
|
||||
|
||||
public interface EncodeOnly {
|
||||
byte [] encode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,9 +29,6 @@ package resources.encodables;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @author Waverunner
|
||||
*/
|
||||
public interface Encodable {
|
||||
byte [] encode();
|
||||
void decode(ByteBuffer data);
|
||||
|
||||
@@ -42,7 +42,6 @@ import resources.player.PlayerFlags;
|
||||
import utilities.Encoder.StringType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class PlayerObject extends IntangibleObject {
|
||||
@@ -279,37 +278,45 @@ public class PlayerObject extends IntangibleObject {
|
||||
sendDelta(8, 6, activeQuest);
|
||||
}
|
||||
|
||||
public void removeFriend(String friend) {
|
||||
play9.removeFriend(friend, this);
|
||||
public boolean addFriend(String friend) {
|
||||
return play9.addFriend(friend, this);
|
||||
}
|
||||
|
||||
public void addFriend(String friend) {
|
||||
play9.addFriend(friend, this);
|
||||
public boolean removeFriend(String friend) {
|
||||
return play9.removeFriend(friend, this);
|
||||
}
|
||||
|
||||
public boolean isFriend(String target) {
|
||||
return play9.isFriend(target);
|
||||
}
|
||||
|
||||
|
||||
public List<String> getFriendsList() {
|
||||
return play9.getFriendsList();
|
||||
}
|
||||
|
||||
public void addIgnored(String ignored) {
|
||||
play9.addIgnored(ignored, this);
|
||||
|
||||
public void sendFriendsList() {
|
||||
play9.sendFriendsList(this);
|
||||
}
|
||||
|
||||
public void removeIgnored(String ignored) {
|
||||
play9.removeIgnored(ignored, this);
|
||||
public boolean addIgnored(String ignored) {
|
||||
return play9.addIgnored(ignored, this);
|
||||
}
|
||||
|
||||
public boolean removeIgnored(String ignored) {
|
||||
return play9.removeIgnored(ignored, this);
|
||||
}
|
||||
|
||||
public boolean isIgnored(String target) {
|
||||
return play9.isIgnored(target);
|
||||
}
|
||||
|
||||
|
||||
public List<String> getIgnoreList() {
|
||||
return play9.getIgnoreList();
|
||||
}
|
||||
|
||||
public void sendIgnoreList() {
|
||||
play9.sendIgnoreList(this);
|
||||
}
|
||||
|
||||
public String getProfWheelPosition() {
|
||||
return play8.getProfWheelPosition();
|
||||
@@ -333,7 +340,7 @@ public class PlayerObject extends IntangibleObject {
|
||||
}
|
||||
|
||||
public List<String> getJoinedChannels() {
|
||||
return Collections.unmodifiableList(joinedChannels);
|
||||
return new ArrayList<>(joinedChannels);
|
||||
}
|
||||
|
||||
public boolean addJoinedChannel(String path) {
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
***********************************************************************************/
|
||||
package resources.objects.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import resources.collections.SWGList;
|
||||
import resources.collections.SWGSet;
|
||||
@@ -58,50 +60,70 @@ class PlayerObjectPrivateNP implements Persistable {
|
||||
|
||||
}
|
||||
|
||||
public void removeFriend(String friend, SWGObject target) {
|
||||
synchronized (friendsList) {
|
||||
friendsList.remove(friend);
|
||||
}
|
||||
friendsList.sendDeltaMessage(target);
|
||||
}
|
||||
|
||||
public void addFriend(String friend, SWGObject target) {
|
||||
public boolean addFriend(String friend, SWGObject target) {
|
||||
friend = friend.toLowerCase(Locale.US);
|
||||
synchronized (friendsList) {
|
||||
if (friendsList.contains(friend))
|
||||
return false;
|
||||
friendsList.add(friend);
|
||||
}
|
||||
friendsList.sendDeltaMessage(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeFriend(String friend, SWGObject target) {
|
||||
boolean changed;
|
||||
synchronized (friendsList) {
|
||||
changed = friendsList.remove(friend.toLowerCase(Locale.US));
|
||||
}
|
||||
friendsList.sendDeltaMessage(target);
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean isFriend(String friend) {
|
||||
synchronized (friendsList) {
|
||||
return friendsList.contains(friend);
|
||||
return friendsList.contains(friend.toLowerCase(Locale.US));
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getFriendsList() {
|
||||
return friendsList;
|
||||
return new ArrayList<>(friendsList);
|
||||
}
|
||||
|
||||
public void addIgnored(String ignored, SWGObject target) {
|
||||
public void sendFriendsList(SWGObject target) {
|
||||
friendsList.sendRefreshedListData(target);
|
||||
}
|
||||
|
||||
public boolean addIgnored(String ignored, SWGObject target) {
|
||||
ignored = ignored.toLowerCase(Locale.US);
|
||||
synchronized (ignoreList) {
|
||||
if (ignoreList.contains(ignored))
|
||||
return false;
|
||||
ignoreList.add(ignored);
|
||||
}
|
||||
ignoreList.sendDeltaMessage(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void removeIgnored(String ignored, SWGObject target) {
|
||||
public boolean removeIgnored(String ignored, SWGObject target) {
|
||||
boolean changed;
|
||||
synchronized (ignoreList) {
|
||||
ignoreList.remove(ignored);
|
||||
changed = ignoreList.remove(ignored.toLowerCase(Locale.US));
|
||||
}
|
||||
ignoreList.sendDeltaMessage(target);
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean isIgnored(String target) {
|
||||
return ignoreList.contains(target);
|
||||
return ignoreList.contains(target.toLowerCase(Locale.US));
|
||||
}
|
||||
|
||||
public List<String> getIgnoreList() {
|
||||
return ignoreList;
|
||||
return new ArrayList<>(ignoreList);
|
||||
}
|
||||
|
||||
public void sendIgnoreList(SWGObject target) {
|
||||
ignoreList.sendRefreshedListData(target);
|
||||
}
|
||||
|
||||
public void addDraftSchematic(String schematic, SWGObject target) {
|
||||
|
||||
@@ -125,6 +125,14 @@ public class Player implements Comparable<Player> {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getCharacterFirstName() {
|
||||
String name = getCharacterName();
|
||||
int spaceIndex = name.indexOf(' ');
|
||||
if (spaceIndex != -1)
|
||||
return name.substring(0, spaceIndex);
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
+120
-188
@@ -49,7 +49,7 @@ import network.packets.swg.zone.object_controller.SpatialChat;
|
||||
import resources.Terrain;
|
||||
import resources.chat.ChatAvatar;
|
||||
import resources.chat.ChatResult;
|
||||
import resources.collections.SWGList;
|
||||
import resources.control.Assert;
|
||||
import resources.control.Manager;
|
||||
import resources.encodables.OutOfBandPackage;
|
||||
import resources.encodables.ProsePackage;
|
||||
@@ -60,22 +60,20 @@ import resources.player.PlayerState;
|
||||
import resources.server_info.Log;
|
||||
import resources.server_info.RelationalServerData;
|
||||
import resources.server_info.RelationalServerFactory;
|
||||
import services.CoreManager;
|
||||
import services.player.PlayerManager;
|
||||
|
||||
public class ChatManager extends Manager {
|
||||
|
||||
|
||||
private final ChatRoomService roomService;
|
||||
private final ChatMailService mailService;
|
||||
private final RelationalServerData chatLogs;
|
||||
private final PreparedStatement insertChatLog;
|
||||
|
||||
|
||||
public ChatManager() {
|
||||
roomService = new ChatRoomService();
|
||||
mailService = new ChatMailService();
|
||||
chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db");
|
||||
insertChatLog = chatLogs.prepareStatement("INSERT INTO chat_log VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
|
||||
|
||||
addChildService(roomService);
|
||||
addChildService(mailService);
|
||||
|
||||
@@ -90,37 +88,31 @@ public class ChatManager extends Manager {
|
||||
Packet p = gpi.getPacket();
|
||||
if (!(p instanceof SWGPacket))
|
||||
return;
|
||||
SWGPacket swg = (SWGPacket) p;
|
||||
switch (swg.getPacketType()) {
|
||||
switch (((SWGPacket) p).getPacketType()) {
|
||||
case CHAT_INSTANT_MESSAGE_TO_CHARACTER:
|
||||
if (p instanceof ChatInstantMessageToCharacter)
|
||||
handleInstantMessage(gpi.getPlayerManager(), gpi.getPlayer(), (ChatInstantMessageToCharacter) p);
|
||||
handleInstantMessage(gpi.getPlayer(), (ChatInstantMessageToCharacter) p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handlePlayerEventIntent(PlayerEventIntent pei) {
|
||||
Player player = pei.getPlayer();
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
switch (pei.getEvent()) {
|
||||
case PE_FIRST_ZONE:
|
||||
updateChatAvatarStatus(player, true);
|
||||
updateChatAvatarStatus(pei.getPlayer(), true);
|
||||
break;
|
||||
case PE_LOGGED_OUT:
|
||||
if (player.getCreatureObject() == null)
|
||||
break;
|
||||
updateChatAvatarStatus(player, false);
|
||||
updateChatAvatarStatus(pei.getPlayer(), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleChatBroadcastIntent(ChatBroadcastIntent cbi) {
|
||||
switch(cbi.getBroadcastType()) {
|
||||
switch (cbi.getBroadcastType()) {
|
||||
case AREA:
|
||||
broadcastAreaMessage(cbi.getMessage(), cbi.getBroadcaster());
|
||||
logChat(cbi.getBroadcaster(), ChatType.SYSTEM, ChatRange.LOCAL, cbi.getMessage());
|
||||
@@ -134,19 +126,22 @@ public class ChatManager extends Manager {
|
||||
logChat(cbi.getBroadcaster(), ChatType.SYSTEM, ChatRange.GALAXY, cbi.getMessage());
|
||||
break;
|
||||
case PERSONAL:
|
||||
broadcastPersonalMessage(cbi.getProse(), cbi.getBroadcaster(), cbi.getMessage());
|
||||
logChat(cbi.getBroadcaster(), ChatType.SYSTEM, ChatRange.PERSONAL, cbi.getMessage());
|
||||
if (cbi.getProse() != null) {
|
||||
broadcastPersonalMessage(cbi.getBroadcaster(), cbi.getProse());
|
||||
logChat(cbi.getBroadcaster(), ChatType.SYSTEM, ChatRange.PERSONAL, "**OOB DATA**");
|
||||
} else {
|
||||
broadcastPersonalMessage(cbi.getBroadcaster(), cbi.getMessage());
|
||||
logChat(cbi.getBroadcaster(), ChatType.SYSTEM, ChatRange.PERSONAL, cbi.getMessage());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleChatAvatarRequestIntent(ChatAvatarRequestIntent cari) {
|
||||
switch (cari.getRequestType()) {
|
||||
case TARGET_STATUS: {
|
||||
Player player = cari.getPlayer();
|
||||
sendTargetAvatarStatus(player, new ChatAvatar(0, cari.getTarget(), CoreManager.getGalaxy().getName()));
|
||||
case TARGET_STATUS:
|
||||
sendTargetAvatarStatus(cari.getPlayer(), new ChatAvatar(cari.getPlayer(), cari.getTarget()));
|
||||
break;
|
||||
}
|
||||
case FRIEND_ADD_TARGET:
|
||||
handleAddFriend(cari.getPlayer(), cari.getTarget());
|
||||
break;
|
||||
@@ -156,237 +151,183 @@ public class ChatManager extends Manager {
|
||||
case FRIEND_LIST:
|
||||
handleRequestFriendList(cari.getPlayer());
|
||||
break;
|
||||
case IGNORE_REMOVE_TARGET:
|
||||
handleRemoveIgnored(cari.getPlayer(), cari.getTarget());
|
||||
break;
|
||||
case IGNORE_ADD_TARGET:
|
||||
handleAddIgnored(cari.getPlayer(), cari.getTarget());
|
||||
break;
|
||||
case IGNORE_REMOVE_TARGET:
|
||||
handleRemoveIgnored(cari.getPlayer(), cari.getTarget());
|
||||
break;
|
||||
case IGNORE_LIST:
|
||||
handleRequestIgnoreList(cari.getPlayer());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Friends List */
|
||||
|
||||
private void handleRequestFriendList(Player player) {
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return;
|
||||
|
||||
SWGList<String> friends = (SWGList<String>) ghost.getFriendsList();
|
||||
|
||||
friends.sendRefreshedListData(ghost);
|
||||
}
|
||||
|
||||
private void handleRemoveFriend(Player player, String target) {
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return;
|
||||
|
||||
if (!ghost.isFriend(target)) {
|
||||
sendSystemMessage(player, "@cmnty:friend_not_found", target);
|
||||
return;
|
||||
}
|
||||
|
||||
ghost.removeFriend(target);
|
||||
|
||||
sendSystemMessage(player, "@cmnty:friend_removed", target);
|
||||
}
|
||||
|
||||
|
||||
private void handleAddFriend(Player player, String target) {
|
||||
if (target.equalsIgnoreCase(player.getCharacterName().split(" ")[0]))
|
||||
if (target.equalsIgnoreCase(player.getCharacterFirstName()))
|
||||
return;
|
||||
|
||||
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return;
|
||||
|
||||
|
||||
if (ghost.isIgnored(target)) {
|
||||
sendSystemMessage(player, "@cmnty:friend_fail_is_ignored", target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ghost.isFriend(target)) {
|
||||
sendSystemMessage(player, "@cmnty:friend_duplicate", target);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!player.getPlayerManager().playerExists(target)) {
|
||||
sendSystemMessage(player, "@cmnty:friend_not_found", target);
|
||||
return;
|
||||
}
|
||||
|
||||
ghost.addFriend(target);
|
||||
sendSystemMessage(player, "@cmnty:friend_added", target);
|
||||
|
||||
player.sendPacket(new ChatFriendsListUpdate(new ChatAvatar(0, target, CoreManager.getGalaxy().getName()), true));
|
||||
}
|
||||
|
||||
/* Ignore List */
|
||||
|
||||
private void handleAddIgnored(Player player, String target) {
|
||||
if (target.equalsIgnoreCase(player.getCharacterName().split(" ")[0]))
|
||||
return;
|
||||
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return;
|
||||
|
||||
if (ghost.isIgnored(target)) {
|
||||
sendSystemMessage(player, "@cmnty:ignore_duplicate", target);
|
||||
|
||||
if (!ghost.addFriend(target)) {
|
||||
sendSystemMessage(player, "@cmnty:friend_duplicate", target);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sendSystemMessage(player, "@cmnty:friend_added", target);
|
||||
sendTargetAvatarStatus(player, new ChatAvatar(null, target));
|
||||
}
|
||||
|
||||
private void handleRemoveFriend(Player player, String target) {
|
||||
if (!player.getPlayerObject().removeFriend(target)) {
|
||||
sendSystemMessage(player, "@cmnty:friend_not_found", target);
|
||||
return;
|
||||
}
|
||||
|
||||
sendSystemMessage(player, "@cmnty:friend_removed", target);
|
||||
}
|
||||
|
||||
private void handleRequestFriendList(Player player) {
|
||||
player.getPlayerObject().sendFriendsList();
|
||||
}
|
||||
|
||||
/* Ignore List */
|
||||
|
||||
private void handleAddIgnored(Player player, String target) {
|
||||
if (target.equalsIgnoreCase(player.getCharacterFirstName()))
|
||||
return;
|
||||
|
||||
if (!player.getPlayerManager().playerExists(target)) {
|
||||
sendSystemMessage(player, "@cmnty:ignore_not_found", target);
|
||||
return;
|
||||
}
|
||||
|
||||
ghost.addIgnored(target);
|
||||
|
||||
player.getPlayerObject().removeFriend(target);
|
||||
|
||||
if (!player.getPlayerObject().addIgnored(target)) {
|
||||
sendSystemMessage(player, "@cmnty:ignore_duplicate", target);
|
||||
return;
|
||||
}
|
||||
|
||||
sendSystemMessage(player, "@cmnty:ignore_added", target);
|
||||
}
|
||||
|
||||
|
||||
private void handleRemoveIgnored(Player player, String target) {
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return;
|
||||
|
||||
if (!ghost.isIgnored(target)) {
|
||||
if (!player.getPlayerObject().removeIgnored(target)) {
|
||||
sendSystemMessage(player, "@cmnty:ignore_not_found", target);
|
||||
return;
|
||||
}
|
||||
|
||||
ghost.removeIgnored(target);
|
||||
|
||||
|
||||
sendSystemMessage(player, "@cmnty:ignore_removed", target);
|
||||
}
|
||||
|
||||
|
||||
private void handleRequestIgnoreList(Player player) {
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return;
|
||||
|
||||
SWGList<String> ignored = (SWGList<String>) ghost.getIgnoreList();
|
||||
|
||||
ignored.sendRefreshedListData(ghost);
|
||||
player.getPlayerObject().sendIgnoreList();
|
||||
}
|
||||
|
||||
|
||||
/* Misc */
|
||||
|
||||
|
||||
private void sendSystemMessage(Player player, String stringId, String target) {
|
||||
new ChatBroadcastIntent(player, new ProsePackage("StringId", stringId, "TT", target)).broadcast();
|
||||
}
|
||||
|
||||
|
||||
private void handleSpatialChatIntent(SpatialChatIntent spi) {
|
||||
Player sender = spi.getPlayer();
|
||||
SWGObject actor = sender.getCreatureObject();
|
||||
String senderName = sender.getCharacterFirstName();
|
||||
|
||||
// Send to self
|
||||
SpatialChat message = new SpatialChat(actor.getObjectId(), actor.getObjectId(), 0, spi.getMessage(), (short) spi.getChatType(), (short) spi.getMoodId());
|
||||
sender.sendPacket(message);
|
||||
logChat(sender, ChatType.SPATIAL, ChatRange.LOCAL, spi.getMessage());
|
||||
|
||||
String senderName = ChatAvatar.getFromPlayer(sender).getName();
|
||||
|
||||
|
||||
// Notify observers of the chat message
|
||||
for (Player owner : actor.getObservers()) {
|
||||
PlayerObject awareGhost = owner.getPlayerObject();
|
||||
if (!awareGhost.isIgnored(senderName))
|
||||
owner.sendPacket(new SpatialChat(owner.getCreatureObject().getObjectId(), message));
|
||||
if (owner.getPlayerObject().isIgnored(senderName))
|
||||
continue;
|
||||
owner.sendPacket(new SpatialChat(owner.getCreatureObject().getObjectId(), message));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInstantMessage(PlayerManager playerMgr, Player sender, ChatInstantMessageToCharacter request) {
|
||||
private void handleInstantMessage(Player sender, ChatInstantMessageToCharacter request) {
|
||||
String strReceiver = request.getCharacter().toLowerCase(Locale.ENGLISH);
|
||||
String strSender = sender.getCharacterName();
|
||||
String strSender = sender.getCharacterFirstName();
|
||||
|
||||
if (strSender.contains(" "))
|
||||
strSender = strSender.split(" ")[0];
|
||||
Player receiver = sender.getPlayerManager().getPlayerByCreatureFirstName(strReceiver);
|
||||
|
||||
Player receiver = playerMgr.getPlayerByCreatureFirstName(strReceiver);
|
||||
|
||||
int errorCode = 0; // 0 = No issue, 4 = "strReceiver is not online"
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
if (receiver == null || receiver.getPlayerState() != PlayerState.ZONED_IN)
|
||||
errorCode = 4;
|
||||
|
||||
if (errorCode != 4 && receiver.getPlayerObject() != null && receiver.getPlayerObject().isIgnored(strSender))
|
||||
errorCode = ChatResult.IGNORED.getCode();
|
||||
|
||||
sender.sendPacket(new ChatOnSendInstantMessage(errorCode, request.getSequence()));
|
||||
result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
|
||||
else if (receiver.getPlayerObject().isIgnored(strSender))
|
||||
result = ChatResult.IGNORED;
|
||||
|
||||
if (errorCode != 0)
|
||||
sender.sendPacket(new ChatOnSendInstantMessage(result.getCode(), request.getSequence()));
|
||||
|
||||
if (result != ChatResult.SUCCESS)
|
||||
return;
|
||||
|
||||
receiver.sendPacket(new ChatInstantMessageToClient(request.getGalaxy(), strSender, request.getMessage()));
|
||||
logChat(sender, receiver, ChatType.TELL, request.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/* Friends */
|
||||
|
||||
|
||||
private void updateChatAvatarStatus(Player player, boolean online) {
|
||||
PlayerManager playerManager = player.getPlayerManager();
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
String galaxy = CoreManager.getGalaxy().getName();
|
||||
|
||||
if (online) {
|
||||
PlayerObject playerObject = player.getPlayerObject();
|
||||
if (playerObject != null && playerObject.getFriendsList().size() <= 0) {
|
||||
for (String friend : playerObject.getFriendsList()) {
|
||||
sendTargetAvatarStatus(player, new ChatAvatar(0, friend, galaxy));
|
||||
}
|
||||
for (String friend : player.getPlayerObject().getFriendsList()) {
|
||||
sendTargetAvatarStatus(player, new ChatAvatar(null, friend));
|
||||
}
|
||||
}
|
||||
|
||||
final ChatFriendsListUpdate update = new ChatFriendsListUpdate(avatar, online);
|
||||
|
||||
playerManager.notifyPlayers(playerNotified -> {
|
||||
|
||||
String playerName = player.getCharacterFirstName().toLowerCase(Locale.US);
|
||||
player.getPlayerManager().notifyPlayers(playerNotified -> {
|
||||
if (playerNotified.getPlayerState() != PlayerState.ZONED_IN)
|
||||
return false;
|
||||
|
||||
PlayerObject playerObject = playerNotified.getPlayerObject();
|
||||
return playerObject != null && playerObject.getFriendsList().contains(update.getFriend().getName());
|
||||
|
||||
}, update);
|
||||
|
||||
return playerNotified.getPlayerObject().isFriend(playerName);
|
||||
}, new ChatFriendsListUpdate(new ChatAvatar(player, playerName), online));
|
||||
}
|
||||
|
||||
|
||||
private void sendTargetAvatarStatus(Player player, ChatAvatar target) {
|
||||
PlayerObject object = player.getPlayerObject();
|
||||
if (object == null)
|
||||
return;
|
||||
|
||||
Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target.getName());
|
||||
|
||||
boolean online = true;
|
||||
if (targetPlayer == null || targetPlayer.getPlayerState() != PlayerState.ZONED_IN)
|
||||
online = false;
|
||||
|
||||
player.sendPacket(new ChatFriendsListUpdate(target, online));
|
||||
}
|
||||
|
||||
private void broadcastAreaMessage(String message, Player broadcaster) {
|
||||
ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message);
|
||||
broadcaster.sendPacket(packet);
|
||||
|
||||
broadcaster.getCreatureObject().sendObservers(packet);
|
||||
player.sendPacket(new ChatFriendsListUpdate(target, targetPlayer != null && targetPlayer.getPlayerState() == PlayerState.ZONED_IN));
|
||||
}
|
||||
|
||||
|
||||
private void broadcastAreaMessage(String message, Player broadcaster) {
|
||||
broadcaster.getCreatureObject().sendObserversAndSelf(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message));
|
||||
}
|
||||
|
||||
private void broadcastPlanetMessage(String message, Terrain terrain) {
|
||||
ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message);
|
||||
new NotifyPlayersPacketIntent(packet, terrain, null).broadcast();
|
||||
new NotifyPlayersPacketIntent(packet, terrain).broadcast();
|
||||
}
|
||||
|
||||
|
||||
private void broadcastGalaxyMessage(String message) {
|
||||
ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message);
|
||||
new NotifyPlayersPacketIntent(packet).broadcast();
|
||||
}
|
||||
|
||||
private void broadcastPersonalMessage(ProsePackage prose, Player player, String message) {
|
||||
if (prose != null)
|
||||
player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, new OutOfBandPackage(prose)));
|
||||
else
|
||||
player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, message));
|
||||
private void broadcastPersonalMessage(Player player, String message) {
|
||||
player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, message));
|
||||
}
|
||||
|
||||
private void broadcastPersonalMessage(Player player, ProsePackage prose) {
|
||||
player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, new OutOfBandPackage(prose)));
|
||||
}
|
||||
|
||||
private void logChat(Player broadcaster, ChatType type, ChatRange range, String message) {
|
||||
@@ -414,8 +355,7 @@ public class ChatManager extends Manager {
|
||||
}
|
||||
|
||||
private void logChat(long sendId, String sendName, long recvId, String recvName, String type, String range, String room, String subject, String message) {
|
||||
if (message == null)
|
||||
return;
|
||||
Assert.notNull(message, "Message cannot be null!");
|
||||
try {
|
||||
synchronized (insertChatLog) {
|
||||
insertChatLog.setLong(1, System.currentTimeMillis());
|
||||
@@ -435,20 +375,12 @@ public class ChatManager extends Manager {
|
||||
}
|
||||
}
|
||||
|
||||
public static enum ChatType {
|
||||
MAIL,
|
||||
TELL,
|
||||
SYSTEM,
|
||||
SPATIAL,
|
||||
CHAT
|
||||
public enum ChatType {
|
||||
MAIL, TELL, SYSTEM, SPATIAL, CHAT
|
||||
}
|
||||
|
||||
public static enum ChatRange {
|
||||
PERSONAL,
|
||||
ROOM,
|
||||
LOCAL,
|
||||
TERRAIN,
|
||||
GALAXY
|
||||
public enum ChatRange {
|
||||
PERSONAL, ROOM, LOCAL, TERRAIN, GALAXY
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/************************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package services.chat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import resources.chat.ChatRoom;
|
||||
import resources.control.Assert;
|
||||
import resources.server_info.Log;
|
||||
|
||||
public class ChatRoomContainer {
|
||||
|
||||
private final Object mapMutex;
|
||||
private final Map<Integer, ChatRoom> idMap;
|
||||
private final Map<String, ChatRoom> pathMap;
|
||||
|
||||
public ChatRoomContainer() {
|
||||
this.mapMutex = new Object();
|
||||
this.idMap = new HashMap<>();
|
||||
this.pathMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public boolean addRoom(ChatRoom room) {
|
||||
Assert.notNull(room, "ChatRoom cannot be null!");
|
||||
Assert.test(room.getId() > 0, "ChatRoom ID must be > 0!");
|
||||
Assert.notNull(room.getPath(), "Path must not be null!");
|
||||
Assert.test(!room.getPath().isEmpty(), "Path must be non-empty!");
|
||||
Assert.test(room.getPath().startsWith("SWG."), "Path must start with \"SWG.\"!");
|
||||
synchronized (mapMutex) {
|
||||
ChatRoom overwrittenId = idMap.put(room.getId(), room);
|
||||
ChatRoom overwrittenPath = pathMap.put(room.getPath(), room);
|
||||
if (overwrittenId != null || overwrittenPath != null) {
|
||||
if (overwrittenId != overwrittenPath)
|
||||
Log.w("Internal maps in ChatRoomContainer are out of sync! ID and Path don't match for room: %s", room);
|
||||
if (overwrittenId != null)
|
||||
idMap.put(overwrittenId.getId(), overwrittenId);
|
||||
else
|
||||
idMap.put(overwrittenPath.getId(), overwrittenPath);
|
||||
if (overwrittenPath != null)
|
||||
pathMap.put(overwrittenPath.getPath(), overwrittenPath);
|
||||
else
|
||||
pathMap.put(overwrittenId.getPath(), overwrittenId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean destroyRoom(ChatRoom room) {
|
||||
Assert.notNull(room, "ChatRoom cannot be null!");
|
||||
synchronized (mapMutex) {
|
||||
boolean success = true;
|
||||
success = idMap.remove(room.getId()) != null && success;
|
||||
success = pathMap.remove(room.getPath()) != null && success;
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
public List<ChatRoom> getAllRooms() {
|
||||
synchronized (mapMutex) {
|
||||
return new ArrayList<>(idMap.values());
|
||||
}
|
||||
}
|
||||
|
||||
public ChatRoom getRoomById(int roomId) {
|
||||
Assert.test(roomId > 0, "Room ID must be > 0!");
|
||||
synchronized (mapMutex) {
|
||||
return idMap.get(roomId);
|
||||
}
|
||||
}
|
||||
|
||||
public ChatRoom getRoomByPath(String path) {
|
||||
Assert.notNull(path, "Path must not be null!");
|
||||
Assert.test(!path.isEmpty(), "Path must be non-empty!");
|
||||
Assert.test(path.startsWith("SWG."), "Path must start with \"SWG.\"!");
|
||||
synchronized (mapMutex) {
|
||||
return pathMap.get(path);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasRoomWithId(int roomId) {
|
||||
Assert.test(roomId > 0, "Room ID must be > 0!");
|
||||
synchronized (mapMutex) {
|
||||
return idMap.containsKey(roomId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasRoomWithPath(String path) {
|
||||
Assert.notNull(path, "Path must not be null!");
|
||||
Assert.test(!path.isEmpty(), "Path must be non-empty!");
|
||||
Assert.test(path.startsWith("SWG."), "Path must start with \"SWG.\"!");
|
||||
synchronized (mapMutex) {
|
||||
return pathMap.containsKey(path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
/************************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package services.chat;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import network.packets.swg.zone.chat.ChatOnDestroyRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnEnteredRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnLeaveRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnSendRoomMessage;
|
||||
import network.packets.swg.zone.insertion.ChatRoomList;
|
||||
import resources.chat.ChatAvatar;
|
||||
import resources.chat.ChatResult;
|
||||
import resources.chat.ChatRoom;
|
||||
import resources.client_info.ServerFactory;
|
||||
import resources.client_info.visitors.DatatableData;
|
||||
import resources.control.Assert;
|
||||
import resources.encodables.OutOfBandPackage;
|
||||
import resources.player.AccessLevel;
|
||||
import resources.player.Player;
|
||||
import resources.server_info.CachedObjectDatabase;
|
||||
import resources.server_info.Log;
|
||||
import resources.server_info.ObjectDatabase;
|
||||
import resources.server_info.RelationalServerData;
|
||||
import resources.server_info.RelationalServerFactory;
|
||||
import services.CoreManager;
|
||||
import services.chat.ChatManager.ChatRange;
|
||||
import services.chat.ChatManager.ChatType;
|
||||
|
||||
public class ChatRoomHandler {
|
||||
|
||||
private final ObjectDatabase<ChatRoom> database;
|
||||
private final ChatRoomContainer rooms;
|
||||
private final AtomicInteger maxChatRoomId;
|
||||
private final Object roomCreationMutex;
|
||||
|
||||
private RelationalServerData chatLogs;
|
||||
private PreparedStatement insertChatLog;
|
||||
|
||||
public ChatRoomHandler() {
|
||||
this.database = new CachedObjectDatabase<ChatRoom>("odb/chat_rooms.db", ChatRoom::create, (r, s) -> r.save(s));
|
||||
this.rooms = new ChatRoomContainer();
|
||||
this.maxChatRoomId = new AtomicInteger(0);
|
||||
this.roomCreationMutex = new Object();
|
||||
}
|
||||
|
||||
public boolean initialize() {
|
||||
database.load();
|
||||
database.traverse((room) -> {
|
||||
if (room.getId() >= maxChatRoomId.get())
|
||||
maxChatRoomId.set(room.getId());
|
||||
if (room.getOwner().equals(ChatAvatar.getSystemAvatar()))
|
||||
return;
|
||||
rooms.addRoom(room);
|
||||
});
|
||||
chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db");
|
||||
insertChatLog = chatLogs.prepareStatement("INSERT INTO chat_log VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
createSystemChannels();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean terminate() {
|
||||
database.save();
|
||||
database.close();
|
||||
chatLogs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void enterChatChannels(Player player) {
|
||||
for (String channel : player.getPlayerObject().getJoinedChannels()) {
|
||||
enterChatChannel(player, channel, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void enterPlanetaryChatChannels(Player player) {
|
||||
// Leave old zone-only chat channels
|
||||
for (String channel : new ArrayList<>(player.getPlayerObject().getJoinedChannels())) {
|
||||
if (channel.endsWith(".Planet") || channel.endsWith(".system")) {
|
||||
leaveChatChannel(player, channel);
|
||||
}
|
||||
}
|
||||
|
||||
// Enter the new zone-only chat channels
|
||||
String planetPath = "SWG." + player.getGalaxyName() + "." + player.getCreatureObject().getTerrain().getName() + ".";
|
||||
Assert.test(rooms.hasRoomWithPath(planetPath + "Planet"), "Planet chat does not exist! planetPath = " + planetPath);
|
||||
Assert.test(rooms.hasRoomWithPath(planetPath + "system"), "System chat does not exist! planetPath = " + planetPath);
|
||||
enterChatChannel(player, planetPath + "Planet", false);
|
||||
enterChatChannel(player, planetPath + "system", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to join the specified chat channel
|
||||
*
|
||||
* @param player Player joining the chat channel
|
||||
* @param room Chat room to enter
|
||||
*/
|
||||
public void enterChatChannel(Player player, ChatRoom room, int sequence, boolean ignoreInvitation) {
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
|
||||
ChatResult result = room.canJoinRoom(avatar, ignoreInvitation);
|
||||
if (player.getAccessLevel() != AccessLevel.PLAYER)
|
||||
result = ChatResult.SUCCESS;
|
||||
|
||||
Log.d("enterChatChannel user=%s player=%s room=%s result=%s", player.getUsername(), player.getCharacterName(), room.getPath(), result);
|
||||
if (result != ChatResult.SUCCESS) {
|
||||
player.sendPacket(new ChatOnEnteredRoom(avatar, result, room.getId(), sequence));
|
||||
return;
|
||||
}
|
||||
// TODO: Check if player is appropriate faction for the room (Rebel and imperial chat rooms)
|
||||
|
||||
// Server-based list so we can join chat channels automatically
|
||||
player.getPlayerObject().addJoinedChannel(room.getPath());
|
||||
|
||||
// Re-send the player the room list with just this room as it could have been public/hidden
|
||||
// This also "refreshes" the client, not sending this will cause a Chat channel unavailable message.
|
||||
if (!room.isPublic())
|
||||
player.sendPacket(new ChatRoomList(room));
|
||||
|
||||
// Notify players of success, it's ChatResult.SUCCESS at this point
|
||||
player.sendPacket(new ChatOnEnteredRoom(avatar, result, room.getId(), sequence));
|
||||
|
||||
// Notify everyone that a player entered the room
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnEnteredRoom(avatar, result, room.getId(), 0));
|
||||
|
||||
room.addMember(avatar);
|
||||
}
|
||||
|
||||
public void enterChatChannel(Player player, int id, int sequence) {
|
||||
ChatRoom room = rooms.getRoomById(id);
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnEnteredRoom(ChatAvatar.getFromPlayer(player), ChatResult.NONE, id, sequence));
|
||||
return;
|
||||
}
|
||||
enterChatChannel(player, room, sequence, false);
|
||||
}
|
||||
|
||||
public void enterChatChannel(Player player, String path, boolean ignoreInvitation) {
|
||||
ChatRoom room = rooms.getRoomByPath(path);
|
||||
if (room == null) {
|
||||
// Channel was not found, attempt to remove it from this players list of channels if it exists.
|
||||
// This can happen if a channel was deleted while the player was offline
|
||||
player.getPlayerObject().removeJoinedChannel(path);
|
||||
return;
|
||||
}
|
||||
enterChatChannel(player, room, 0, ignoreInvitation);
|
||||
}
|
||||
|
||||
public void leaveChatChannel(Player player, ChatRoom room, int sequence) {
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
|
||||
if (!room.removeMember(avatar) && !player.getPlayerObject().removeJoinedChannel(room.getPath()))
|
||||
return;
|
||||
|
||||
Log.d("leaveChatChannel user=%s player=%s room=%s", player.getUsername(), player.getCharacterName(), room.getPath());
|
||||
player.sendPacket(new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), sequence));
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), 0));
|
||||
}
|
||||
|
||||
public void leaveChatChannel(Player player, String path) {
|
||||
ChatRoom room = rooms.getRoomByPath(path);
|
||||
if (room == null)
|
||||
return;
|
||||
leaveChatChannel(player, room, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chat room with the specified address path. If the path's parent channel doesn't exist, then a new chat room is created with the same passed arguments.
|
||||
*
|
||||
* @param creator Room creator who will also become the owner of this room
|
||||
* @param isPublic Determines if the room should be publicly displayed in the channel listing
|
||||
* @param moderated Determines if the room should be moderated
|
||||
* @param path Address for the channel (Ex: SWG.serverName.Imperial)
|
||||
* @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy)
|
||||
* @param persist If true then this channel will be saved in an {@link ObjectDatabase}
|
||||
* @return {@link ChatRoom}
|
||||
*/
|
||||
public void createRoom(ChatAvatar creator, boolean isPublic, boolean moderated, String path, String title, boolean persist) {
|
||||
Assert.notNull(path, "Path cannot be empty!");
|
||||
Assert.test(!path.isEmpty(), "Path cannot be empty!");
|
||||
Assert.test(path.startsWith("SWG."+creator.getGalaxy()) && !path.equals("SWG."+creator.getGalaxy()), "Invalid path! " + path);
|
||||
|
||||
synchronized (roomCreationMutex) {
|
||||
if (rooms.getRoomByPath(path) != null)
|
||||
return;
|
||||
|
||||
// All paths should have parents, lets validate to make sure they exist first. Create them if they don't.
|
||||
// This chunk of code makes this function recursive
|
||||
int lastIndex = path.lastIndexOf('.', path.length());
|
||||
if (lastIndex != -1) {
|
||||
String parentPath = path.substring(0, lastIndex);
|
||||
if (!parentPath.equals("SWG."+creator.getGalaxy()))
|
||||
createRoom(creator, isPublic, false, parentPath, "", persist);
|
||||
}
|
||||
|
||||
ChatRoom room = new ChatRoom();
|
||||
room.setId(maxChatRoomId.incrementAndGet());
|
||||
room.setOwner(creator);
|
||||
room.setCreator(creator);
|
||||
room.setIsPublic(isPublic);
|
||||
room.setModerated(moderated);
|
||||
room.setPath(path);
|
||||
room.setTitle(title);
|
||||
room.addModerator(creator);
|
||||
rooms.addRoom(room);
|
||||
|
||||
if (persist)
|
||||
database.add(room);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessageToRoom(Player player, int roomId, int sequence, String message, OutOfBandPackage oobPackage) {
|
||||
sendMessageToRoom(player, rooms.getRoomById(roomId), sequence, message, oobPackage);;
|
||||
}
|
||||
|
||||
public void sendMessageToRoom(Player player, String path, int sequence, String message, OutOfBandPackage oobPackage) {
|
||||
sendMessageToRoom(player, rooms.getRoomByPath(path), sequence, message, oobPackage);;
|
||||
}
|
||||
|
||||
public void sendMessageToRoom(Player player, ChatRoom room, int sequence, String message, OutOfBandPackage oobPackage) {
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnSendRoomMessage(ChatResult.ROOM_INVALID_ID.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = room.canSendMessage(avatar);
|
||||
if (result == ChatResult.SUCCESS && message.length() > 512)
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
|
||||
player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), sequence));
|
||||
|
||||
if (result == ChatResult.SUCCESS) {
|
||||
room.sendMessage(avatar, message, oobPackage, player.getPlayerManager());
|
||||
logChat(player.getCreatureObject().getObjectId(), player.getCharacterName(), room.getId() + "/" + room.getPath(), message);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean notifyDestroyRoom(ChatAvatar destroyer, String roomPath, int sequence) {
|
||||
ChatRoom room;
|
||||
|
||||
synchronized (roomCreationMutex) {
|
||||
room = rooms.getRoomByPath(roomPath);
|
||||
if (room == null)
|
||||
return false;
|
||||
rooms.destroyRoom(room);
|
||||
}
|
||||
|
||||
// Send the ChatOnDestroyRoom packet to every else in the room besides the person destroying the packet
|
||||
ChatOnDestroyRoom packet = new ChatOnDestroyRoom(destroyer, ChatResult.SUCCESS.getCode(), room.getId(), 0);
|
||||
room.getMembers().forEach(member -> {
|
||||
if (!destroyer.equals(member))
|
||||
member.getPlayer().sendPacket(packet);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void createSystemChannels() {
|
||||
/**
|
||||
* Channel Notes
|
||||
* Group channels: created by System
|
||||
* SWG.serverName.group.GroupObjectId.GroupChat title = GroupId
|
||||
* Guild channels: created by System
|
||||
* SWG.serverName.guild.GuildId.GuildChat title = GuildId
|
||||
* City channels: created by System
|
||||
* SWG.serverName.city.CityId.CityChat title = CityId
|
||||
*/
|
||||
|
||||
String galaxy = CoreManager.getGalaxy().getName();
|
||||
ChatAvatar systemAvatar = ChatAvatar.getSystemAvatar();
|
||||
String basePath = "SWG." + galaxy + ".";
|
||||
|
||||
DatatableData rooms = ServerFactory.getDatatable("chat/default_rooms.iff");
|
||||
rooms.handleRows((r) -> {
|
||||
Log.d("Creating room: %s\t\t'%s'", basePath + rooms.getCell(r, 0), rooms.getCell(r, 1));
|
||||
createRoom(systemAvatar, true, false, basePath + rooms.getCell(r, 0), (String) rooms.getCell(r, 1), false);
|
||||
});
|
||||
|
||||
createPlanetChannels(systemAvatar, basePath);
|
||||
|
||||
/*
|
||||
* Battlefield Room path examples: SWG.Bria.corellia.battlefield SWG.Bria.corellia.battlefield.corellia_mountain_fortress.allFactions SWG.Bria.corellia.battlefield.corellia_pvp.allFactions / Imperial / Rebel SWG.Bria.corellia.battlefield.corellia_rebel_riverside_fort.allFactions
|
||||
*/
|
||||
}
|
||||
|
||||
private void createPlanetChannels(ChatAvatar systemAvatar, String basePath) {
|
||||
DatatableData planets = ServerFactory.getDatatable("chat/planets.iff");
|
||||
planets.handleRows((r) -> {
|
||||
String path = basePath + planets.getCell(r, 0) + ".";
|
||||
createRoom(systemAvatar, true, false, path + "Planet", "public chat for this planet, cannot create rooms here", false);
|
||||
createRoom(systemAvatar, true, false, path + "system", "system messages for this planet, cannot create rooms here", false);
|
||||
createRoom(systemAvatar, true, false, path + "Chat", "public chat for this planet, can create rooms here", false);
|
||||
});
|
||||
}
|
||||
|
||||
public ChatRoom getRoomById(int roomId) {
|
||||
return rooms.getRoomById(roomId);
|
||||
}
|
||||
|
||||
public ChatRoom getRoomByPath(String path) {
|
||||
return rooms.getRoomByPath(path);
|
||||
}
|
||||
|
||||
public List<ChatRoom> getRoomList(Player player) {
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
|
||||
List<ChatRoom> ret = new ArrayList<>();
|
||||
for (ChatRoom chatRoom : rooms.getAllRooms()) {
|
||||
if (!chatRoom.isPublic() && !chatRoom.isInvited(avatar) && !chatRoom.getOwner().equals(avatar))
|
||||
continue;
|
||||
ret.add(chatRoom);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void logChat(long sendId, String sendName, String room, String message) {
|
||||
try {
|
||||
synchronized (insertChatLog) {
|
||||
insertChatLog.setLong(1, System.currentTimeMillis());
|
||||
insertChatLog.setLong(2, sendId);
|
||||
insertChatLog.setString(3, sendName);
|
||||
insertChatLog.setLong(4, 0);
|
||||
insertChatLog.setString(5, "");
|
||||
insertChatLog.setString(6, ChatType.CHAT.name());
|
||||
insertChatLog.setString(7, ChatRange.ROOM.name());
|
||||
insertChatLog.setString(8, room);
|
||||
insertChatLog.setString(9, "");
|
||||
insertChatLog.setString(10, message);
|
||||
insertChatLog.executeUpdate();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
package services.chat;
|
||||
|
||||
import intents.NotifyPlayersPacketIntent;
|
||||
import intents.PlayerEventIntent;
|
||||
import intents.chat.ChatRoomUpdateIntent;
|
||||
import intents.network.GalacticPacketIntent;
|
||||
@@ -44,13 +43,10 @@ import network.packets.swg.zone.chat.ChatOnAddModeratorToRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnBanAvatarFromRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnCreateRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnDestroyRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnEnteredRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnInviteToRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnKickAvatarFromRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnLeaveRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnReceiveRoomInvitation;
|
||||
import network.packets.swg.zone.chat.ChatOnRemoveModeratorFromRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnSendRoomMessage;
|
||||
import network.packets.swg.zone.chat.ChatOnUnbanAvatarFromRoom;
|
||||
import network.packets.swg.zone.chat.ChatOnUninviteFromRoom;
|
||||
import network.packets.swg.zone.chat.ChatQueryRoom;
|
||||
@@ -62,53 +58,19 @@ import network.packets.swg.zone.chat.ChatSendToRoom;
|
||||
import network.packets.swg.zone.chat.ChatUnbanAvatarFromRoom;
|
||||
import network.packets.swg.zone.chat.ChatUninviteFromRoom;
|
||||
import network.packets.swg.zone.insertion.ChatRoomList;
|
||||
import resources.Terrain;
|
||||
import resources.chat.ChatAvatar;
|
||||
import resources.chat.ChatResult;
|
||||
import resources.chat.ChatRoom;
|
||||
import resources.client_info.ServerFactory;
|
||||
import resources.client_info.visitors.DatatableData;
|
||||
import resources.control.Assert;
|
||||
import resources.control.Service;
|
||||
import resources.objects.player.PlayerObject;
|
||||
import resources.player.AccessLevel;
|
||||
import resources.player.Player;
|
||||
import resources.server_info.CachedObjectDatabase;
|
||||
import resources.server_info.Log;
|
||||
import resources.server_info.ObjectDatabase;
|
||||
import resources.server_info.RelationalServerData;
|
||||
import resources.server_info.RelationalServerFactory;
|
||||
import resources.server_info.SynchronizedMap;
|
||||
import services.CoreManager;
|
||||
import services.chat.ChatManager.ChatRange;
|
||||
import services.chat.ChatManager.ChatType;
|
||||
import services.player.PlayerManager;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import resources.encodables.OutOfBandPackage;
|
||||
|
||||
/**
|
||||
* @author Waverunner
|
||||
*/
|
||||
public class ChatRoomService extends Service {
|
||||
|
||||
// Map to keep track of each player's recent message for a room to prevent duplicates from client
|
||||
private final ObjectDatabase<ChatRoom> database;
|
||||
private final Map<Integer, ChatRoom> roomMap;
|
||||
private final AtomicInteger maxChatRoomId;
|
||||
|
||||
private RelationalServerData chatLogs;
|
||||
private PreparedStatement insertChatLog;
|
||||
private final ChatRoomHandler chatRoomHandler;
|
||||
|
||||
public ChatRoomService() {
|
||||
database = new CachedObjectDatabase<ChatRoom>("odb/chat_rooms.db", ChatRoom::create, (r, s) -> r.save(s));
|
||||
roomMap = new SynchronizedMap<>();
|
||||
maxChatRoomId = new AtomicInteger(0);
|
||||
chatRoomHandler = new ChatRoomHandler();
|
||||
|
||||
registerForIntent(ChatRoomUpdateIntent.class, crui -> handleChatRoomUpdateIntent(crui));
|
||||
registerForIntent(GalacticPacketIntent.class, gpi -> handleGalacticPacketIntent(gpi));
|
||||
@@ -117,24 +79,12 @@ public class ChatRoomService extends Service {
|
||||
|
||||
@Override
|
||||
public boolean initialize() {
|
||||
database.load();
|
||||
database.traverse((room) -> {
|
||||
if (room.getId() >= maxChatRoomId.get())
|
||||
maxChatRoomId.set(room.getId());
|
||||
roomMap.put(room.getId(), room);
|
||||
});
|
||||
chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db");
|
||||
insertChatLog = chatLogs.prepareStatement("INSERT INTO chat_log VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
|
||||
createSystemChannels(CoreManager.getGalaxy().getName());
|
||||
return super.initialize();
|
||||
return super.initialize() && chatRoomHandler.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean terminate() {
|
||||
database.close();
|
||||
chatLogs.close();
|
||||
return super.terminate();
|
||||
return chatRoomHandler.terminate() && super.terminate();
|
||||
}
|
||||
|
||||
private void handleGalacticPacketIntent(GalacticPacketIntent gpi) {
|
||||
@@ -149,16 +99,13 @@ public class ChatRoomService extends Service {
|
||||
if (p instanceof ChatQueryRoom)
|
||||
handleChatQueryRoom(player, (ChatQueryRoom) p);
|
||||
break;
|
||||
case CHAT_ENTER_ROOM_BY_ID: {
|
||||
if (!(p instanceof ChatEnterRoomById))
|
||||
return;
|
||||
ChatEnterRoomById enterRoomById = (ChatEnterRoomById) p;
|
||||
enterChatChannel(player, enterRoomById.getRoomId(), enterRoomById.getSequence());
|
||||
case CHAT_ENTER_ROOM_BY_ID:
|
||||
if (p instanceof ChatEnterRoomById)
|
||||
chatRoomHandler.enterChatChannel(player, ((ChatEnterRoomById) p).getRoomId(), ((ChatEnterRoomById) p).getSequence());
|
||||
break;
|
||||
}
|
||||
case CHAT_REMOVE_AVATAR_FROM_ROOM:
|
||||
if (p instanceof ChatRemoveAvatarFromRoom)
|
||||
leaveChatChannel(player, ((ChatRemoveAvatarFromRoom) p).getPath());
|
||||
chatRoomHandler.leaveChatChannel(player, ((ChatRemoveAvatarFromRoom) p).getPath());
|
||||
break;
|
||||
case CHAT_SEND_TO_ROOM:
|
||||
if (p instanceof ChatSendToRoom)
|
||||
@@ -210,17 +157,10 @@ public class ChatRoomService extends Service {
|
||||
}
|
||||
|
||||
private void handlePlayerEventIntent(PlayerEventIntent pei) {
|
||||
Player player = pei.getPlayer();
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
switch (pei.getEvent()) {
|
||||
case PE_ZONE_IN_SERVER:
|
||||
enterPlanetaryChatChannels(player);
|
||||
break;
|
||||
case PE_FIRST_ZONE:
|
||||
if (player.getPlayerObject() != null)
|
||||
enterChatChannels(player, player.getPlayerObject().getJoinedChannels());
|
||||
case PE_ZONE_IN_CLIENT:
|
||||
chatRoomHandler.enterChatChannels(pei.getPlayer());
|
||||
chatRoomHandler.enterPlanetaryChatChannels(pei.getPlayer());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -230,19 +170,19 @@ public class ChatRoomService extends Service {
|
||||
private void handleChatRoomUpdateIntent(ChatRoomUpdateIntent crui) {
|
||||
switch (crui.getUpdateType()) {
|
||||
case CREATE:
|
||||
createRoom(crui.getAvatar(), crui.isPublic(), crui.getPath(), crui.getTitle());
|
||||
chatRoomHandler.createRoom(crui.getAvatar(), crui.isPublic(), false, crui.getPath(), crui.getTitle(), false);
|
||||
break;
|
||||
case DESTROY:
|
||||
notifyDestroyRoom(crui.getAvatar(), crui.getPath(), 0);
|
||||
chatRoomHandler.notifyDestroyRoom(crui.getAvatar(), crui.getPath(), 0);
|
||||
break;
|
||||
case JOIN:
|
||||
enterChatChannel(crui.getPlayer(), crui.getPath(), crui.isIgnoreInvitation());
|
||||
chatRoomHandler.enterChatChannel(crui.getPlayer(), crui.getPath(), crui.isIgnoreInvitation());
|
||||
break;
|
||||
case LEAVE:
|
||||
leaveChatChannel(crui.getPlayer(), crui.getPath());
|
||||
chatRoomHandler.leaveChatChannel(crui.getPlayer(), crui.getPath());
|
||||
break;
|
||||
case SEND_MESSAGE:
|
||||
sendMessageToRoom(crui.getPlayer(), getRoom(crui.getPath()), 0, crui.getMessage(), new OutOfBandPackage());
|
||||
chatRoomHandler.sendMessageToRoom(crui.getPlayer(), crui.getPath(), 0, crui.getMessage(), new OutOfBandPackage());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -252,307 +192,180 @@ public class ChatRoomService extends Service {
|
||||
/* Chat Rooms */
|
||||
|
||||
private void handleChatRemoveModeratorFromRoom(Player player, ChatRemoveModeratorFromRoom p) {
|
||||
String path = p.getRoom();
|
||||
ChatAvatar target = p.getAvatar();
|
||||
int sequence = p.getSequence();
|
||||
|
||||
ChatRoom room = getRoom(path);
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoom());
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.ROOM_INVALID_NAME.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_NAME;
|
||||
else if (!room.isModerated())
|
||||
result = ChatResult.CUSTOM_FAILURE;
|
||||
else if (!room.isModerator(sender))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
else if (!room.removeModerator(target))
|
||||
result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
|
||||
|
||||
if (!room.isModerated()) {
|
||||
player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.CUSTOM_FAILURE.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isModerator(sender)) {
|
||||
player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.removeModerator(target)) {
|
||||
player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.SUCCESS.getCode(), path, sequence));
|
||||
player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, result.getCode(), p.getRoom(), p.getSequence()));
|
||||
}
|
||||
|
||||
private void handleChatAddModeratorToRoom(Player player, ChatAddModeratorToRoom p) {
|
||||
String path = p.getRoom();
|
||||
ChatAvatar target = p.getAvatar();
|
||||
int sequence = p.getSequence();
|
||||
|
||||
ChatRoom room = getRoom(path);
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoom());
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.ROOM_INVALID_NAME.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isModerated()) {
|
||||
player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.CUSTOM_FAILURE.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isModerator(sender)) {
|
||||
player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target.getName());
|
||||
if (targetPlayer == null) {
|
||||
player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_NAME;
|
||||
else if (!room.isModerated())
|
||||
result = ChatResult.CUSTOM_FAILURE;
|
||||
else if (!room.isModerator(sender))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
else if (!room.removeModerator(target) || player.getPlayerManager().getPlayerByCreatureFirstName(target.getName()) == null)
|
||||
result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
|
||||
else if (room.addModerator(target))
|
||||
result = ChatResult.NONE;
|
||||
|
||||
if (room.removeBanned(target)) {
|
||||
// Remove player from the ban list for players that have joined the room, since this player is now a moderator
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnUnbanAvatarFromRoom(path, sender, target, ChatResult.SUCCESS.getCode(), 0));
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnUnbanAvatarFromRoom(p.getRoom(), sender, target, ChatResult.SUCCESS.getCode(), 0));
|
||||
}
|
||||
|
||||
if (!room.addModerator(target)) {
|
||||
player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.NONE.getCode(), path, sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.SUCCESS.getCode(), path, sequence));
|
||||
player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, result.getCode(), p.getRoom(), p.getSequence()));
|
||||
}
|
||||
|
||||
private void handleChatUnbanAvatarFromRoom(Player player, ChatUnbanAvatarFromRoom p) {
|
||||
String path = p.getRoom();
|
||||
ChatAvatar target = p.getAvatar();
|
||||
int sequence = p.getSequence();
|
||||
|
||||
ChatRoom room = getRoom(path);
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoom());
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnUnbanAvatarFromRoom(path, sender, target, ChatResult.ROOM_INVALID_NAME.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_NAME;
|
||||
else if (!room.isModerator(sender))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
else if (!room.isBanned(target) || !room.removeBanned(target))
|
||||
result = ChatResult.ROOM_AVATAR_BANNED;
|
||||
|
||||
if (!room.isModerator(sender)) {
|
||||
player.sendPacket(new ChatOnUnbanAvatarFromRoom(path, sender, target, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isBanned(target) || !room.removeBanned(target)) {
|
||||
player.sendPacket(new ChatOnUnbanAvatarFromRoom(path, sender, target, ChatResult.ROOM_AVATAR_BANNED.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnUnbanAvatarFromRoom(path, sender, target, ChatResult.SUCCESS.getCode(), sequence));
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnUnbanAvatarFromRoom(p.getRoom(), sender, target, result.getCode(), p.getSequence()));
|
||||
}
|
||||
|
||||
private void handleChatBanAvatarFromRoom(Player player, ChatBanAvatarFromRoom p) {
|
||||
String path = p.getRoom();
|
||||
ChatAvatar target = p.getAvatar();
|
||||
int sequence = p.getSequence();
|
||||
|
||||
ChatRoom room = getRoom(path);
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoom());
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnBanAvatarFromRoom(path, sender, target, ChatResult.ROOM_INVALID_NAME.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isModerator(sender)) {
|
||||
player.sendPacket(new ChatOnBanAvatarFromRoom(path, sender, target, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (room.isBanned(target)) {
|
||||
player.sendPacket(new ChatOnBanAvatarFromRoom(path, sender, target, ChatResult.ROOM_AVATAR_BANNED.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isMember(target)) {
|
||||
player.sendPacket(new ChatOnBanAvatarFromRoom(path, sender, target, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
if (room.isModerator(target))
|
||||
room.removeModerator(target);
|
||||
|
||||
if (room.isInvited(target))
|
||||
room.removeInvited(target);
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_NAME;
|
||||
else if (!room.isModerator(sender))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
else if (room.isBanned(target))
|
||||
result = ChatResult.ROOM_AVATAR_BANNED;
|
||||
else if (!room.isMember(target))
|
||||
result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
|
||||
|
||||
room.removeModerator(target);
|
||||
room.removeInvited(target);
|
||||
room.addBanned(target);
|
||||
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnBanAvatarFromRoom(path, sender, target, ChatResult.SUCCESS.getCode(), sequence));
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnBanAvatarFromRoom(p.getRoom(), sender, target, result.getCode(), p.getSequence()));
|
||||
}
|
||||
|
||||
private void handleChatKickAvatarFromRoom(Player player, ChatKickAvatarFromRoom p) {
|
||||
String path = p.getRoom();
|
||||
ChatAvatar target = p.getAvatar();
|
||||
|
||||
ChatRoom room = getRoom(path);
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoom());
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnKickAvatarFromRoom(target, sender, ChatResult.ROOM_INVALID_NAME.getCode(), path));
|
||||
return;
|
||||
}
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_NAME;
|
||||
else if (!room.isModerator(sender))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
else if (!room.isMember(target))
|
||||
result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
|
||||
else if (player.getPlayerManager().getPlayerByCreatureFirstName(target.getName()) == null)
|
||||
result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
|
||||
|
||||
if (!room.isModerator(sender)) {
|
||||
player.sendPacket(new ChatOnKickAvatarFromRoom(target, sender, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), path));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isMember(target)) {
|
||||
player.sendPacket(new ChatOnKickAvatarFromRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path));
|
||||
return;
|
||||
}
|
||||
|
||||
Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target.getName());
|
||||
if (targetPlayer == null) {
|
||||
player.sendPacket(new ChatOnKickAvatarFromRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path));
|
||||
return;
|
||||
}
|
||||
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnKickAvatarFromRoom(target, sender, ChatResult.SUCCESS.getCode(), path));
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnKickAvatarFromRoom(target, sender, result.getCode(), p.getRoom()));
|
||||
}
|
||||
|
||||
private void handleChatUninviteFromRoom(Player player, ChatUninviteFromRoom p) {
|
||||
String path = p.getRoom();
|
||||
ChatRoom room = getRoom(path);
|
||||
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoom());
|
||||
ChatAvatar invitee = p.getAvatar();
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.ROOM_INVALID_NAME.getCode(), p.getSequence()));
|
||||
return;
|
||||
}
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_NAME;
|
||||
else if (room.isPublic())
|
||||
result = ChatResult.CUSTOM_FAILURE;
|
||||
else if (!room.isModerator(sender))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
else if (!room.removeInvited(invitee))
|
||||
result = ChatResult.ROOM_PRIVATE;
|
||||
|
||||
if (room.isPublic()) {
|
||||
player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.CUSTOM_FAILURE.getCode(), p.getSequence()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isModerator(sender)) {
|
||||
player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), p.getSequence()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.removeInvited(invitee)) {
|
||||
player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.ROOM_PRIVATE.getCode(), p.getSequence()));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.SUCCESS.getCode(), p.getSequence()));
|
||||
player.sendPacket(new ChatOnUninviteFromRoom(p.getRoom(), sender, invitee, result.getCode(), p.getSequence()));
|
||||
}
|
||||
|
||||
private void handleChatInviteToRoom(Player player, ChatInviteAvatarToRoom p) {
|
||||
String path = p.getRoom();
|
||||
ChatRoom room = getRoom(path);
|
||||
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
if (room == null) {
|
||||
player.sendPacket(new ChatOnInviteToRoom(path, sender, p.getAvatar(), ChatResult.ROOM_INVALID_NAME.getCode()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (room.isPublic()) {
|
||||
player.sendPacket(new ChatOnInviteToRoom(path, sender, p.getAvatar(), ChatResult.CUSTOM_FAILURE.getCode()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!room.isModerator(sender)) {
|
||||
player.sendPacket(new ChatOnInviteToRoom(path, sender, p.getAvatar(), ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode()));
|
||||
return;
|
||||
}
|
||||
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoom());
|
||||
ChatAvatar invitee = p.getAvatar();
|
||||
ChatAvatar sender = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_NAME;
|
||||
else if (room.isPublic())
|
||||
result = ChatResult.CUSTOM_FAILURE;
|
||||
else if (!room.isModerator(sender))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
|
||||
Player invitedPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(invitee.getName());
|
||||
if (invitedPlayer == null) {
|
||||
player.sendPacket(new ChatOnInviteToRoom(path, sender, invitee, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode()));
|
||||
return;
|
||||
if (result == ChatResult.SUCCESS && invitedPlayer == null)
|
||||
result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
|
||||
|
||||
player.sendPacket(new ChatOnInviteToRoom(p.getRoom(), sender, invitee, result.getCode()));
|
||||
|
||||
if (result == ChatResult.SUCCESS) {
|
||||
room.addInvited(invitee);
|
||||
// Notify the invited client that the room exists if not already in the clients chat lists
|
||||
invitedPlayer.sendPacket(new ChatRoomList(room));
|
||||
invitedPlayer.sendPacket(new ChatOnReceiveRoomInvitation(sender, p.getRoom()));
|
||||
}
|
||||
|
||||
player.sendPacket(new ChatOnInviteToRoom(path, sender, invitee, ChatResult.SUCCESS.getCode()));
|
||||
|
||||
room.addInvited(invitee);
|
||||
|
||||
// Notify the invited client that the room exists if not already in the clients chat lists
|
||||
invitedPlayer.sendPacket(new ChatRoomList(room));
|
||||
|
||||
invitedPlayer.sendPacket(new ChatOnReceiveRoomInvitation(sender, path));
|
||||
}
|
||||
|
||||
private void handleChatDestroyRoom(Player player, ChatDestroyRoom p) {
|
||||
ChatRoom room = roomMap.get(p.getRoomId());
|
||||
ChatRoom room = chatRoomHandler.getRoomById(p.getRoomId());
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if ((room == null || !room.getCreator().equals(avatar) || !room.getOwner().equals(avatar))) {
|
||||
player.sendPacket(new ChatOnDestroyRoom(avatar, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), p.getRoomId(), p.getSequence()));
|
||||
return;
|
||||
}
|
||||
if ((room == null || !room.getCreator().equals(avatar) || !room.getOwner().equals(avatar)))
|
||||
result = ChatResult.ROOM_AVATAR_NO_PERMISSION;
|
||||
else if (!chatRoomHandler.notifyDestroyRoom(avatar, room.getPath(), p.getSequence()))
|
||||
result = ChatResult.NONE;
|
||||
|
||||
if (!notifyDestroyRoom(avatar, room.getPath(), p.getSequence())) {
|
||||
player.sendPacket(new ChatOnDestroyRoom(avatar, ChatResult.NONE.getCode(), p.getRoomId(), p.getSequence()));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendPacket(new ChatOnDestroyRoom(avatar, ChatResult.SUCCESS.getCode(), p.getRoomId(), p.getSequence()));
|
||||
player.sendPacket(new ChatOnDestroyRoom(avatar, result.getCode(), p.getRoomId(), p.getSequence()));
|
||||
}
|
||||
|
||||
private void handleChatCreateRoom(Player player, ChatCreateRoom p) {
|
||||
String path = p.getRoomName();
|
||||
String title = p.getRoomTitle();
|
||||
ChatRoom room = getRoom(path);
|
||||
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
if (room != null)
|
||||
|
||||
if (chatRoomHandler.getRoomByPath(path) != null)
|
||||
result = ChatResult.ROOM_ALREADY_EXISTS;
|
||||
else
|
||||
chatRoomHandler.createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), p.isModerated(), path, p.getRoomTitle(), true);
|
||||
|
||||
if (result == ChatResult.SUCCESS) {
|
||||
room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title, true);
|
||||
room.setModerated(p.isModerated());
|
||||
}
|
||||
|
||||
player.sendPacket(new ChatOnCreateRoom(result.getCode(), room, p.getSequence()));
|
||||
player.sendPacket(new ChatOnCreateRoom(result.getCode(), chatRoomHandler.getRoomByPath(path), p.getSequence()));
|
||||
}
|
||||
|
||||
private void handleChatSendToRoom(Player player, ChatSendToRoom p) {
|
||||
ChatRoom room = getRoom(p.getRoomId());
|
||||
sendMessageToRoom(player, room, p.getSequence(), p.getMessage(), p.getOutOfBandPackage());
|
||||
}
|
||||
|
||||
private void sendMessageToRoom(Player player, ChatRoom room, int sequence, String message, OutOfBandPackage outOfBandPackage) {
|
||||
ChatResult result = ChatResult.SUCCESS;
|
||||
|
||||
if (room == null)
|
||||
result = ChatResult.ROOM_INVALID_ID;
|
||||
|
||||
if (result != ChatResult.SUCCESS) {
|
||||
player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), sequence));
|
||||
return;
|
||||
}
|
||||
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
|
||||
result = room.canSendMessage(avatar);
|
||||
|
||||
// TODO: Check length of messages -- Result 16 is used for too long message
|
||||
|
||||
player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), sequence));
|
||||
|
||||
if (result == ChatResult.SUCCESS) {
|
||||
room.sendMessage(avatar, message, outOfBandPackage, player.getPlayerManager());
|
||||
logChat(player.getCreatureObject().getObjectId(), player.getCharacterName(), room.getId() + "/" + room.getPath(), message);
|
||||
}
|
||||
chatRoomHandler.sendMessageToRoom(player, p.getRoomId(), p.getSequence(), p.getMessage(), p.getOutOfBandPackage());
|
||||
}
|
||||
|
||||
private void handleChatQueryRoom(Player player, ChatQueryRoom p) {
|
||||
ChatRoom room = getRoom(p.getRoomPath()); // No result code is sent for queries
|
||||
ChatRoom room = chatRoomHandler.getRoomByPath(p.getRoomPath()); // No result code is sent for queries
|
||||
if (room == null)
|
||||
return;
|
||||
|
||||
@@ -560,291 +373,7 @@ public class ChatRoomService extends Service {
|
||||
}
|
||||
|
||||
private void handleChatRoomListRequest(Player player) {
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
|
||||
List<ChatRoom> rooms = new ArrayList<>();
|
||||
for (ChatRoom chatRoom : roomMap.values()) {
|
||||
if (!chatRoom.isPublic() && !chatRoom.isInvited(avatar) && !chatRoom.getOwner().equals(avatar))
|
||||
continue;
|
||||
rooms.add(chatRoom);
|
||||
}
|
||||
|
||||
ChatRoomList response = new ChatRoomList(rooms);
|
||||
player.sendPacket(response);
|
||||
}
|
||||
|
||||
private void sendOnEnteredChatRoom(Player player, ChatAvatar avatar, ChatResult result, int id, int sequence) {
|
||||
ChatOnEnteredRoom onEnteredRoom = new ChatOnEnteredRoom(avatar, id, sequence);
|
||||
onEnteredRoom.setResult(result.getCode());
|
||||
player.sendPacket(onEnteredRoom);
|
||||
}
|
||||
|
||||
public void enterChatChannels(Player player, List<String> channels) {
|
||||
for (String s : channels) {
|
||||
enterChatChannel(player, s, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void enterPlanetaryChatChannels(Player player) {
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return;
|
||||
|
||||
// Leave old zone-only chat channels
|
||||
String planetEndPath = ".Planet";
|
||||
for (String channel : new ArrayList<>(ghost.getJoinedChannels())) {
|
||||
if (channel.endsWith(planetEndPath)) {
|
||||
leaveChatChannel(player, channel);
|
||||
} else {
|
||||
// Better way of doing this?
|
||||
String[] split = channel.split("\\.");
|
||||
if (split.length == 3 && split[2].equals("system"))
|
||||
leaveChatChannel(player, channel);
|
||||
}
|
||||
}
|
||||
|
||||
Terrain terrain = player.getCreatureObject().getTerrain();
|
||||
|
||||
// Enter the new zone-only chat channels
|
||||
String planetPath = "SWG." + player.getGalaxyName() + "." + terrain.getName() + ".";
|
||||
Assert.notNull(getRoom(planetPath + "Planet"));
|
||||
Assert.notNull(getRoom(planetPath + "system"));
|
||||
|
||||
enterChatChannel(player, planetPath + "Planet", false);
|
||||
enterChatChannel(player, planetPath + "system", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to join the specified chat channel
|
||||
*
|
||||
* @param player Player joining the chat channel
|
||||
* @param room Chat room to enter
|
||||
*/
|
||||
public void enterChatChannel(Player player, ChatRoom room, int sequence, boolean ignoreInvitation) {
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null) {
|
||||
sendOnEnteredChatRoom(player, avatar, ChatResult.NONE, room.getId(), sequence);
|
||||
return;
|
||||
}
|
||||
|
||||
ChatResult result = room.canJoinRoom(avatar, ignoreInvitation);
|
||||
|
||||
if (result != ChatResult.SUCCESS && player.getAccessLevel() != AccessLevel.PLAYER) {
|
||||
sendOnEnteredChatRoom(player, avatar, result, room.getId(), sequence);
|
||||
return;
|
||||
}
|
||||
// TODO: Check if player is appropriate faction for the room (Rebel and imperial chat rooms)
|
||||
|
||||
// Server-based list so we can join chat channels automatically
|
||||
ghost.addJoinedChannel(room.getPath());
|
||||
|
||||
// Re-send the player the room list with just this room as it could have been private/hidden
|
||||
// This also "refreshes" the client, not sending this will cause a Chat channel unavailable message.
|
||||
if (!room.isPublic())
|
||||
player.sendPacket(new ChatRoomList(room));
|
||||
|
||||
// Notify players of success, it's ChatResult.SUCCESS at this point
|
||||
player.sendPacket(new ChatOnEnteredRoom(avatar, result.getCode(), room.getId(), sequence));
|
||||
|
||||
PlayerManager manager = player.getPlayerManager();
|
||||
// Notify everyone that a player entered the room
|
||||
room.sendPacketToMembers(manager, new ChatOnEnteredRoom(avatar, result.getCode(), room.getId(), 0));
|
||||
|
||||
room.addMember(avatar);
|
||||
}
|
||||
|
||||
public void enterChatChannel(Player player, int id, int sequence) {
|
||||
ChatRoom room = getRoom(id);
|
||||
if (room == null) {
|
||||
sendOnEnteredChatRoom(player, ChatAvatar.getFromPlayer(player), ChatResult.NONE, id, sequence);
|
||||
return;
|
||||
}
|
||||
enterChatChannel(player, room, sequence, false);
|
||||
}
|
||||
|
||||
public void enterChatChannel(Player player, String path, boolean ignoreInvitation) {
|
||||
for (ChatRoom room : roomMap.values()) {
|
||||
if (room.getPath().equals(path)) {
|
||||
enterChatChannel(player, room, 0, ignoreInvitation);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Channel was not found, attempt to remove it from this players list of channels if it exists.
|
||||
// This can happen if a channel was deleted while the player was offline
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null) {
|
||||
Log.e("Tried to join a room with a path that does not exist: " + path);
|
||||
return;
|
||||
}
|
||||
ghost.removeJoinedChannel(path);
|
||||
}
|
||||
|
||||
public void leaveChatChannel(Player player, ChatRoom room, int sequence) {
|
||||
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
|
||||
|
||||
PlayerObject ghost = player.getPlayerObject();
|
||||
if (ghost == null)
|
||||
return; // ChatOnLeaveRoom doesn't do anything other than for a ChatResult.SUCCESS, so no need to send a fail
|
||||
|
||||
if (!room.removeMember(avatar) && !ghost.removeJoinedChannel(room.getPath()))
|
||||
return;
|
||||
|
||||
player.sendPacket(new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), sequence));
|
||||
|
||||
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), 0));
|
||||
}
|
||||
|
||||
public void leaveChatChannel(Player player, String path) {
|
||||
for (ChatRoom chatRoom : roomMap.values()) {
|
||||
if (chatRoom.getPath().equals(path)) {
|
||||
leaveChatChannel(player, chatRoom, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chat room with the specified address path. If the path's parent channel doesn't exist, then a new chat room is created with the same passed arguments.
|
||||
*
|
||||
* @param creator Room creator who will also become the owner of this room
|
||||
* @param isPublic Determines if the room should be publicly displayed in the channel listing
|
||||
* @param path Address for the channel (Ex: SWG.serverName.Imperial)
|
||||
* @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy)
|
||||
* @param persist If true then this channel will be saved in an {@link ObjectDatabase}
|
||||
* @return {@link ChatRoom}
|
||||
*/
|
||||
public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title, boolean persist) {
|
||||
if (path.isEmpty() || path.endsWith("."))
|
||||
return null;
|
||||
|
||||
String base = "SWG." + creator.getGalaxy();
|
||||
if (!path.startsWith(base) || path.equals(base))
|
||||
return null;
|
||||
|
||||
if (getRoom(path) != null)
|
||||
return getRoom(path);
|
||||
|
||||
// All paths should have parents, lets validate to make sure they exist first. Create them if they don't.
|
||||
int lastIndex = path.lastIndexOf('.');
|
||||
if (lastIndex != -1) {
|
||||
String parentPath = path.substring(0, lastIndex);
|
||||
if (getRoom(parentPath) == null) {
|
||||
createRoom(creator, isPublic, parentPath, "", persist);
|
||||
}
|
||||
}
|
||||
|
||||
ChatRoom room = new ChatRoom();
|
||||
room.setId(maxChatRoomId.incrementAndGet());
|
||||
room.setOwner(creator);
|
||||
room.setCreator(creator);
|
||||
room.setIsPublic(isPublic);
|
||||
room.setPath(path);
|
||||
room.setTitle(title);
|
||||
room.addModerator(creator);
|
||||
roomMap.put(room.getId(), room);
|
||||
|
||||
if (persist)
|
||||
database.add(room);
|
||||
return room;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new, non-persistent, chat room with the specified address path.
|
||||
*
|
||||
* @param creator Room creator who will also become the owner of this room
|
||||
* @param isPublic Determines if the room should be publicly displayed in the channel listing
|
||||
* @param path Address for the channel (Ex: SWG.serverName.Imperial)
|
||||
* @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy)
|
||||
* @return {@link ChatRoom}
|
||||
*/
|
||||
public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title) {
|
||||
return createRoom(creator, isPublic, path, title, false);
|
||||
}
|
||||
|
||||
public boolean notifyDestroyRoom(ChatAvatar destroyer, String roomPath, int sequence) {
|
||||
ChatRoom room = getRoom(roomPath);
|
||||
if (roomPath == null)
|
||||
return false;
|
||||
|
||||
if (!destroyRoom(room))
|
||||
return false;
|
||||
|
||||
// Send the ChatOnDestroyRoom packet to every else in the room besides the person destroying the packet
|
||||
List<Long> networkIds = new ArrayList<>();
|
||||
room.getMembers().forEach(member -> {
|
||||
if (!destroyer.equals(member))
|
||||
networkIds.add(member.getNetworkId());
|
||||
});
|
||||
|
||||
new NotifyPlayersPacketIntent(new ChatOnDestroyRoom(destroyer, ChatResult.SUCCESS.getCode(), room.getId(), 0), networkIds).broadcast();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean destroyRoom(ChatRoom room) {
|
||||
return room != null && roomMap.remove(room.getId()) != null;
|
||||
}
|
||||
|
||||
public void createSystemChannels(String galaxy) {
|
||||
/**
|
||||
* Channel Notes Group channels: created by System - SWG.serverName.group.GroupObjectId.GroupChat title = GroupId Guild channels: created by System - SWG.serverName.guild.GuildId.GuildChat title = GuildId City channels: created by System - SWG.serverName.city.CityId.CityChat title = CityId
|
||||
*/
|
||||
|
||||
ChatAvatar systemAvatar = ChatAvatar.getSystemAvatar(galaxy);
|
||||
String basePath = "SWG." + galaxy + ".";
|
||||
|
||||
DatatableData rooms = ServerFactory.getDatatable("chat/default_rooms.iff");
|
||||
rooms.handleRows((r) -> createRoom(systemAvatar, true, basePath + rooms.getCell(r, 0), (String) rooms.getCell(r, 1), true));
|
||||
|
||||
createPlanetChannels(systemAvatar, basePath);
|
||||
|
||||
/*
|
||||
* Battlefield Room path examples: SWG.Bria.corellia.battlefield SWG.Bria.corellia.battlefield.corellia_mountain_fortress.allFactions SWG.Bria.corellia.battlefield.corellia_pvp.allFactions / Imperial / Rebel SWG.Bria.corellia.battlefield.corellia_rebel_riverside_fort.allFactions
|
||||
*/
|
||||
}
|
||||
|
||||
private void createPlanetChannels(ChatAvatar systemAvatar, String basePath) {
|
||||
DatatableData planets = ServerFactory.getDatatable("chat/planets.iff");
|
||||
planets.handleRows((r) -> {
|
||||
String path = basePath + planets.getCell(r, 0) + ".";
|
||||
createRoom(systemAvatar, true, path + "Planet", "public chat for this planet, cannot create rooms here", true);
|
||||
createRoom(systemAvatar, true, path + "system", "system messages for this planet, cannot create rooms here", true);
|
||||
createRoom(systemAvatar, true, path + "Chat", "public chat for this planet, can create rooms here", true);
|
||||
});
|
||||
}
|
||||
|
||||
public ChatRoom getRoom(String path) {
|
||||
for (ChatRoom room : roomMap.values()) {
|
||||
if (room.getPath().equals(path))
|
||||
return room;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ChatRoom getRoom(int roomId) {
|
||||
return roomMap.get(roomId);
|
||||
}
|
||||
|
||||
private void logChat(long sendId, String sendName, String room, String message) {
|
||||
try {
|
||||
synchronized (insertChatLog) {
|
||||
insertChatLog.setLong(1, System.currentTimeMillis());
|
||||
insertChatLog.setLong(2, sendId);
|
||||
insertChatLog.setString(3, sendName);
|
||||
insertChatLog.setLong(4, 0);
|
||||
insertChatLog.setString(5, "");
|
||||
insertChatLog.setString(6, ChatType.CHAT.name());
|
||||
insertChatLog.setString(7, ChatRange.ROOM.name());
|
||||
insertChatLog.setString(8, room);
|
||||
insertChatLog.setString(9, "");
|
||||
insertChatLog.setString(10, message);
|
||||
insertChatLog.executeUpdate();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
player.sendPacket(new ChatRoomList(chatRoomHandler.getRoomList(player)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user