Skip to content

Commit

Permalink
Added ranged chat
Browse files Browse the repository at this point in the history
The module includes the following:
- `/rangedchatspy` to spy messages from far away
- global chat mode (permission: `chatplugin.global-chat`)
- new `PUBLIC_MESSAGES` data container with `global` column
- syntax update: "chat messages" are now called "public messages"
  • Loading branch information
Remigio07 committed Apr 20, 2024
1 parent e19db4b commit d605a28
Show file tree
Hide file tree
Showing 30 changed files with 540 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public enum DataContainer {
PLAYERS("id", "player_uuid", "player_name", "player_ip", "language", "last_logout", "time_played", "messages_sent", "bans", "warnings", "kicks", "mutes", "ignored_players"),

/**
* Represents the chat messages' data.
* Represents the public messages' data.
*/
CHAT_MESSAGES("player_uuid", "player_name", "rank_id", "server", "world", "message", "date", "deny_chat_reason"),
PUBLIC_MESSAGES("player_uuid", "player_name", "rank_id", "server", "world", "message", "date", "deny_chat_reason", "global"),

/**
* Represents the private messages' data.
Expand Down Expand Up @@ -98,13 +98,13 @@ public String getDatabaseTableID() {
* Gets this data type's ID column's label.
*
* <p>Will return {@link Utils#NOT_APPLICABLE} if called on
* {@link #CHAT_MESSAGES} or {@link #PRIVATE_MESSAGES}, "player_id"
* {@link #PUBLIC_MESSAGES} or {@link #PRIVATE_MESSAGES}, "player_id"
* if called on {@link #IP_ADDRESSES} and "id" otherwise.</p>
*
* @return ID column's label
*/
public String getIDColumn() {
return this == CHAT_MESSAGES || this == PRIVATE_MESSAGES ? Utils.NOT_APPLICABLE : this == IP_ADDRESSES ? "player_id" : "id";
return this == PUBLIC_MESSAGES || this == PRIVATE_MESSAGES ? Utils.NOT_APPLICABLE : this == IP_ADDRESSES ? "player_id" : "id";
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
import me.remigio07.chatplugin.api.common.util.annotation.Nullable;
import me.remigio07.chatplugin.api.common.util.manager.ChatPluginManagerException;
import me.remigio07.chatplugin.api.server.chat.log.ChatLogManager;
import me.remigio07.chatplugin.api.server.chat.log.LoggedChatMessage;
import me.remigio07.chatplugin.api.server.chat.log.LoggedMessage;
import me.remigio07.chatplugin.api.server.chat.log.LoggedPrivateMessage;
import me.remigio07.chatplugin.api.server.chat.log.LoggedPublicMessage;

/**
* Represents the storage connector used by the plugin.
Expand Down Expand Up @@ -324,24 +324,24 @@ public void insertNewMessage(LoggedMessage message) throws SQLException, IOExcep
}

/**
* Gets a list of logged chat messages from the storage.
* Gets a list of logged public messages from the storage.
*
* @param sender Messages' sender
* @param sender Public messages' sender
* @param timeAgo Maximum time elapsed
* @param query Text to search
* @return List of logged messages
* @throws SQLException If something goes wrong and {@link StorageMethod#isDatabase()}
* @throws UnsupportedOperationException If <code>!</code>{@link ChatPlugin#isPremium()}
*/
@NotNull
public List<LoggedChatMessage> getChatMessages(@NotNull OfflinePlayer sender, long timeAgo, String query) throws SQLException {
throw new UnsupportedOperationException("Unable to get messages from the storage on the free version");
public List<LoggedPublicMessage> getPublicMessages(@NotNull OfflinePlayer sender, long timeAgo, String query) throws SQLException {
throw new UnsupportedOperationException("Unable to get public messages from the storage on the free version");
}

/**
* Gets a list of logged private messages from the storage.
*
* @param sender Messages' sender
* @param sender Private messages' sender
* @param timeAgo Maximum time elapsed
* @param query Text to search
* @return List of logged private messages
Expand All @@ -355,7 +355,7 @@ public List<LoggedPrivateMessage> getPrivateMessages(@NotNull OfflinePlayer send

/**
* Cleans messages older than {@link ChatLogManager#getMessagesAutoCleanerPeriod()}
* from {@link DataContainer#CHAT_MESSAGES} and {@link DataContainer#PRIVATE_MESSAGES}.
* from {@link DataContainer#PUBLIC_MESSAGES} and {@link DataContainer#PRIVATE_MESSAGES}.
*
* <p>Will do nothing if called on a proxy environment.</p>
*
Expand Down Expand Up @@ -463,7 +463,7 @@ public static StorageConnector getInstance() {
* @param id Data's ID
* @return Requested list of data
* @throws SQLException If something goes wrong and {@link StorageMethod#isDatabase()}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#CHAT_MESSAGES}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#PUBLIC_MESSAGES}
* <code>|| container == </code>{@link DataContainer#PRIVATE_MESSAGES}
*/
@NotNull
Expand Down Expand Up @@ -498,7 +498,7 @@ public static StorageConnector getInstance() {
* @param data Data to set or <code>null</code>
* @throws SQLException If something goes wrong and {@link StorageMethod#isDatabase()}
* @throws IOException If something goes wrong and {@link StorageMethod#isFlatFile()}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#CHAT_MESSAGES}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#PUBLIC_MESSAGES}
* <code>|| container == </code>{@link DataContainer#PRIVATE_MESSAGES}
*/
public abstract void setData(DataContainer container, String position, int id, @Nullable(why = "Data will become SQL NULL if null") Object data) throws SQLException, IOException;
Expand All @@ -509,7 +509,7 @@ public static StorageConnector getInstance() {
* @param container Container to check
* @return All entries' IDs
* @throws SQLException If something goes wrong and {@link StorageMethod#isDatabase()}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#CHAT_MESSAGES}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#PUBLIC_MESSAGES}
* <code>|| container == </code>{@link DataContainer#PRIVATE_MESSAGES}
*/
@NotNull
Expand All @@ -521,7 +521,7 @@ public static StorageConnector getInstance() {
* @param container Container to check
* @return Next entry's ID
* @throws SQLException If something goes wrong and {@link StorageMethod#isDatabase()}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#CHAT_MESSAGES}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#PUBLIC_MESSAGES}
* <code>|| container == </code>{@link DataContainer#PRIVATE_MESSAGES}
*/
public abstract int getNextID(DataContainer container) throws SQLException;
Expand All @@ -533,7 +533,7 @@ public static StorageConnector getInstance() {
* @param id Entry's ID
* @throws SQLException If something goes wrong and {@link StorageMethod#isDatabase()}
* @throws IOException If something goes wrong and {@link StorageMethod#isFlatFile()}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#CHAT_MESSAGES}
* @throws IllegalArgumentException If <code>container == </code>{@link DataContainer#PUBLIC_MESSAGES}
* <code>|| container == </code>{@link DataContainer#PRIVATE_MESSAGES}
*/
public abstract void removeEntry(DataContainer container, int id) throws SQLException, IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ private Object[] combineSecondTermValues(WhereCondition... conditions) {

@Override
public @NotNull List<Object> getRowValues(DataContainer table, int id) throws SQLException {
if (table == DataContainer.CHAT_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
if (table == DataContainer.PUBLIC_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
throw new IllegalArgumentException("Unable to get row values in table " + table.getDatabaseTableID() + " using an ID since that table does not have IDs");
List<Object> list = new ArrayList<>();

Expand All @@ -127,22 +127,22 @@ private Object[] combineSecondTermValues(WhereCondition... conditions) {

@Override
public void setData(DataContainer table, String column, int id, @Nullable(why = "Data will become SQL NULL if null") Object data) throws SQLException {
if (table == DataContainer.CHAT_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
if (table == DataContainer.PUBLIC_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
throw new IllegalArgumentException("Unable to set data to table " + table.getDatabaseTableID() + " using an ID since that table does not have IDs");
executeUpdate("UPDATE " + table.getDatabaseTableID() + " SET " + column + " = ? WHERE " + table.getIDColumn() + " = ?", data, id);
}

@NotNull
@Override
public List<Integer> getIDs(DataContainer table) throws SQLException {
if (table == DataContainer.CHAT_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
if (table == DataContainer.PUBLIC_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
throw new IllegalArgumentException("Unable to get IDs in table " + table.getDatabaseTableID() + " since that table does not have IDs");
return Utils.numberListToIntegerList(getColumnValues("SELECT " + table.getIDColumn() + " FROM " + table.getDatabaseTableID(), 1, Number.class));
}

@Override
public void removeEntry(DataContainer table, int id) throws SQLException {
if (table == DataContainer.CHAT_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
if (table == DataContainer.PUBLIC_MESSAGES || table == DataContainer.PRIVATE_MESSAGES)
throw new IllegalArgumentException("Unable to remove entry in table " + table.getDatabaseTableID() + " using an ID since that table does not have IDs");
executeUpdate("DELETE FROM " + table.getDatabaseTableID() + " WHERE " + table.getIDColumn() + " = ?", id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public abstract class HoverInfoManager implements ChatPluginManager {
protected String playerClickValue, urlColor;
protected List<PlaceholderType> playerPlaceholderTypes = Collections.emptyList();
protected Map<Language, String> playerHovers = new HashMap<>(), urlHovers = new HashMap<>();
protected List<String> chatFormat = new ArrayList<>();
protected List<String> chatFormat = new ArrayList<>(), globalChatFormat = new ArrayList<>();
protected long loadTime;

/**
Expand Down Expand Up @@ -176,14 +176,28 @@ public Map<Language, String> getURLHovers() {
}

/**
* Gets {@link ChatManager#getFormat()} split around placeholders contained in the format.
* Gets {@link ChatManager#getFormat()} split
* around placeholders contained in the format.
*
* @return Chat's format, split up
*/
public List<String> getChatFormat() {
return chatFormat;
}

/**
* Gets {@link RangedChatManager#getGlobalModeFormat()}
* split around placeholders contained in the format.
*
* <p>Will always return an empty list when
* <code>!{@link RangedChatManager#isEnabled()} || !{@link RangedChatManager#isGlobalModeEnabled()}</code>.</p>
*
* @return Global chat's format, split up
*/
public List<String> getGlobalChatFormat() {
return globalChatFormat;
}

/**
* Gets this manager's instance.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* ChatPlugin - A complete yet lightweight plugin which handles just too many features!
* Copyright 2024 Remigio07
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*
* <https://remigio07.me/chatplugin>
*/

package me.remigio07.chatplugin.api.server.chat;

import me.remigio07.chatplugin.api.common.storage.configuration.ConfigurationType;
import me.remigio07.chatplugin.api.common.util.manager.ChatPluginManager;

/**
* Manager that handles the ranged chat.
*
* @see <a href="https://remigio07.me/chatplugin/wiki/modules/Chat#ranged-chat">ChatPlugin wiki/Modules/Chat/Ranged chat</a>
*/
public abstract class RangedChatManager implements ChatPluginManager {

protected static RangedChatManager instance;
protected boolean enabled, spyOnJoinEnabled, globalModeEnabled;
protected int range;
protected String spyFormat, globalModePrefix, globalModeFormat;
protected long loadTime;

/**
* Checks if this manager is enabled.
*
* <p><strong>Found at:</strong> "chat.ranged-chat.enabled" in {@link ConfigurationType#CHAT}</p>
*/
@Override
public boolean isEnabled() {
return enabled;
}

/**
* Checks if the ranged chat spy should be enabled for players who join
* the server and have the permission "chatplugin.commands.rangedchatspy".
*
* <p><strong>Found at:</strong> "chat.ranged-chat.spy.on-join-enabled" in {@link ConfigurationType#CHAT}</p>
*
* @return Whether the ranged chat spy should be enabled on join
*/
public boolean isSpyOnJoinEnabled() {
return spyOnJoinEnabled;
}

/**
* Checks if messages will be considered global when
* they start with {@link #getGlobalModePrefix()}.
*
* <p><strong>Found at:</strong> "chat.ranged-chat.global-mode.enabled" in {@link ConfigurationType#CHAT}</p>
*
* @return Whether the global mode is enabled
*/
public boolean isGlobalModeEnabled() {
return globalModeEnabled;
}

/**
* Gets the ranged chat's range, in blocks.
*
* <p><strong>Found at:</strong> "chat.ranged-chat.range" in {@link ConfigurationType#CHAT}</p>
*
* @return Chat's range
*/
public int getRange() {
return range;
}

/**
* Gets the chat format displayed to Staff
* members when players send a local message.
*
* <p><strong>Found at:</strong> "chat.ranged-chat.spy.format" in {@link ConfigurationType#CHAT}</p>
*
* @return Ranged chat spy's format
*/
public String getSpyFormat() {
return spyFormat;
}

/**
* Gets the prefix required to treat a message as global.
*
* <p><strong>Found at:</strong> "chat.ranged-chat.global-mode.prefix" in {@link ConfigurationType#CHAT}</p>
*
* @return Global mode's prefix
*/
public String getGlobalModePrefix() {
return globalModePrefix;
}

/**
* Gets the format used to send global messages to players.
*
* <p><strong>Found at:</strong> "chat.ranged-chat.global-mode.format" in {@link ConfigurationType#CHAT}</p>
*
* @return Global mode chat's format
*/
public String getGlobalModeFormat() {
return globalModeFormat;
}

/**
* Gets this manager's instance.
*
* @return Manager's instance
*/
public static RangedChatManager getInstance() {
return instance;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ public static ChatLogManager getInstance() {
}

/**
* Gets a logged chat messages' list for the specified sender and text.
* Gets a logged public messages' list for the specified sender and text.
*
* @param sender Chat messages' sender
* @param timeAgo Chat messages' maximum age
* @param sender Public messages' sender
* @param timeAgo Public messages' maximum age
* @param query Text to search
* @return Sender's logged chat messages
* @return Sender's logged public messages
*/
@NotNull
public abstract List<LoggedChatMessage> getLoggedChatMessages(OfflinePlayer sender, long timeAgo, String query);
public abstract List<LoggedPublicMessage> getLoggedPublicMessages(OfflinePlayer sender, long timeAgo, String query);

/**
* Gets a logged private messages' list for the specified sender and text.
Expand All @@ -104,20 +104,22 @@ public static ChatLogManager getInstance() {
public abstract List<LoggedPrivateMessage> getLoggedPrivateMessages(OfflinePlayer sender, long timeAgo, String query);

/**
* Logs a player's chat message and inserts it into {@link DataContainer#CHAT_MESSAGES}.
* Logs a player's public message and inserts it into {@link DataContainer#PUBLIC_MESSAGES}.
*
* <p>Specify <code>null</code> as <code>denyChatReason</code> if the chat
* message has not been blocked by a {@link DenyChatReasonHandler}.</p>
*
* @param sender Chat message's sender
* @param chatMessage Chat message to log
* @param denyChatReason Chat message's deny chat reason
* @throws IllegalArgumentException If chat message's length exceeds 256 characters
* @param sender Public message's sender
* @param publicMessage Public message to log
* @param global Whether the message is global
* @param denyChatReason Public message's deny chat reason
* @throws IllegalArgumentException If the public message's length exceeds 256 characters
*/
public abstract void logChatMessage(
public abstract void logPublicMessage(
ChatPluginServerPlayer sender,
String chatMessage,
@Nullable(why = "Chat message may not have been blocked") DenyChatReason<?> denyChatReason
String publicMessage,
boolean global,
@Nullable(why = "Public message may not have been blocked") DenyChatReason<?> denyChatReason
);

/**
Expand All @@ -132,7 +134,7 @@ public abstract void logChatMessage(
* @param recipient Private message's recipient
* @param privateMessage Private message to log
* @param denyChatReason Private message's deny chat reason
* @throws IllegalArgumentException If private message's length exceeds 256 characters
* @throws IllegalArgumentException If the private message's length exceeds 256 characters
*/
public abstract void logPrivateMessage(
@NotNull ChatPluginServerPlayer sender,
Expand Down

0 comments on commit d605a28

Please sign in to comment.